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