Another build fix.
[dcpomatic.git] / src / lib / 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 <boost/filesystem.hpp>
38 #include <string>
39 #include <list>
40 #include <map>
41 #include <inttypes.h>
42 #include <cstdio>
43
44 namespace StringPrivate
45 {
46   // the actual composition class - using string::compose is cleaner, so we
47   // hide it here
48   class Composition
49   {
50   public:
51     // initialize and prepare format string on the form "text %1 text %2 etc."
52     explicit Composition(std::string fmt);
53
54     // supply an replacement argument starting from %1
55     template <typename T>
56     Composition &arg(const T &obj);
57
58     // compose and return string
59     std::string str() const;
60
61   private:
62     std::string os;
63     int arg_no;
64
65     // we store the output as a list - when the output string is requested, the
66     // list is concatenated to a string; this way we can keep iterators into
67     // the list instead of into a string where they're possibly invalidated on
68     // inserting a specification string
69     typedef std::list<std::string> output_list;
70     output_list output;
71
72     // the initial parse of the format string fills in the specification map
73     // with positions for each of the various %?s
74     typedef std::multimap<int, output_list::iterator> specification_map;
75     specification_map specs;
76   };
77
78   // helper for converting spec string numbers
79   inline int char_to_int(char c)
80   {
81     switch (c) {
82     case '0': return 0;
83     case '1': return 1;
84     case '2': return 2;
85     case '3': return 3;
86     case '4': return 4;
87     case '5': return 5;
88     case '6': return 6;
89     case '7': return 7;
90     case '8': return 8;
91     case '9': return 9;
92     default: return -1000;
93     }
94   }
95
96   inline bool is_number(int n)
97   {
98     switch (n) {
99     case '0':
100     case '1':
101     case '2':
102     case '3':
103     case '4':
104     case '5':
105     case '6':
106     case '7':
107     case '8':
108     case '9':
109       return true;
110
111     default:
112       return false;
113     }
114   }
115
116   template <typename T>
117   inline void write(std::string& s, const T& obj)
118   {
119     /* Assume anything not specialized has a to_string() method */
120     s += to_string (obj);
121   }
122
123   template <>
124   inline void write(std::string& s, const int64_t& obj)
125   {
126     char buffer[64];
127 #ifdef DCPOMATIC_WINDOWS
128     __mingw_snprintf(buffer, 64, "%" PRId64, obj);
129 #else
130     snprintf(buffer, 64, "%" PRId64, obj);
131 #endif
132     s += buffer;
133   }
134
135   template <>
136   inline void write(std::string& s, const uint64_t& obj)
137   {
138     char buffer[64];
139 #ifdef DCPOMATIC_WINDOWS
140     __mingw_snprintf(buffer, 64, "%" PRud64, obj);
141 #else
142     snprintf(buffer, 64, "%" PRIu64, obj);
143 #endif
144     s += buffer;
145   }
146
147   template <>
148   inline void write(std::string& s, const int& obj)
149   {
150     char buffer[64];
151     snprintf(buffer, 64, "%d", obj);
152     s += buffer;
153   }
154
155   template <>
156   inline void write(std::string& s, const unsigned int& obj)
157   {
158     char buffer[64];
159     snprintf(buffer, 64, "%ud", obj);
160     s += buffer;
161   }
162
163   template <>
164   inline void write(std::string& s, const long unsigned int& obj)
165   {
166     char buffer[64];
167     snprintf(buffer, 64, "%lu", obj);
168     s += buffer;
169   }
170
171   template <>
172   inline void write(std::string& s, const float& obj)
173   {
174     char buffer[64];
175     snprintf(buffer, 64, "%f", obj);
176     s += buffer;
177   }
178
179   template <>
180   inline void write(std::string& s, const char& obj)
181   {
182     s += obj;
183   }
184
185   template <>
186   inline void write(std::string& s, const double& obj)
187   {
188     char buffer[64];
189     snprintf(buffer, 64, "%f", obj);
190     s += buffer;
191   }
192
193   template <>
194   inline void write(std::string& s, char const * const & obj)
195   {
196     s += obj;
197   }
198
199   template <>
200   inline void write(std::string& s, char* const & obj)
201   {
202     s += obj;
203   }
204
205   template <>
206   inline void write(std::string& s, const std::string& obj)
207   {
208     s += obj;
209   }
210
211   template <>
212   inline void write(std::string& s, const boost::filesystem::path & obj)
213   {
214     s += obj.string();
215   }
216
217   // implementation of class Composition
218   template <typename T>
219   inline Composition &Composition::arg(const T &obj)
220   {
221     write(os, obj);
222
223     if (!os.empty()) {          // manipulators don't produce output
224       for (specification_map::const_iterator i = specs.lower_bound(arg_no), end = specs.upper_bound(arg_no); i != end; ++i) {
225         output_list::iterator pos = i->second;
226         ++pos;
227
228         output.insert(pos, os);
229       }
230
231       os = "";
232       ++arg_no;
233     }
234
235     return *this;
236   }
237
238   inline Composition::Composition(std::string fmt)
239     : arg_no(1)
240   {
241     std::string::size_type b = 0, i = 0;
242
243     // fill in output with the strings between the %1 %2 %3 etc. and
244     // fill in specs with the positions
245     while (i < fmt.length()) {
246       if (fmt[i] == '%' && i + 1 < fmt.length()) {
247         if (fmt[i + 1] == '%') {        // catch %%
248           fmt.replace(i, 2, "%");
249           ++i;
250         }
251         else if (is_number(fmt[i + 1])) { // aha! a spec!
252           // save string
253           output.push_back(fmt.substr(b, i - b));
254
255           int n = 1;            // number of digits
256           int spec_no = 0;
257
258           do {
259             spec_no += char_to_int(fmt[i + n]);
260             spec_no *= 10;
261             ++n;
262           } while (i + n < fmt.length() && is_number(fmt[i + n]));
263
264           spec_no /= 10;
265           output_list::iterator pos = output.end();
266           --pos;                // safe since we have just inserted a string>
267
268           specs.insert(specification_map::value_type(spec_no, pos));
269
270           // jump over spec string
271           i += n;
272           b = i;
273         }
274         else
275           ++i;
276       }
277       else
278         ++i;
279     }
280
281     if (i - b > 0)              // add the rest of the string
282       output.push_back(fmt.substr(b, i - b));
283   }
284
285   inline std::string Composition::str() const
286   {
287     // assemble string
288     std::string str;
289
290     for (output_list::const_iterator i = output.begin(), end = output.end();
291          i != end; ++i)
292       str += *i;
293
294     return str;
295   }
296 }
297
298 // now for the real thing(s)
299 namespace String
300 {
301   // a series of functions which accept a format string on the form "text %1
302   // more %2 less %3" and a number of templated parameters and spits out the
303   // composited string
304   template <typename T1>
305   inline std::string compose(const std::string &fmt, const T1 &o1)
306   {
307     StringPrivate::Composition c(fmt);
308     c.arg(o1);
309     return c.str();
310   }
311
312   template <typename T1, typename T2>
313   inline std::string compose(const std::string &fmt,
314                              const T1 &o1, const T2 &o2)
315   {
316     StringPrivate::Composition c(fmt);
317     c.arg(o1).arg(o2);
318     return c.str();
319   }
320
321   template <typename T1, typename T2, typename T3>
322   inline std::string compose(const std::string &fmt,
323                              const T1 &o1, const T2 &o2, const T3 &o3)
324   {
325     StringPrivate::Composition c(fmt);
326     c.arg(o1).arg(o2).arg(o3);
327     return c.str();
328   }
329
330   template <typename T1, typename T2, typename T3, typename T4>
331   inline std::string compose(const std::string &fmt,
332                              const T1 &o1, const T2 &o2, const T3 &o3,
333                              const T4 &o4)
334   {
335     StringPrivate::Composition c(fmt);
336     c.arg(o1).arg(o2).arg(o3).arg(o4);
337     return c.str();
338   }
339
340   template <typename T1, typename T2, typename T3, typename T4, typename T5>
341   inline std::string compose(const std::string &fmt,
342                              const T1 &o1, const T2 &o2, const T3 &o3,
343                              const T4 &o4, const T5 &o5)
344   {
345     StringPrivate::Composition c(fmt);
346     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
347     return c.str();
348   }
349
350   template <typename T1, typename T2, typename T3, typename T4, typename T5,
351             typename T6>
352   inline std::string compose(const std::string &fmt,
353                              const T1 &o1, const T2 &o2, const T3 &o3,
354                              const T4 &o4, const T5 &o5, const T6 &o6)
355   {
356     StringPrivate::Composition c(fmt);
357     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
358     return c.str();
359   }
360
361   template <typename T1, typename T2, typename T3, typename T4, typename T5,
362             typename T6, typename T7>
363   inline std::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)
367   {
368     StringPrivate::Composition c(fmt);
369     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
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>
375   inline std::string compose(const std::string &fmt,
376                              const T1 &o1, const T2 &o2, const T3 &o3,
377                              const T4 &o4, const T5 &o5, const T6 &o6,
378                              const T7 &o7, const T8 &o8)
379   {
380     StringPrivate::Composition c(fmt);
381     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
382     return c.str();
383   }
384
385   template <typename T1, typename T2, typename T3, typename T4, typename T5,
386             typename T6, typename T7, typename T8, typename T9>
387   inline std::string compose(const std::string &fmt,
388                              const T1 &o1, const T2 &o2, const T3 &o3,
389                              const T4 &o4, const T5 &o5, const T6 &o6,
390                              const T7 &o7, const T8 &o8, const T9 &o9)
391   {
392     StringPrivate::Composition c(fmt);
393     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
394     return c.str();
395   }
396
397   template <typename T1, typename T2, typename T3, typename T4, typename T5,
398             typename T6, typename T7, typename T8, typename T9, typename T10>
399   inline std::string compose(const std::string &fmt,
400                              const T1 &o1, const T2 &o2, const T3 &o3,
401                              const T4 &o4, const T5 &o5, const T6 &o6,
402                              const T7 &o7, const T8 &o8, const T9 &o9,
403                              const T10 &o10)
404   {
405     StringPrivate::Composition c(fmt);
406     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
407       .arg(o10);
408     return c.str();
409   }
410
411   template <typename T1, typename T2, typename T3, typename T4, typename T5,
412             typename T6, typename T7, typename T8, typename T9, typename T10,
413             typename T11>
414   inline std::string compose(const std::string &fmt,
415                              const T1 &o1, const T2 &o2, const T3 &o3,
416                              const T4 &o4, const T5 &o5, const T6 &o6,
417                              const T7 &o7, const T8 &o8, const T9 &o9,
418                              const T10 &o10, const T11 &o11)
419   {
420     StringPrivate::Composition c(fmt);
421     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
422       .arg(o10).arg(o11);
423     return c.str();
424   }
425
426   template <typename T1, typename T2, typename T3, typename T4, typename T5,
427             typename T6, typename T7, typename T8, typename T9, typename T10,
428             typename T11, typename T12>
429   inline std::string compose(const std::string &fmt,
430                              const T1 &o1, const T2 &o2, const T3 &o3,
431                              const T4 &o4, const T5 &o5, const T6 &o6,
432                              const T7 &o7, const T8 &o8, const T9 &o9,
433                              const T10 &o10, const T11 &o11, const T12 &o12)
434   {
435     StringPrivate::Composition c(fmt);
436     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
437       .arg(o10).arg(o11).arg(o12);
438     return c.str();
439   }
440
441   template <typename T1, typename T2, typename T3, typename T4, typename T5,
442             typename T6, typename T7, typename T8, typename T9, typename T10,
443             typename T11, typename T12, typename T13>
444   inline std::string compose(const std::string &fmt,
445                              const T1 &o1, const T2 &o2, const T3 &o3,
446                              const T4 &o4, const T5 &o5, const T6 &o6,
447                              const T7 &o7, const T8 &o8, const T9 &o9,
448                              const T10 &o10, const T11 &o11, const T12 &o12,
449                              const T13 &o13)
450   {
451     StringPrivate::Composition c(fmt);
452     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
453       .arg(o10).arg(o11).arg(o12).arg(o13);
454     return c.str();
455   }
456
457   template <typename T1, typename T2, typename T3, typename T4, typename T5,
458             typename T6, typename T7, typename T8, typename T9, typename T10,
459             typename T11, typename T12, typename T13, typename T14>
460   inline std::string compose(const std::string &fmt,
461                              const T1 &o1, const T2 &o2, const T3 &o3,
462                              const T4 &o4, const T5 &o5, const T6 &o6,
463                              const T7 &o7, const T8 &o8, const T9 &o9,
464                              const T10 &o10, const T11 &o11, const T12 &o12,
465                              const T13 &o13, const T14 &o14)
466   {
467     StringPrivate::Composition c(fmt);
468     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
469       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
470     return c.str();
471   }
472
473   template <typename T1, typename T2, typename T3, typename T4, typename T5,
474             typename T6, typename T7, typename T8, typename T9, typename T10,
475             typename T11, typename T12, typename T13, typename T14,
476             typename T15>
477   inline std::string compose(const std::string &fmt,
478                              const T1 &o1, const T2 &o2, const T3 &o3,
479                              const T4 &o4, const T5 &o5, const T6 &o6,
480                              const T7 &o7, const T8 &o8, const T9 &o9,
481                              const T10 &o10, const T11 &o11, const T12 &o12,
482                              const T13 &o13, const T14 &o14, const T15 &o15)
483   {
484     StringPrivate::Composition c(fmt);
485     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
486       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
487     return c.str();
488   }
489 }
490
491
492 #endif // STRING_COMPOSE_H