More 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 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 int& obj)
137   {
138     char buffer[64];
139     snprintf(buffer, 64, "%d", obj);
140     s += buffer;
141   }
142
143   template <>
144   inline void write(std::string& s, const unsigned int& obj)
145   {
146     char buffer[64];
147     snprintf(buffer, 64, "%ud", obj);
148     s += buffer;
149   }
150
151   template <>
152   inline void write(std::string& s, const long unsigned int& obj)
153   {
154     char buffer[64];
155     snprintf(buffer, 64, "%lu", obj);
156     s += buffer;
157   }
158
159   template <>
160   inline void write(std::string& s, const float& obj)
161   {
162     char buffer[64];
163     snprintf(buffer, 64, "%f", obj);
164     s += buffer;
165   }
166
167   template <>
168   inline void write(std::string& s, const char& obj)
169   {
170     s += obj;
171   }
172
173   template <>
174   inline void write(std::string& s, const double& obj)
175   {
176     char buffer[64];
177     snprintf(buffer, 64, "%f", obj);
178     s += buffer;
179   }
180
181   template <>
182   inline void write(std::string& s, char const * const & obj)
183   {
184     s += obj;
185   }
186
187   template <>
188   inline void write(std::string& s, char* const & obj)
189   {
190     s += obj;
191   }
192
193   template <>
194   inline void write(std::string& s, const std::string& obj)
195   {
196     s += obj;
197   }
198
199   template <>
200   inline void write(std::string& s, const boost::filesystem::path & obj)
201   {
202     s += obj.string();
203   }
204
205   // implementation of class Composition
206   template <typename T>
207   inline Composition &Composition::arg(const T &obj)
208   {
209     write(os, obj);
210
211     if (!os.empty()) {          // manipulators don't produce output
212       for (specification_map::const_iterator i = specs.lower_bound(arg_no), end = specs.upper_bound(arg_no); i != end; ++i) {
213         output_list::iterator pos = i->second;
214         ++pos;
215
216         output.insert(pos, os);
217       }
218
219       os = "";
220       ++arg_no;
221     }
222
223     return *this;
224   }
225
226   inline Composition::Composition(std::string fmt)
227     : arg_no(1)
228   {
229     std::string::size_type b = 0, i = 0;
230
231     // fill in output with the strings between the %1 %2 %3 etc. and
232     // fill in specs with the positions
233     while (i < fmt.length()) {
234       if (fmt[i] == '%' && i + 1 < fmt.length()) {
235         if (fmt[i + 1] == '%') {        // catch %%
236           fmt.replace(i, 2, "%");
237           ++i;
238         }
239         else if (is_number(fmt[i + 1])) { // aha! a spec!
240           // save string
241           output.push_back(fmt.substr(b, i - b));
242
243           int n = 1;            // number of digits
244           int spec_no = 0;
245
246           do {
247             spec_no += char_to_int(fmt[i + n]);
248             spec_no *= 10;
249             ++n;
250           } while (i + n < fmt.length() && is_number(fmt[i + n]));
251
252           spec_no /= 10;
253           output_list::iterator pos = output.end();
254           --pos;                // safe since we have just inserted a string>
255
256           specs.insert(specification_map::value_type(spec_no, pos));
257
258           // jump over spec string
259           i += n;
260           b = i;
261         }
262         else
263           ++i;
264       }
265       else
266         ++i;
267     }
268
269     if (i - b > 0)              // add the rest of the string
270       output.push_back(fmt.substr(b, i - b));
271   }
272
273   inline std::string Composition::str() const
274   {
275     // assemble string
276     std::string str;
277
278     for (output_list::const_iterator i = output.begin(), end = output.end();
279          i != end; ++i)
280       str += *i;
281
282     return str;
283   }
284 }
285
286 // now for the real thing(s)
287 namespace String
288 {
289   // a series of functions which accept a format string on the form "text %1
290   // more %2 less %3" and a number of templated parameters and spits out the
291   // composited string
292   template <typename T1>
293   inline std::string compose(const std::string &fmt, const T1 &o1)
294   {
295     StringPrivate::Composition c(fmt);
296     c.arg(o1);
297     return c.str();
298   }
299
300   template <typename T1, typename T2>
301   inline std::string compose(const std::string &fmt,
302                              const T1 &o1, const T2 &o2)
303   {
304     StringPrivate::Composition c(fmt);
305     c.arg(o1).arg(o2);
306     return c.str();
307   }
308
309   template <typename T1, typename T2, typename T3>
310   inline std::string compose(const std::string &fmt,
311                              const T1 &o1, const T2 &o2, const T3 &o3)
312   {
313     StringPrivate::Composition c(fmt);
314     c.arg(o1).arg(o2).arg(o3);
315     return c.str();
316   }
317
318   template <typename T1, typename T2, typename T3, typename T4>
319   inline std::string compose(const std::string &fmt,
320                              const T1 &o1, const T2 &o2, const T3 &o3,
321                              const T4 &o4)
322   {
323     StringPrivate::Composition c(fmt);
324     c.arg(o1).arg(o2).arg(o3).arg(o4);
325     return c.str();
326   }
327
328   template <typename T1, typename T2, typename T3, typename T4, typename T5>
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)
332   {
333     StringPrivate::Composition c(fmt);
334     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
335     return c.str();
336   }
337
338   template <typename T1, typename T2, typename T3, typename T4, typename T5,
339             typename T6>
340   inline std::string compose(const std::string &fmt,
341                              const T1 &o1, const T2 &o2, const T3 &o3,
342                              const T4 &o4, const T5 &o5, const T6 &o6)
343   {
344     StringPrivate::Composition c(fmt);
345     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
346     return c.str();
347   }
348
349   template <typename T1, typename T2, typename T3, typename T4, typename T5,
350             typename T6, typename T7>
351   inline std::string compose(const std::string &fmt,
352                              const T1 &o1, const T2 &o2, const T3 &o3,
353                              const T4 &o4, const T5 &o5, const T6 &o6,
354                              const T7 &o7)
355   {
356     StringPrivate::Composition c(fmt);
357     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
358     return c.str();
359   }
360
361   template <typename T1, typename T2, typename T3, typename T4, typename T5,
362             typename T6, typename T7, typename T8>
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, const T8 &o8)
367   {
368     StringPrivate::Composition c(fmt);
369     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
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>
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, const T9 &o9)
379   {
380     StringPrivate::Composition c(fmt);
381     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
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, typename T10>
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                              const T10 &o10)
392   {
393     StringPrivate::Composition c(fmt);
394     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
395       .arg(o10);
396     return c.str();
397   }
398
399   template <typename T1, typename T2, typename T3, typename T4, typename T5,
400             typename T6, typename T7, typename T8, typename T9, typename T10,
401             typename T11>
402   inline std::string compose(const std::string &fmt,
403                              const T1 &o1, const T2 &o2, const T3 &o3,
404                              const T4 &o4, const T5 &o5, const T6 &o6,
405                              const T7 &o7, const T8 &o8, const T9 &o9,
406                              const T10 &o10, const T11 &o11)
407   {
408     StringPrivate::Composition c(fmt);
409     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
410       .arg(o10).arg(o11);
411     return c.str();
412   }
413
414   template <typename T1, typename T2, typename T3, typename T4, typename T5,
415             typename T6, typename T7, typename T8, typename T9, typename T10,
416             typename T11, typename T12>
417   inline std::string compose(const std::string &fmt,
418                              const T1 &o1, const T2 &o2, const T3 &o3,
419                              const T4 &o4, const T5 &o5, const T6 &o6,
420                              const T7 &o7, const T8 &o8, const T9 &o9,
421                              const T10 &o10, const T11 &o11, const T12 &o12)
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       .arg(o10).arg(o11).arg(o12);
426     return c.str();
427   }
428
429   template <typename T1, typename T2, typename T3, typename T4, typename T5,
430             typename T6, typename T7, typename T8, typename T9, typename T10,
431             typename T11, typename T12, typename T13>
432   inline std::string compose(const std::string &fmt,
433                              const T1 &o1, const T2 &o2, const T3 &o3,
434                              const T4 &o4, const T5 &o5, const T6 &o6,
435                              const T7 &o7, const T8 &o8, const T9 &o9,
436                              const T10 &o10, const T11 &o11, const T12 &o12,
437                              const T13 &o13)
438   {
439     StringPrivate::Composition c(fmt);
440     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
441       .arg(o10).arg(o11).arg(o12).arg(o13);
442     return c.str();
443   }
444
445   template <typename T1, typename T2, typename T3, typename T4, typename T5,
446             typename T6, typename T7, typename T8, typename T9, typename T10,
447             typename T11, typename T12, typename T13, typename T14>
448   inline std::string compose(const std::string &fmt,
449                              const T1 &o1, const T2 &o2, const T3 &o3,
450                              const T4 &o4, const T5 &o5, const T6 &o6,
451                              const T7 &o7, const T8 &o8, const T9 &o9,
452                              const T10 &o10, const T11 &o11, const T12 &o12,
453                              const T13 &o13, const T14 &o14)
454   {
455     StringPrivate::Composition c(fmt);
456     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
457       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
458     return c.str();
459   }
460
461   template <typename T1, typename T2, typename T3, typename T4, typename T5,
462             typename T6, typename T7, typename T8, typename T9, typename T10,
463             typename T11, typename T12, typename T13, typename T14,
464             typename T15>
465   inline std::string compose(const std::string &fmt,
466                              const T1 &o1, const T2 &o2, const T3 &o3,
467                              const T4 &o4, const T5 &o5, const T6 &o6,
468                              const T7 &o7, const T8 &o8, const T9 &o9,
469                              const T10 &o10, const T11 &o11, const T12 &o12,
470                              const T13 &o13, const T14 &o14, const T15 &o15)
471   {
472     StringPrivate::Composition c(fmt);
473     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
474       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
475     return c.str();
476   }
477 }
478
479
480 #endif // STRING_COMPOSE_H