ardour
compose.h
Go to the documentation of this file.
1 /* Defines String::compose(fmt, arg...) for easy, i18n-friendly
2  * composition of strings.
3  *
4  * Version 1.0.
5  *
6  * Copyright (c) 2002 Ole Laursen <olau@hardworking.dk>.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21  * USA.
22  */
23 
24 //
25 // Basic usage is like
26 //
27 // std::cout << String::compose("This is a %1x%2 matrix.", rows, cols);
28 //
29 // See http://www.cs.auc.dk/~olau/compose/ or the included README.compose for
30 // more details.
31 //
32 
33 #ifndef STRING_COMPOSE_H
34 #define STRING_COMPOSE_H
35 
36 #include <sstream>
37 #include <string>
38 #include <list>
39 #include <map> // for multimap
40 
41 #include "pbd/libpbd_visibility.h"
42 
43 namespace StringPrivate
44 {
45  // the actual composition class - using string::compose is cleaner, so we
46  // hide it here
48  {
49  public:
50  // initialize and prepare format string on the form "text %1 text %2 etc."
51  explicit Composition(std::string fmt);
52 
53  // supply an replacement argument starting from %1
54  template <typename T>
55  Composition &arg(const T &obj);
56 
57  // compose and return string
58  std::string str() const;
59 
60  private:
61  std::ostringstream os;
62  int arg_no;
63 
64  // we store the output as a list - when the output string is requested, the
65  // list is concatenated to a string; this way we can keep iterators into
66  // the list instead of into a string where they're possibly invalidated on
67  // inserting a specification string
68  typedef std::list<std::string> output_list;
69  output_list output;
70 
71  // the initial parse of the format string fills in the specification map
72  // with positions for each of the various %?s
73  typedef std::multimap<int, output_list::iterator> specification_map;
74  specification_map specs;
75  };
76 
77  // helper for converting spec string numbers
78  inline int char_to_int(char c)
79  {
80  switch (c) {
81  case '0': return 0;
82  case '1': return 1;
83  case '2': return 2;
84  case '3': return 3;
85  case '4': return 4;
86  case '5': return 5;
87  case '6': return 6;
88  case '7': return 7;
89  case '8': return 8;
90  case '9': return 9;
91  default: return -1000;
92  }
93  }
94 
95  inline bool is_number(int n)
96  {
97  switch (n) {
98  case '0':
99  case '1':
100  case '2':
101  case '3':
102  case '4':
103  case '5':
104  case '6':
105  case '7':
106  case '8':
107  case '9':
108  return true;
109 
110  default:
111  return false;
112  }
113  }
114 
115 
116  // implementation of class Composition
117  template <typename T>
118  inline Composition &Composition::arg(const T &obj)
119  {
120  os << obj;
121 
122  std::string rep = os.str();
123 
124  if (!rep.empty()) { // manipulators don't produce output
125  for (specification_map::const_iterator i = specs.lower_bound(arg_no),
126  end = specs.upper_bound(arg_no); i != end; ++i) {
127  output_list::iterator pos = i->second;
128  ++pos;
129 
130  output.insert(pos, rep);
131  }
132 
133  os.str(std::string());
134  //os.clear();
135  ++arg_no;
136  }
137 
138  return *this;
139  }
140 
141  inline Composition::Composition(std::string fmt)
142  : arg_no(1)
143  {
144  std::string::size_type b = 0, i = 0;
145 
146  // fill in output with the strings between the %1 %2 %3 etc. and
147  // fill in specs with the positions
148  while (i < fmt.length()) {
149  if (fmt[i] == '%' && i + 1 < fmt.length()) {
150  if (fmt[i + 1] == '%') { // catch %%
151  fmt.replace(i, 2, "%");
152  ++i;
153  }
154  else if (is_number(fmt[i + 1])) { // aha! a spec!
155  // save string
156  output.push_back(fmt.substr(b, i - b));
157 
158  int n = 1; // number of digits
159  int spec_no = 0;
160 
161  do {
162  spec_no += char_to_int(fmt[i + n]);
163  spec_no *= 10;
164  ++n;
165  } while (i + n < fmt.length() && is_number(fmt[i + n]));
166 
167  spec_no /= 10;
168  output_list::iterator pos = output.end();
169  --pos; // safe since we have just inserted a string>
170 
171  specs.insert(specification_map::value_type(spec_no, pos));
172 
173  // jump over spec string
174  i += n;
175  b = i;
176  }
177  else
178  ++i;
179  }
180  else
181  ++i;
182  }
183 
184  if (i - b > 0) // add the rest of the string
185  output.push_back(fmt.substr(b, i - b));
186  }
187 
188  inline std::string Composition::str() const
189  {
190  // assemble string
191  std::string str;
192 
193  for (output_list::const_iterator i = output.begin(), end = output.end();
194  i != end; ++i)
195  str += *i;
196 
197  return str;
198  }
199 }
200 
201 // now for the real thing(s)
202 //namespace PBD
203 //{
204  // a series of functions which accept a format string on the form "text %1
205  // more %2 less %3" and a number of templated parameters and spits out the
206  // composited string
207  template <typename T1>
208  inline std::string string_compose(const std::string &fmt, const T1 &o1)
209  {
211  c.arg(o1);
212  return c.str();
213  }
214 
215  template <typename T1, typename T2>
216  inline std::string string_compose(const std::string &fmt,
217  const T1 &o1, const T2 &o2)
218  {
220  c.arg(o1).arg(o2);
221  return c.str();
222  }
223 
224  template <typename T1, typename T2, typename T3>
225  inline std::string string_compose(const std::string &fmt,
226  const T1 &o1, const T2 &o2, const T3 &o3)
227  {
229  c.arg(o1).arg(o2).arg(o3);
230  return c.str();
231  }
232 
233  template <typename T1, typename T2, typename T3, typename T4>
234  inline std::string string_compose(const std::string &fmt,
235  const T1 &o1, const T2 &o2, const T3 &o3,
236  const T4 &o4)
237  {
239  c.arg(o1).arg(o2).arg(o3).arg(o4);
240  return c.str();
241  }
242 
243  template <typename T1, typename T2, typename T3, typename T4, typename T5>
244  inline std::string string_compose(const std::string &fmt,
245  const T1 &o1, const T2 &o2, const T3 &o3,
246  const T4 &o4, const T5 &o5)
247  {
249  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
250  return c.str();
251  }
252 
253  template <typename T1, typename T2, typename T3, typename T4, typename T5,
254  typename T6>
255  inline std::string string_compose(const std::string &fmt,
256  const T1 &o1, const T2 &o2, const T3 &o3,
257  const T4 &o4, const T5 &o5, const T6 &o6)
258  {
260  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
261  return c.str();
262  }
263 
264  template <typename T1, typename T2, typename T3, typename T4, typename T5,
265  typename T6, typename T7>
266  inline std::string string_compose(const std::string &fmt,
267  const T1 &o1, const T2 &o2, const T3 &o3,
268  const T4 &o4, const T5 &o5, const T6 &o6,
269  const T7 &o7)
270  {
272  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
273  return c.str();
274  }
275 
276  template <typename T1, typename T2, typename T3, typename T4, typename T5,
277  typename T6, typename T7, typename T8>
278  inline std::string string_compose(const std::string &fmt,
279  const T1 &o1, const T2 &o2, const T3 &o3,
280  const T4 &o4, const T5 &o5, const T6 &o6,
281  const T7 &o7, const T8 &o8)
282  {
284  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
285  return c.str();
286  }
287 
288  template <typename T1, typename T2, typename T3, typename T4, typename T5,
289  typename T6, typename T7, typename T8, typename T9>
290  inline std::string string_compose(const std::string &fmt,
291  const T1 &o1, const T2 &o2, const T3 &o3,
292  const T4 &o4, const T5 &o5, const T6 &o6,
293  const T7 &o7, const T8 &o8, const T9 &o9)
294  {
296  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
297  return c.str();
298  }
299 
300  template <typename T1, typename T2, typename T3, typename T4, typename T5,
301  typename T6, typename T7, typename T8, typename T9, typename T10>
302  inline std::string string_compose(const std::string &fmt,
303  const T1 &o1, const T2 &o2, const T3 &o3,
304  const T4 &o4, const T5 &o5, const T6 &o6,
305  const T7 &o7, const T8 &o8, const T9 &o9,
306  const T10 &o10)
307  {
309  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
310  .arg(o10);
311  return c.str();
312  }
313 
314  template <typename T1, typename T2, typename T3, typename T4, typename T5,
315  typename T6, typename T7, typename T8, typename T9, typename T10,
316  typename T11>
317  inline std::string string_compose(const std::string &fmt,
318  const T1 &o1, const T2 &o2, const T3 &o3,
319  const T4 &o4, const T5 &o5, const T6 &o6,
320  const T7 &o7, const T8 &o8, const T9 &o9,
321  const T10 &o10, const T11 &o11)
322  {
324  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
325  .arg(o10).arg(o11);
326  return c.str();
327  }
328 
329  template <typename T1, typename T2, typename T3, typename T4, typename T5,
330  typename T6, typename T7, typename T8, typename T9, typename T10,
331  typename T11, typename T12>
332  inline std::string string_compose(const std::string &fmt,
333  const T1 &o1, const T2 &o2, const T3 &o3,
334  const T4 &o4, const T5 &o5, const T6 &o6,
335  const T7 &o7, const T8 &o8, const T9 &o9,
336  const T10 &o10, const T11 &o11, const T12 &o12)
337  {
339  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
340  .arg(o10).arg(o11).arg(o12);
341  return c.str();
342  }
343 
344  template <typename T1, typename T2, typename T3, typename T4, typename T5,
345  typename T6, typename T7, typename T8, typename T9, typename T10,
346  typename T11, typename T12, typename T13>
347  inline std::string string_compose(const std::string &fmt,
348  const T1 &o1, const T2 &o2, const T3 &o3,
349  const T4 &o4, const T5 &o5, const T6 &o6,
350  const T7 &o7, const T8 &o8, const T9 &o9,
351  const T10 &o10, const T11 &o11, const T12 &o12,
352  const T13 &o13)
353  {
355  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
356  .arg(o10).arg(o11).arg(o12).arg(o13);
357  return c.str();
358  }
359 
360  template <typename T1, typename T2, typename T3, typename T4, typename T5,
361  typename T6, typename T7, typename T8, typename T9, typename T10,
362  typename T11, typename T12, typename T13, typename T14>
363  inline std::string string_compose(const std::string &fmt,
364  const T1 &o1, const T2 &o2, const T3 &o3,
365  const T4 &o4, const T5 &o5, const T6 &o6,
366  const T7 &o7, const T8 &o8, const T9 &o9,
367  const T10 &o10, const T11 &o11, const T12 &o12,
368  const T13 &o13, const T14 &o14)
369  {
371  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
372  .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
373  return c.str();
374  }
375 
376  template <typename T1, typename T2, typename T3, typename T4, typename T5,
377  typename T6, typename T7, typename T8, typename T9, typename T10,
378  typename T11, typename T12, typename T13, typename T14,
379  typename T15>
380  inline std::string string_compose(const std::string &fmt,
381  const T1 &o1, const T2 &o2, const T3 &o3,
382  const T4 &o4, const T5 &o5, const T6 &o6,
383  const T7 &o7, const T8 &o8, const T9 &o9,
384  const T10 &o10, const T11 &o11, const T12 &o12,
385  const T13 &o13, const T14 &o14, const T15 &o15)
386  {
388  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
389  .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
390  return c.str();
391  }
392 //}
393 
394 
395 #endif // STRING_COMPOSE_H
int char_to_int(char c)
Definition: compose.h:78
#define LIBPBD_API
std::multimap< int, output_list::iterator > specification_map
Definition: compose.h:73
std::string str() const
Definition: compose.h:188
bool is_number(int n)
Definition: compose.h:95
Composition & arg(const T &obj)
Definition: compose.h:118
std::list< std::string > output_list
Definition: compose.h:68
specification_map specs
Definition: compose.h:74
Composition(std::string fmt)
Definition: compose.h:141
std::ostringstream os
Definition: compose.h:61
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208