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