Windows build fixes.
[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 int16_t& obj)
125   {
126     char buffer[64];
127 #ifdef DCPOMATIC_WINDOWS
128     __mingw_snprintf(buffer, 64, "%" PRId16, obj);
129 #else
130     snprintf(buffer, 64, "%" PRId16, obj);
131 #endif
132     s += buffer;
133   }
134
135   template <>
136   inline void write(std::string& s, const uint16_t& obj)
137   {
138     char buffer[64];
139 #ifdef DCPOMATIC_WINDOWS
140     __mingw_snprintf(buffer, 64, "%" PRIu16, obj);
141 #else
142     snprintf(buffer, 64, "%" PRIu16, obj);
143 #endif
144     s += buffer;
145   }
146
147   template <>
148   inline void write(std::string& s, const int32_t& obj)
149   {
150     char buffer[64];
151 #ifdef DCPOMATIC_WINDOWS
152     __mingw_snprintf(buffer, 64, "%" PRId32, obj);
153 #else
154     snprintf(buffer, 64, "%" PRId32, obj);
155 #endif
156     s += buffer;
157   }
158
159   template <>
160   inline void write(std::string& s, const uint32_t& obj)
161   {
162     char buffer[64];
163 #ifdef DCPOMATIC_WINDOWS
164     __mingw_snprintf(buffer, 64, "%" PRIu32, obj);
165 #else
166     snprintf(buffer, 64, "%" PRIu32, obj);
167 #endif
168     s += buffer;
169   }
170
171   template <>
172   inline void write(std::string& s, const int64_t& obj)
173   {
174     char buffer[64];
175 #ifdef DCPOMATIC_WINDOWS
176     __mingw_snprintf(buffer, 64, "%" PRId64, obj);
177 #else
178     snprintf(buffer, 64, "%" PRId64, obj);
179 #endif
180     s += buffer;
181   }
182
183   template <>
184   inline void write(std::string& s, const uint64_t& obj)
185   {
186     char buffer[64];
187 #ifdef DCPOMATIC_WINDOWS
188     __mingw_snprintf(buffer, 64, "%" PRIu64, obj);
189 #else
190     snprintf(buffer, 64, "%" PRIu64, obj);
191 #endif
192     s += buffer;
193   }
194
195   template <>
196   inline void write(std::string& s, const float& obj)
197   {
198     char buffer[64];
199     snprintf(buffer, 64, "%f", obj);
200     s += buffer;
201   }
202
203   template <>
204   inline void write(std::string& s, const char& obj)
205   {
206     s += obj;
207   }
208
209   template <>
210   inline void write(std::string& s, const double& obj)
211   {
212     char buffer[64];
213     snprintf(buffer, 64, "%f", obj);
214     s += buffer;
215   }
216
217   template <>
218   inline void write(std::string& s, char const * const & obj)
219   {
220     s += obj;
221   }
222
223   template <>
224   inline void write(std::string& s, char* const & obj)
225   {
226     s += obj;
227   }
228
229   template <>
230   inline void write(std::string& s, const std::string& obj)
231   {
232     s += obj;
233   }
234
235   inline void write(std::string& s, wchar_t const * const & obj)
236   {
237     std::wstring ws (obj);
238     std::string w (ws.begin(), ws.end());
239     s += w;
240   }
241
242   template <>
243   inline void write(std::string& s, const boost::filesystem::path & obj)
244   {
245     s += obj.string();
246   }
247
248   // implementation of class Composition
249   template <typename T>
250   inline Composition &Composition::arg(const T &obj)
251   {
252     write(os, obj);
253
254     if (!os.empty()) {          // manipulators don't produce output
255       for (specification_map::const_iterator i = specs.lower_bound(arg_no), end = specs.upper_bound(arg_no); i != end; ++i) {
256         output_list::iterator pos = i->second;
257         ++pos;
258
259         output.insert(pos, os);
260       }
261
262       os = "";
263       ++arg_no;
264     }
265
266     return *this;
267   }
268
269   inline Composition::Composition(std::string fmt)
270     : arg_no(1)
271   {
272     std::string::size_type b = 0, i = 0;
273
274     // fill in output with the strings between the %1 %2 %3 etc. and
275     // fill in specs with the positions
276     while (i < fmt.length()) {
277       if (fmt[i] == '%' && i + 1 < fmt.length()) {
278         if (fmt[i + 1] == '%') {        // catch %%
279           fmt.replace(i, 2, "%");
280           ++i;
281         }
282         else if (is_number(fmt[i + 1])) { // aha! a spec!
283           // save string
284           output.push_back(fmt.substr(b, i - b));
285
286           int n = 1;            // number of digits
287           int spec_no = 0;
288
289           do {
290             spec_no += char_to_int(fmt[i + n]);
291             spec_no *= 10;
292             ++n;
293           } while (i + n < fmt.length() && is_number(fmt[i + n]));
294
295           spec_no /= 10;
296           output_list::iterator pos = output.end();
297           --pos;                // safe since we have just inserted a string>
298
299           specs.insert(specification_map::value_type(spec_no, pos));
300
301           // jump over spec string
302           i += n;
303           b = i;
304         }
305         else
306           ++i;
307       }
308       else
309         ++i;
310     }
311
312     if (i - b > 0)              // add the rest of the string
313       output.push_back(fmt.substr(b, i - b));
314   }
315
316   inline std::string Composition::str() const
317   {
318     // assemble string
319     std::string str;
320
321     for (output_list::const_iterator i = output.begin(), end = output.end();
322          i != end; ++i)
323       str += *i;
324
325     return str;
326   }
327 }
328
329 // now for the real thing(s)
330 namespace String
331 {
332   // a series of functions which accept a format string on the form "text %1
333   // more %2 less %3" and a number of templated parameters and spits out the
334   // composited string
335   template <typename T1>
336   inline std::string compose(const std::string &fmt, const T1 &o1)
337   {
338     StringPrivate::Composition c(fmt);
339     c.arg(o1);
340     return c.str();
341   }
342
343   template <typename T1, typename T2>
344   inline std::string compose(const std::string &fmt,
345                              const T1 &o1, const T2 &o2)
346   {
347     StringPrivate::Composition c(fmt);
348     c.arg(o1).arg(o2);
349     return c.str();
350   }
351
352   template <typename T1, typename T2, typename T3>
353   inline std::string compose(const std::string &fmt,
354                              const T1 &o1, const T2 &o2, const T3 &o3)
355   {
356     StringPrivate::Composition c(fmt);
357     c.arg(o1).arg(o2).arg(o3);
358     return c.str();
359   }
360
361   template <typename T1, typename T2, typename T3, typename T4>
362   inline std::string compose(const std::string &fmt,
363                              const T1 &o1, const T2 &o2, const T3 &o3,
364                              const T4 &o4)
365   {
366     StringPrivate::Composition c(fmt);
367     c.arg(o1).arg(o2).arg(o3).arg(o4);
368     return c.str();
369   }
370
371   template <typename T1, typename T2, typename T3, typename T4, typename T5>
372   inline std::string compose(const std::string &fmt,
373                              const T1 &o1, const T2 &o2, const T3 &o3,
374                              const T4 &o4, const T5 &o5)
375   {
376     StringPrivate::Composition c(fmt);
377     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
378     return c.str();
379   }
380
381   template <typename T1, typename T2, typename T3, typename T4, typename T5,
382             typename T6>
383   inline std::string compose(const std::string &fmt,
384                              const T1 &o1, const T2 &o2, const T3 &o3,
385                              const T4 &o4, const T5 &o5, const T6 &o6)
386   {
387     StringPrivate::Composition c(fmt);
388     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
389     return c.str();
390   }
391
392   template <typename T1, typename T2, typename T3, typename T4, typename T5,
393             typename T6, typename T7>
394   inline std::string compose(const std::string &fmt,
395                              const T1 &o1, const T2 &o2, const T3 &o3,
396                              const T4 &o4, const T5 &o5, const T6 &o6,
397                              const T7 &o7)
398   {
399     StringPrivate::Composition c(fmt);
400     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
401     return c.str();
402   }
403
404   template <typename T1, typename T2, typename T3, typename T4, typename T5,
405             typename T6, typename T7, typename T8>
406   inline std::string compose(const std::string &fmt,
407                              const T1 &o1, const T2 &o2, const T3 &o3,
408                              const T4 &o4, const T5 &o5, const T6 &o6,
409                              const T7 &o7, const T8 &o8)
410   {
411     StringPrivate::Composition c(fmt);
412     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
413     return c.str();
414   }
415
416   template <typename T1, typename T2, typename T3, typename T4, typename T5,
417             typename T6, typename T7, typename T8, typename T9>
418   inline std::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   {
423     StringPrivate::Composition c(fmt);
424     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
425     return c.str();
426   }
427
428   template <typename T1, typename T2, typename T3, typename T4, typename T5,
429             typename T6, typename T7, typename T8, typename T9, typename T10>
430   inline std::string compose(const std::string &fmt,
431                              const T1 &o1, const T2 &o2, const T3 &o3,
432                              const T4 &o4, const T5 &o5, const T6 &o6,
433                              const T7 &o7, const T8 &o8, const T9 &o9,
434                              const T10 &o10)
435   {
436     StringPrivate::Composition c(fmt);
437     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
438       .arg(o10);
439     return c.str();
440   }
441
442   template <typename T1, typename T2, typename T3, typename T4, typename T5,
443             typename T6, typename T7, typename T8, typename T9, typename T10,
444             typename T11>
445   inline std::string compose(const std::string &fmt,
446                              const T1 &o1, const T2 &o2, const T3 &o3,
447                              const T4 &o4, const T5 &o5, const T6 &o6,
448                              const T7 &o7, const T8 &o8, const T9 &o9,
449                              const T10 &o10, const T11 &o11)
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);
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>
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   {
466     StringPrivate::Composition c(fmt);
467     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
468       .arg(o10).arg(o11).arg(o12);
469     return c.str();
470   }
471
472   template <typename T1, typename T2, typename T3, typename T4, typename T5,
473             typename T6, typename T7, typename T8, typename T9, typename T10,
474             typename T11, typename T12, typename T13>
475   inline std::string compose(const std::string &fmt,
476                              const T1 &o1, const T2 &o2, const T3 &o3,
477                              const T4 &o4, const T5 &o5, const T6 &o6,
478                              const T7 &o7, const T8 &o8, const T9 &o9,
479                              const T10 &o10, const T11 &o11, const T12 &o12,
480                              const T13 &o13)
481   {
482     StringPrivate::Composition c(fmt);
483     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
484       .arg(o10).arg(o11).arg(o12).arg(o13);
485     return c.str();
486   }
487
488   template <typename T1, typename T2, typename T3, typename T4, typename T5,
489             typename T6, typename T7, typename T8, typename T9, typename T10,
490             typename T11, typename T12, typename T13, typename T14>
491   inline std::string compose(const std::string &fmt,
492                              const T1 &o1, const T2 &o2, const T3 &o3,
493                              const T4 &o4, const T5 &o5, const T6 &o6,
494                              const T7 &o7, const T8 &o8, const T9 &o9,
495                              const T10 &o10, const T11 &o11, const T12 &o12,
496                              const T13 &o13, const T14 &o14)
497   {
498     StringPrivate::Composition c(fmt);
499     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
500       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
501     return c.str();
502   }
503
504   template <typename T1, typename T2, typename T3, typename T4, typename T5,
505             typename T6, typename T7, typename T8, typename T9, typename T10,
506             typename T11, typename T12, typename T13, typename T14,
507             typename T15>
508   inline std::string compose(const std::string &fmt,
509                              const T1 &o1, const T2 &o2, const T3 &o3,
510                              const T4 &o4, const T5 &o5, const T6 &o6,
511                              const T7 &o7, const T8 &o8, const T9 &o9,
512                              const T10 &o10, const T11 &o11, const T12 &o12,
513                              const T13 &o13, const T14 &o14, const T15 &o15)
514   {
515     StringPrivate::Composition c(fmt);
516     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
517       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
518     return c.str();
519   }
520 }
521
522
523 #endif // STRING_COMPOSE_H