libsub
 All Classes Files Functions Variables
compose.hpp
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.aau.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 namespace StringPrivate
42 {
43  // the actual composition class - using string::compose is cleaner, so we
44  // hide it here
46  {
47  public:
48  // initialize and prepare format string on the form "text %1 text %2 etc."
49  explicit Composition(std::string fmt);
50 
51  // supply an replacement argument starting from %1
52  template <typename T>
53  Composition &arg(const T &obj);
54 
55  // compose and return string
56  std::string str() const;
57 
58  private:
59  std::ostringstream os;
60  int arg_no;
61 
62  // we store the output as a list - when the output string is requested, the
63  // list is concatenated to a string; this way we can keep iterators into
64  // the list instead of into a string where they're possibly invalidated on
65  // inserting a specification string
66  typedef std::list<std::string> output_list;
67  output_list output;
68 
69  // the initial parse of the format string fills in the specification map
70  // with positions for each of the various %?s
71  typedef std::multimap<int, output_list::iterator> specification_map;
72  specification_map specs;
73  };
74 
75  // helper for converting spec string numbers
76  inline int char_to_int(char c)
77  {
78  switch (c) {
79  case '0': return 0;
80  case '1': return 1;
81  case '2': return 2;
82  case '3': return 3;
83  case '4': return 4;
84  case '5': return 5;
85  case '6': return 6;
86  case '7': return 7;
87  case '8': return 8;
88  case '9': return 9;
89  default: return -1000;
90  }
91  }
92 
93  inline bool is_number(int n)
94  {
95  switch (n) {
96  case '0':
97  case '1':
98  case '2':
99  case '3':
100  case '4':
101  case '5':
102  case '6':
103  case '7':
104  case '8':
105  case '9':
106  return true;
107 
108  default:
109  return false;
110  }
111  }
112 
113 
114  // implementation of class Composition
115  template <typename T>
116  inline Composition &Composition::arg(const T &obj)
117  {
118  os << obj;
119 
120  std::string rep = os.str();
121 
122  if (!rep.empty()) { // manipulators don't produce output
123  for (specification_map::const_iterator i = specs.lower_bound(arg_no),
124  end = specs.upper_bound(arg_no); i != end; ++i) {
125  output_list::iterator pos = i->second;
126  ++pos;
127 
128  output.insert(pos, rep);
129  }
130 
131  os.str(std::string());
132  //os.clear();
133  ++arg_no;
134  }
135 
136  return *this;
137  }
138 
139  inline Composition::Composition(std::string fmt)
140  : arg_no(1)
141  {
142  std::string::size_type b = 0, i = 0;
143 
144  // fill in output with the strings between the %1 %2 %3 etc. and
145  // fill in specs with the positions
146  while (i < fmt.length()) {
147  if (fmt[i] == '%' && i + 1 < fmt.length()) {
148  if (fmt[i + 1] == '%') { // catch %%
149  fmt.replace(i, 2, "%");
150  ++i;
151  }
152  else if (is_number(fmt[i + 1])) { // aha! a spec!
153  // save string
154  output.push_back(fmt.substr(b, i - b));
155 
156  int n = 1; // number of digits
157  int spec_no = 0;
158 
159  do {
160  spec_no += char_to_int(fmt[i + n]);
161  spec_no *= 10;
162  ++n;
163  } while (i + n < fmt.length() && is_number(fmt[i + n]));
164 
165  spec_no /= 10;
166  output_list::iterator pos = output.end();
167  --pos; // safe since we have just inserted a string>
168 
169  specs.insert(specification_map::value_type(spec_no, pos));
170 
171  // jump over spec string
172  i += n;
173  b = i;
174  }
175  else
176  ++i;
177  }
178  else
179  ++i;
180  }
181 
182  if (i - b > 0) // add the rest of the string
183  output.push_back(fmt.substr(b, i - b));
184  }
185 
186  inline std::string Composition::str() const
187  {
188  // assemble string
189  std::string str;
190 
191  for (output_list::const_iterator i = output.begin(), end = output.end();
192  i != end; ++i)
193  str += *i;
194 
195  return str;
196  }
197 }
198 
199 // now for the real thing(s)
200 namespace String
201 {
202  // a series of functions which accept a format string on the form "text %1
203  // more %2 less %3" and a number of templated parameters and spits out the
204  // composited string
205  template <typename T1>
206  inline std::string compose(const std::string &fmt, const T1 &o1)
207  {
209  c.arg(o1);
210  return c.str();
211  }
212 
213  template <typename T1, typename T2>
214  inline std::string compose(const std::string &fmt,
215  const T1 &o1, const T2 &o2)
216  {
218  c.arg(o1).arg(o2);
219  return c.str();
220  }
221 
222  template <typename T1, typename T2, typename T3>
223  inline std::string compose(const std::string &fmt,
224  const T1 &o1, const T2 &o2, const T3 &o3)
225  {
227  c.arg(o1).arg(o2).arg(o3);
228  return c.str();
229  }
230 
231  template <typename T1, typename T2, typename T3, typename T4>
232  inline std::string compose(const std::string &fmt,
233  const T1 &o1, const T2 &o2, const T3 &o3,
234  const T4 &o4)
235  {
237  c.arg(o1).arg(o2).arg(o3).arg(o4);
238  return c.str();
239  }
240 
241  template <typename T1, typename T2, typename T3, typename T4, typename T5>
242  inline std::string compose(const std::string &fmt,
243  const T1 &o1, const T2 &o2, const T3 &o3,
244  const T4 &o4, const T5 &o5)
245  {
247  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
248  return c.str();
249  }
250 
251  template <typename T1, typename T2, typename T3, typename T4, typename T5,
252  typename T6>
253  inline std::string compose(const std::string &fmt,
254  const T1 &o1, const T2 &o2, const T3 &o3,
255  const T4 &o4, const T5 &o5, const T6 &o6)
256  {
258  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
259  return c.str();
260  }
261 
262  template <typename T1, typename T2, typename T3, typename T4, typename T5,
263  typename T6, typename T7>
264  inline std::string compose(const std::string &fmt,
265  const T1 &o1, const T2 &o2, const T3 &o3,
266  const T4 &o4, const T5 &o5, const T6 &o6,
267  const T7 &o7)
268  {
270  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
271  return c.str();
272  }
273 
274  template <typename T1, typename T2, typename T3, typename T4, typename T5,
275  typename T6, typename T7, typename T8>
276  inline std::string compose(const std::string &fmt,
277  const T1 &o1, const T2 &o2, const T3 &o3,
278  const T4 &o4, const T5 &o5, const T6 &o6,
279  const T7 &o7, const T8 &o8)
280  {
282  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
283  return c.str();
284  }
285 
286  template <typename T1, typename T2, typename T3, typename T4, typename T5,
287  typename T6, typename T7, typename T8, typename T9>
288  inline std::string compose(const std::string &fmt,
289  const T1 &o1, const T2 &o2, const T3 &o3,
290  const T4 &o4, const T5 &o5, const T6 &o6,
291  const T7 &o7, const T8 &o8, const T9 &o9)
292  {
294  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
295  return c.str();
296  }
297 
298  template <typename T1, typename T2, typename T3, typename T4, typename T5,
299  typename T6, typename T7, typename T8, typename T9, typename T10>
300  inline std::string compose(const std::string &fmt,
301  const T1 &o1, const T2 &o2, const T3 &o3,
302  const T4 &o4, const T5 &o5, const T6 &o6,
303  const T7 &o7, const T8 &o8, const T9 &o9,
304  const T10 &o10)
305  {
307  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
308  .arg(o10);
309  return c.str();
310  }
311 
312  template <typename T1, typename T2, typename T3, typename T4, typename T5,
313  typename T6, typename T7, typename T8, typename T9, typename T10,
314  typename T11>
315  inline std::string compose(const std::string &fmt,
316  const T1 &o1, const T2 &o2, const T3 &o3,
317  const T4 &o4, const T5 &o5, const T6 &o6,
318  const T7 &o7, const T8 &o8, const T9 &o9,
319  const T10 &o10, const T11 &o11)
320  {
322  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
323  .arg(o10).arg(o11);
324  return c.str();
325  }
326 
327  template <typename T1, typename T2, typename T3, typename T4, typename T5,
328  typename T6, typename T7, typename T8, typename T9, typename T10,
329  typename T11, typename T12>
330  inline std::string compose(const std::string &fmt,
331  const T1 &o1, const T2 &o2, const T3 &o3,
332  const T4 &o4, const T5 &o5, const T6 &o6,
333  const T7 &o7, const T8 &o8, const T9 &o9,
334  const T10 &o10, const T11 &o11, const T12 &o12)
335  {
337  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
338  .arg(o10).arg(o11).arg(o12);
339  return c.str();
340  }
341 
342  template <typename T1, typename T2, typename T3, typename T4, typename T5,
343  typename T6, typename T7, typename T8, typename T9, typename T10,
344  typename T11, typename T12, typename T13>
345  inline std::string compose(const std::string &fmt,
346  const T1 &o1, const T2 &o2, const T3 &o3,
347  const T4 &o4, const T5 &o5, const T6 &o6,
348  const T7 &o7, const T8 &o8, const T9 &o9,
349  const T10 &o10, const T11 &o11, const T12 &o12,
350  const T13 &o13)
351  {
353  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
354  .arg(o10).arg(o11).arg(o12).arg(o13);
355  return c.str();
356  }
357 
358  template <typename T1, typename T2, typename T3, typename T4, typename T5,
359  typename T6, typename T7, typename T8, typename T9, typename T10,
360  typename T11, typename T12, typename T13, typename T14>
361  inline std::string compose(const std::string &fmt,
362  const T1 &o1, const T2 &o2, const T3 &o3,
363  const T4 &o4, const T5 &o5, const T6 &o6,
364  const T7 &o7, const T8 &o8, const T9 &o9,
365  const T10 &o10, const T11 &o11, const T12 &o12,
366  const T13 &o13, const T14 &o14)
367  {
369  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
370  .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
371  return c.str();
372  }
373 
374  template <typename T1, typename T2, typename T3, typename T4, typename T5,
375  typename T6, typename T7, typename T8, typename T9, typename T10,
376  typename T11, typename T12, typename T13, typename T14,
377  typename T15>
378  inline std::string compose(const std::string &fmt,
379  const T1 &o1, const T2 &o2, const T3 &o3,
380  const T4 &o4, const T5 &o5, const T6 &o6,
381  const T7 &o7, const T8 &o8, const T9 &o9,
382  const T10 &o10, const T11 &o11, const T12 &o12,
383  const T13 &o13, const T14 &o14, const T15 &o15)
384  {
386  c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
387  .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
388  return c.str();
389  }
390 }
391 
392 
393 #endif // STRING_COMPOSE_H
Definition: compose.hpp:45
Definition: compose.hpp:41
Definition: compose.hpp:200