Ardour  9.0-pre0-582-g084a23a80d
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 //
24 // Basic usage is like
25 //
26 // std::cout << String::compose("This is a %1x%2 matrix.", rows, cols);
27 //
28 // See http://www.cs.auc.dk/~olau/compose/ or the included README.compose for
29 // more details.
30 //
31 
32 #ifndef STRING_COMPOSE_H
33 #define STRING_COMPOSE_H
34 
35 #include <sstream>
36 #include <string>
37 #include <list>
38 #include <map> // for multimap
39 
40 #include "pbd/libpbd_visibility.h"
41 
42 namespace StringPrivate
43 {
44 // the actual composition class - using string::compose is cleaner, so we
45 // hide it here
47 {
48 public:
49  // initialize and prepare format string on the form "text %1 text %2 etc."
50  explicit Composition(std::string fmt);
51 
52  // supply an replacement argument starting from %1
53  template <typename T>
54  Composition &arg(const T &obj);
55 
56  // specialization to catch strings (C++ and C)
57  Composition &arg(const std::string &str);
58  Composition &arg(char const * const cstr);
59 
60  // compose and return string
61  std::string str() const;
62 
63 private:
64  std::ostringstream os;
65  int arg_no;
66 
67  // we store the output as a list - when the output string is requested, the
68  // list is concatenated to a string; this way we can keep iterators into
69  // the list instead of into a string where they're possibly invalidated on
70  // inserting a specification string
71  typedef std::list<std::string> output_list;
73 
74  // the initial parse of the format string fills in the specification map
75  // with positions for each of the various %?s
76  typedef std::multimap<int, output_list::iterator> specification_map;
78 };
79 
80 // helper for converting spec string numbers
81 inline int char_to_int(char c)
82 {
83  switch (c) {
84  case '0': return 0;
85  case '1': return 1;
86  case '2': return 2;
87  case '3': return 3;
88  case '4': return 4;
89  case '5': return 5;
90  case '6': return 6;
91  case '7': return 7;
92  case '8': return 8;
93  case '9': return 9;
94  default: return -1000;
95  }
96 }
97 
98 inline bool is_number(int n)
99 {
100  switch (n) {
101  case '0':
102  case '1':
103  case '2':
104  case '3':
105  case '4':
106  case '5':
107  case '6':
108  case '7':
109  case '8':
110  case '9':
111  return true;
112 
113  default:
114  return false;
115  }
116 }
117 
118 // implementation of class Composition
119 template <typename T>
120  inline Composition &Composition::arg(const T &obj)
121  {
122  os << obj;
123 
124  std::string rep = os.str();
125 
126  if (!rep.empty()) { // manipulators don't produce output
127  for (specification_map::const_iterator i = specs.lower_bound(arg_no),
128  end = specs.upper_bound(arg_no); i != end; ++i) {
129  output_list::iterator pos = i->second;
130  ++pos;
131 
132  output.insert(pos, rep);
133  }
134 
135  os.str(std::string());
136  //os.clear();
137  ++arg_no;
138  }
139 
140  return *this;
141  }
142 
143 inline Composition &Composition::arg(const std::string &str)
144 {
145  /* specialization to ensure that empty strings show up
146  * in the output
147  */
148  for (specification_map::const_iterator i = specs.lower_bound(arg_no),
149  end = specs.upper_bound(arg_no); i != end; ++i) {
150  output_list::iterator pos = i->second;
151  ++pos;
152 
153  output.insert(pos, str);
154  }
155 
156  ++arg_no;
157 
158  return *this;
159 }
160 
161 inline Composition &Composition::arg(char const * const cstr)
162 {
163  /* specialization to ensure that empty C strings show up
164  * in the output
165  */
166  for (specification_map::const_iterator i = specs.lower_bound(arg_no),
167  end = specs.upper_bound(arg_no); i != end; ++i) {
168  output_list::iterator pos = i->second;
169  ++pos;
170 
171  output.insert(pos, std::string (cstr));
172  }
173 
174  ++arg_no;
175 
176  return *this;
177 }
178 
179 inline Composition::Composition(std::string fmt)
180  : arg_no(1)
181 {
182  std::string::size_type b = 0, i = 0;
183 
184  // fill in output with the strings between the %1 %2 %3 etc. and
185  // fill in specs with the positions
186  while (i < fmt.length()) {
187  if (fmt[i] == '%' && i + 1 < fmt.length()) {
188  if (fmt[i + 1] == '%') { // catch %%
189  fmt.replace(i, 2, "%");
190  ++i;
191  }
192  else if (is_number(fmt[i + 1])) { // aha! a spec!
193  // save string
194  output.push_back(fmt.substr(b, i - b));
195 
196  int n = 1; // number of digits
197  int spec_no = 0;
198 
199  do {
200  spec_no += char_to_int(fmt[i + n]);
201  spec_no *= 10;
202  ++n;
203  } while (i + n < fmt.length() && is_number(fmt[i + n]));
204 
205  spec_no /= 10;
206  output_list::iterator pos = output.end();
207  --pos; // safe since we have just inserted a string>
208 
209  specs.insert(specification_map::value_type(spec_no, pos));
210 
211  // jump over spec string
212  i += n;
213  b = i;
214  }
215  else
216  ++i;
217  }
218  else
219  ++i;
220  }
221 
222  if (i - b > 0) { // add the rest of the string
223  output.push_back(fmt.substr(b, i - b));
224  }
225 }
226 
227 inline std::string Composition::str() const
228 {
229  // assemble string
230  std::string str;
231 
232  for (output_list::const_iterator i = output.begin(), end = output.end();
233  i != end; ++i)
234  str += *i;
235 
236  return str;
237 }
238 }
239 
240 // now for the real thing(s)
241 
242 // a series of functions which accept a format string on the form "text %1
243 // more %2 less %3" and a number of templated parameters and spits out the
244 // composited string
245 template <typename T1>
246 inline std::string string_compose(const std::string &fmt, const T1 &o1)
247 {
249  c.arg(o1);
250  return c.str();
251 }
252 
253 template <typename T1, typename T2>
254 inline std::string string_compose(const std::string &fmt,
255  const T1 &o1, const T2 &o2)
256 {
258  c.arg(o1).arg(o2);
259  return c.str();
260 }
261 
262 template <typename T1, typename T2, typename T3>
263 inline std::string string_compose(const std::string &fmt,
264  const T1 &o1, const T2 &o2, const T3 &o3)
265 {
267  c.arg(o1).arg(o2).arg(o3);
268  return c.str();
269 }
270 
271 template <typename T1, typename T2, typename T3, typename T4>
272 inline std::string string_compose(const std::string &fmt,
273  const T1 &o1, const T2 &o2, const T3 &o3,
274  const T4 &o4)
275 {
277  c.arg(o1).arg(o2).arg(o3).arg(o4);
278  return c.str();
279 }
280 
281 template <typename T1, typename T2, typename T3, typename T4, typename T5>
282 inline std::string string_compose(const std::string &fmt,
283  const T1 &o1, const T2 &o2, const T3 &o3,
284  const T4 &o4, const T5 &o5)
285 {
287  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
288  return c.str();
289 }
290 
291 template <typename T1, typename T2, typename T3, typename T4, typename T5,
292  typename T6>
293 inline std::string string_compose(const std::string &fmt,
294  const T1 &o1, const T2 &o2, const T3 &o3,
295  const T4 &o4, const T5 &o5, const T6 &o6)
296 {
298  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
299  return c.str();
300 }
301 
302 template <typename T1, typename T2, typename T3, typename T4, typename T5,
303  typename T6, typename T7>
304 inline std::string string_compose(const std::string &fmt,
305  const T1 &o1, const T2 &o2, const T3 &o3,
306  const T4 &o4, const T5 &o5, const T6 &o6,
307  const T7 &o7)
308 {
310  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
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>
316 inline std::string string_compose(const std::string &fmt,
317  const T1 &o1, const T2 &o2, const T3 &o3,
318  const T4 &o4, const T5 &o5, const T6 &o6,
319  const T7 &o7, const T8 &o8)
320 {
322  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
323  return c.str();
324 }
325 
326 template <typename T1, typename T2, typename T3, typename T4, typename T5,
327  typename T6, typename T7, typename T8, typename T9>
328 inline std::string string_compose(const std::string &fmt,
329  const T1 &o1, const T2 &o2, const T3 &o3,
330  const T4 &o4, const T5 &o5, const T6 &o6,
331  const T7 &o7, const T8 &o8, const T9 &o9)
332 {
334  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
335  return c.str();
336 }
337 
338 template <typename T1, typename T2, typename T3, typename T4, typename T5,
339  typename T6, typename T7, typename T8, typename T9, typename T10>
340 inline std::string string_compose(const std::string &fmt,
341  const T1 &o1, const T2 &o2, const T3 &o3,
342  const T4 &o4, const T5 &o5, const T6 &o6,
343  const T7 &o7, const T8 &o8, const T9 &o9,
344  const T10 &o10)
345 {
347  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
348  .arg(o10);
349  return c.str();
350 }
351 
352 template <typename T1, typename T2, typename T3, typename T4, typename T5,
353  typename T6, typename T7, typename T8, typename T9, typename T10,
354  typename T11>
355 inline std::string string_compose(const std::string &fmt,
356  const T1 &o1, const T2 &o2, const T3 &o3,
357  const T4 &o4, const T5 &o5, const T6 &o6,
358  const T7 &o7, const T8 &o8, const T9 &o9,
359  const T10 &o10, const T11 &o11)
360 {
362  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
363  .arg(o10).arg(o11);
364  return c.str();
365 }
366 
367 template <typename T1, typename T2, typename T3, typename T4, typename T5,
368  typename T6, typename T7, typename T8, typename T9, typename T10,
369  typename T11, typename T12>
370 inline std::string string_compose(const std::string &fmt,
371  const T1 &o1, const T2 &o2, const T3 &o3,
372  const T4 &o4, const T5 &o5, const T6 &o6,
373  const T7 &o7, const T8 &o8, const T9 &o9,
374  const T10 &o10, const T11 &o11, const T12 &o12)
375 {
377  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
378  .arg(o10).arg(o11).arg(o12);
379  return c.str();
380 }
381 
382 template <typename T1, typename T2, typename T3, typename T4, typename T5,
383  typename T6, typename T7, typename T8, typename T9, typename T10,
384  typename T11, typename T12, typename T13>
385 inline std::string string_compose(const std::string &fmt,
386  const T1 &o1, const T2 &o2, const T3 &o3,
387  const T4 &o4, const T5 &o5, const T6 &o6,
388  const T7 &o7, const T8 &o8, const T9 &o9,
389  const T10 &o10, const T11 &o11, const T12 &o12,
390  const T13 &o13)
391 {
393  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
394  .arg(o10).arg(o11).arg(o12).arg(o13);
395  return c.str();
396 }
397 
398 template <typename T1, typename T2, typename T3, typename T4, typename T5,
399  typename T6, typename T7, typename T8, typename T9, typename T10,
400  typename T11, typename T12, typename T13, typename T14>
401 inline std::string string_compose(const std::string &fmt,
402  const T1 &o1, const T2 &o2, const T3 &o3,
403  const T4 &o4, const T5 &o5, const T6 &o6,
404  const T7 &o7, const T8 &o8, const T9 &o9,
405  const T10 &o10, const T11 &o11, const T12 &o12,
406  const T13 &o13, const T14 &o14)
407 {
409  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
410  .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
411  return c.str();
412 }
413 
414 template <typename T1, typename T2, typename T3, typename T4, typename T5,
415  typename T6, typename T7, typename T8, typename T9, typename T10,
416  typename T11, typename T12, typename T13, typename T14,
417  typename T15>
418 inline std::string string_compose(const std::string &fmt,
419  const T1 &o1, const T2 &o2, const T3 &o3,
420  const T4 &o4, const T5 &o5, const T6 &o6,
421  const T7 &o7, const T8 &o8, const T9 &o9,
422  const T10 &o10, const T11 &o11, const T12 &o12,
423  const T13 &o13, const T14 &o14, const T15 &o15)
424 {
426  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
427  .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
428  return c.str();
429 }
430 
431 #endif // STRING_COMPOSE_H
std::string str() const
Definition: compose.h:227
std::multimap< int, output_list::iterator > specification_map
Definition: compose.h:76
Composition & arg(const T &obj)
Definition: compose.h:120
Composition(std::string fmt)
Definition: compose.h:179
std::list< std::string > output_list
Definition: compose.h:71
std::ostringstream os
Definition: compose.h:64
specification_map specs
Definition: compose.h:77
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:246
#define LIBPBD_API
bool is_number(int n)
Definition: compose.h:98
int char_to_int(char c)
Definition: compose.h:81