Rename ReelMXF -> ReelFileAsset.
[libdcp.git] / src / 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
51   class Composition
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