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