1 /* -*- c-basic-offset: 2 -*-
2 * Defines String::compose(fmt, arg...) for easy, i18n-friendly
3 * composition of strings.
7 * Copyright (c) 2002 Ole Laursen <olau@hardworking.dk>.
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.
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.
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
26 // Basic usage is like
28 // std::cout << String::compose("This is a %1x%2 matrix.", rows, cols);
30 // See http://www.cs.aau.dk/~olau/compose/ or the included README.compose for
34 #ifndef STRING_COMPOSE_H
35 #define STRING_COMPOSE_H
37 #include <boost/filesystem.hpp>
44 namespace StringPrivate
46 // the actual composition class - using string::compose is cleaner, so we
51 // initialize and prepare format string on the form "text %1 text %2 etc."
52 explicit Composition(std::string fmt);
54 // supply an replacement argument starting from %1
56 Composition &arg(const T &obj);
58 // compose and return string
59 std::string str() const;
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;
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;
78 // helper for converting spec string numbers
79 inline int char_to_int(char c)
92 default: return -1000;
96 inline bool is_number(int n)
116 template <typename T>
117 inline void write(std::string& s, const T& obj)
119 /* Assume anything not specialized has a to_string() method */
120 s += to_string (obj);
124 inline void write(std::string& s, const int64_t& obj)
127 snprintf(buffer, 64, "%" PRId64, obj);
132 inline void write(std::string& s, const int& obj)
135 snprintf(buffer, 64, "%d", obj);
140 inline void write(std::string& s, const unsigned int& obj)
143 snprintf(buffer, 64, "%ud", obj);
148 inline void write(std::string& s, const long unsigned int& obj)
151 snprintf(buffer, 64, "%lu", obj);
156 inline void write(std::string& s, const float& obj)
159 snprintf(buffer, 64, "%f", obj);
164 inline void write(std::string& s, const char& obj)
170 inline void write(std::string& s, const double& obj)
173 snprintf(buffer, 64, "%f", obj);
178 inline void write(std::string& s, char const * const & obj)
184 inline void write(std::string& s, char* const & obj)
190 inline void write(std::string& s, const std::string& obj)
196 inline void write(std::string& s, const boost::filesystem::path & obj)
201 // implementation of class Composition
202 template <typename T>
203 inline Composition &Composition::arg(const T &obj)
207 if (!os.empty()) { // manipulators don't produce output
208 for (specification_map::const_iterator i = specs.lower_bound(arg_no), end = specs.upper_bound(arg_no); i != end; ++i) {
209 output_list::iterator pos = i->second;
212 output.insert(pos, os);
222 inline Composition::Composition(std::string fmt)
225 std::string::size_type b = 0, i = 0;
227 // fill in output with the strings between the %1 %2 %3 etc. and
228 // fill in specs with the positions
229 while (i < fmt.length()) {
230 if (fmt[i] == '%' && i + 1 < fmt.length()) {
231 if (fmt[i + 1] == '%') { // catch %%
232 fmt.replace(i, 2, "%");
235 else if (is_number(fmt[i + 1])) { // aha! a spec!
237 output.push_back(fmt.substr(b, i - b));
239 int n = 1; // number of digits
243 spec_no += char_to_int(fmt[i + n]);
246 } while (i + n < fmt.length() && is_number(fmt[i + n]));
249 output_list::iterator pos = output.end();
250 --pos; // safe since we have just inserted a string>
252 specs.insert(specification_map::value_type(spec_no, pos));
254 // jump over spec string
265 if (i - b > 0) // add the rest of the string
266 output.push_back(fmt.substr(b, i - b));
269 inline std::string Composition::str() const
274 for (output_list::const_iterator i = output.begin(), end = output.end();
282 // now for the real thing(s)
285 // a series of functions which accept a format string on the form "text %1
286 // more %2 less %3" and a number of templated parameters and spits out the
288 template <typename T1>
289 inline std::string compose(const std::string &fmt, const T1 &o1)
291 StringPrivate::Composition c(fmt);
296 template <typename T1, typename T2>
297 inline std::string compose(const std::string &fmt,
298 const T1 &o1, const T2 &o2)
300 StringPrivate::Composition c(fmt);
305 template <typename T1, typename T2, typename T3>
306 inline std::string compose(const std::string &fmt,
307 const T1 &o1, const T2 &o2, const T3 &o3)
309 StringPrivate::Composition c(fmt);
310 c.arg(o1).arg(o2).arg(o3);
314 template <typename T1, typename T2, typename T3, typename T4>
315 inline std::string compose(const std::string &fmt,
316 const T1 &o1, const T2 &o2, const T3 &o3,
319 StringPrivate::Composition c(fmt);
320 c.arg(o1).arg(o2).arg(o3).arg(o4);
324 template <typename T1, typename T2, typename T3, typename T4, typename T5>
325 inline std::string compose(const std::string &fmt,
326 const T1 &o1, const T2 &o2, const T3 &o3,
327 const T4 &o4, const T5 &o5)
329 StringPrivate::Composition c(fmt);
330 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
334 template <typename T1, typename T2, typename T3, typename T4, typename T5,
336 inline std::string compose(const std::string &fmt,
337 const T1 &o1, const T2 &o2, const T3 &o3,
338 const T4 &o4, const T5 &o5, const T6 &o6)
340 StringPrivate::Composition c(fmt);
341 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
345 template <typename T1, typename T2, typename T3, typename T4, typename T5,
346 typename T6, typename T7>
347 inline std::string compose(const std::string &fmt,
348 const T1 &o1, const T2 &o2, const T3 &o3,
349 const T4 &o4, const T5 &o5, const T6 &o6,
352 StringPrivate::Composition c(fmt);
353 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
357 template <typename T1, typename T2, typename T3, typename T4, typename T5,
358 typename T6, typename T7, typename T8>
359 inline std::string compose(const std::string &fmt,
360 const T1 &o1, const T2 &o2, const T3 &o3,
361 const T4 &o4, const T5 &o5, const T6 &o6,
362 const T7 &o7, const T8 &o8)
364 StringPrivate::Composition c(fmt);
365 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
369 template <typename T1, typename T2, typename T3, typename T4, typename T5,
370 typename T6, typename T7, typename T8, typename T9>
371 inline std::string compose(const std::string &fmt,
372 const T1 &o1, const T2 &o2, const T3 &o3,
373 const T4 &o4, const T5 &o5, const T6 &o6,
374 const T7 &o7, const T8 &o8, const T9 &o9)
376 StringPrivate::Composition c(fmt);
377 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
381 template <typename T1, typename T2, typename T3, typename T4, typename T5,
382 typename T6, typename T7, typename T8, typename T9, typename T10>
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 const T7 &o7, const T8 &o8, const T9 &o9,
389 StringPrivate::Composition c(fmt);
390 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
395 template <typename T1, typename T2, typename T3, typename T4, typename T5,
396 typename T6, typename T7, typename T8, typename T9, typename T10,
398 inline std::string compose(const std::string &fmt,
399 const T1 &o1, const T2 &o2, const T3 &o3,
400 const T4 &o4, const T5 &o5, const T6 &o6,
401 const T7 &o7, const T8 &o8, const T9 &o9,
402 const T10 &o10, const T11 &o11)
404 StringPrivate::Composition c(fmt);
405 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
410 template <typename T1, typename T2, typename T3, typename T4, typename T5,
411 typename T6, typename T7, typename T8, typename T9, typename T10,
412 typename T11, typename T12>
413 inline std::string compose(const std::string &fmt,
414 const T1 &o1, const T2 &o2, const T3 &o3,
415 const T4 &o4, const T5 &o5, const T6 &o6,
416 const T7 &o7, const T8 &o8, const T9 &o9,
417 const T10 &o10, const T11 &o11, const T12 &o12)
419 StringPrivate::Composition c(fmt);
420 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
421 .arg(o10).arg(o11).arg(o12);
425 template <typename T1, typename T2, typename T3, typename T4, typename T5,
426 typename T6, typename T7, typename T8, typename T9, typename T10,
427 typename T11, typename T12, typename T13>
428 inline std::string compose(const std::string &fmt,
429 const T1 &o1, const T2 &o2, const T3 &o3,
430 const T4 &o4, const T5 &o5, const T6 &o6,
431 const T7 &o7, const T8 &o8, const T9 &o9,
432 const T10 &o10, const T11 &o11, const T12 &o12,
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).arg(o13);
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, typename T14>
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, const T14 &o14)
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).arg(o14);
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,
461 inline std::string compose(const std::string &fmt,
462 const T1 &o1, const T2 &o2, const T3 &o3,
463 const T4 &o4, const T5 &o5, const T6 &o6,
464 const T7 &o7, const T8 &o8, const T9 &o9,
465 const T10 &o10, const T11 &o11, const T12 &o12,
466 const T13 &o13, const T14 &o14, const T15 &o15)
468 StringPrivate::Composition c(fmt);
469 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
470 .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
476 #endif // STRING_COMPOSE_H