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>
43 namespace StringPrivate
45 // the actual composition class - using string::compose is cleaner, so we
50 // initialize and prepare format string on the form "text %1 text %2 etc."
51 explicit Composition(std::string fmt);
53 // supply an replacement argument starting from %1
55 Composition &arg(const T &obj);
57 // compose and return string
58 std::string str() const;
64 // we store the output as a list - when the output string is requested, the
65 // list is concatenated to a string; this way we can keep iterators into
66 // the list instead of into a string where they're possibly invalidated on
67 // inserting a specification string
68 typedef std::list<std::string> output_list;
71 // the initial parse of the format string fills in the specification map
72 // with positions for each of the various %?s
73 typedef std::multimap<int, output_list::iterator> specification_map;
74 specification_map specs;
77 // helper for converting spec string numbers
78 inline int char_to_int(char c)
91 default: return -1000;
95 inline bool is_number(int n)
115 template <typename T>
116 inline void write(std::string& s, const T& obj)
118 /* Assume anything not specialized has a to_string() method */
119 s += to_string (obj);
123 inline void write(std::string& s, const int64_t& obj)
126 snprintf(buffer, 64, "%" PRId64, obj);
131 inline void write(std::string& s, const int& obj)
134 snprintf(buffer, 64, "%d", obj);
139 inline void write(std::string& s, const unsigned int& obj)
142 snprintf(buffer, 64, "%ud", obj);
147 inline void write(std::string& s, const long unsigned int& obj)
150 snprintf(buffer, 64, "%lu", obj);
155 inline void write(std::string& s, const float& obj)
158 snprintf(buffer, 64, "%f", obj);
163 inline void write(std::string& s, const char& obj)
169 inline void write(std::string& s, const double& obj)
172 snprintf(buffer, 64, "%f", obj);
177 inline void write(std::string& s, char const * const & obj)
183 inline void write(std::string& s, char* const & obj)
189 inline void write(std::string& s, const std::string& obj)
195 inline void write(std::string& s, const boost::filesystem::path & obj)
200 // implementation of class Composition
201 template <typename T>
202 inline Composition &Composition::arg(const T &obj)
206 if (!os.empty()) { // manipulators don't produce output
207 for (specification_map::const_iterator i = specs.lower_bound(arg_no), end = specs.upper_bound(arg_no); i != end; ++i) {
208 output_list::iterator pos = i->second;
211 output.insert(pos, os);
221 inline Composition::Composition(std::string fmt)
224 std::string::size_type b = 0, i = 0;
226 // fill in output with the strings between the %1 %2 %3 etc. and
227 // fill in specs with the positions
228 while (i < fmt.length()) {
229 if (fmt[i] == '%' && i + 1 < fmt.length()) {
230 if (fmt[i + 1] == '%') { // catch %%
231 fmt.replace(i, 2, "%");
234 else if (is_number(fmt[i + 1])) { // aha! a spec!
236 output.push_back(fmt.substr(b, i - b));
238 int n = 1; // number of digits
242 spec_no += char_to_int(fmt[i + n]);
245 } while (i + n < fmt.length() && is_number(fmt[i + n]));
248 output_list::iterator pos = output.end();
249 --pos; // safe since we have just inserted a string>
251 specs.insert(specification_map::value_type(spec_no, pos));
253 // jump over spec string
264 if (i - b > 0) // add the rest of the string
265 output.push_back(fmt.substr(b, i - b));
268 inline std::string Composition::str() const
273 for (output_list::const_iterator i = output.begin(), end = output.end();
281 // now for the real thing(s)
284 // a series of functions which accept a format string on the form "text %1
285 // more %2 less %3" and a number of templated parameters and spits out the
287 template <typename T1>
288 inline std::string compose(const std::string &fmt, const T1 &o1)
290 StringPrivate::Composition c(fmt);
295 template <typename T1, typename T2>
296 inline std::string compose(const std::string &fmt,
297 const T1 &o1, const T2 &o2)
299 StringPrivate::Composition c(fmt);
304 template <typename T1, typename T2, typename T3>
305 inline std::string compose(const std::string &fmt,
306 const T1 &o1, const T2 &o2, const T3 &o3)
308 StringPrivate::Composition c(fmt);
309 c.arg(o1).arg(o2).arg(o3);
313 template <typename T1, typename T2, typename T3, typename T4>
314 inline std::string compose(const std::string &fmt,
315 const T1 &o1, const T2 &o2, const T3 &o3,
318 StringPrivate::Composition c(fmt);
319 c.arg(o1).arg(o2).arg(o3).arg(o4);
323 template <typename T1, typename T2, typename T3, typename T4, typename T5>
324 inline std::string compose(const std::string &fmt,
325 const T1 &o1, const T2 &o2, const T3 &o3,
326 const T4 &o4, const T5 &o5)
328 StringPrivate::Composition c(fmt);
329 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
333 template <typename T1, typename T2, typename T3, typename T4, typename T5,
335 inline std::string compose(const std::string &fmt,
336 const T1 &o1, const T2 &o2, const T3 &o3,
337 const T4 &o4, const T5 &o5, const T6 &o6)
339 StringPrivate::Composition c(fmt);
340 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
344 template <typename T1, typename T2, typename T3, typename T4, typename T5,
345 typename T6, typename T7>
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,
351 StringPrivate::Composition c(fmt);
352 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
356 template <typename T1, typename T2, typename T3, typename T4, typename T5,
357 typename T6, typename T7, typename T8>
358 inline std::string compose(const std::string &fmt,
359 const T1 &o1, const T2 &o2, const T3 &o3,
360 const T4 &o4, const T5 &o5, const T6 &o6,
361 const T7 &o7, const T8 &o8)
363 StringPrivate::Composition c(fmt);
364 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
368 template <typename T1, typename T2, typename T3, typename T4, typename T5,
369 typename T6, typename T7, typename T8, typename T9>
370 inline std::string compose(const std::string &fmt,
371 const T1 &o1, const T2 &o2, const T3 &o3,
372 const T4 &o4, const T5 &o5, const T6 &o6,
373 const T7 &o7, const T8 &o8, const T9 &o9)
375 StringPrivate::Composition c(fmt);
376 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
380 template <typename T1, typename T2, typename T3, typename T4, typename T5,
381 typename T6, typename T7, typename T8, typename T9, typename T10>
382 inline std::string compose(const std::string &fmt,
383 const T1 &o1, const T2 &o2, const T3 &o3,
384 const T4 &o4, const T5 &o5, const T6 &o6,
385 const T7 &o7, const T8 &o8, const T9 &o9,
388 StringPrivate::Composition c(fmt);
389 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
394 template <typename T1, typename T2, typename T3, typename T4, typename T5,
395 typename T6, typename T7, typename T8, typename T9, typename T10,
397 inline std::string compose(const std::string &fmt,
398 const T1 &o1, const T2 &o2, const T3 &o3,
399 const T4 &o4, const T5 &o5, const T6 &o6,
400 const T7 &o7, const T8 &o8, const T9 &o9,
401 const T10 &o10, const T11 &o11)
403 StringPrivate::Composition c(fmt);
404 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
409 template <typename T1, typename T2, typename T3, typename T4, typename T5,
410 typename T6, typename T7, typename T8, typename T9, typename T10,
411 typename T11, typename T12>
412 inline std::string compose(const std::string &fmt,
413 const T1 &o1, const T2 &o2, const T3 &o3,
414 const T4 &o4, const T5 &o5, const T6 &o6,
415 const T7 &o7, const T8 &o8, const T9 &o9,
416 const T10 &o10, const T11 &o11, const T12 &o12)
418 StringPrivate::Composition c(fmt);
419 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
420 .arg(o10).arg(o11).arg(o12);
424 template <typename T1, typename T2, typename T3, typename T4, typename T5,
425 typename T6, typename T7, typename T8, typename T9, typename T10,
426 typename T11, typename T12, typename T13>
427 inline std::string compose(const std::string &fmt,
428 const T1 &o1, const T2 &o2, const T3 &o3,
429 const T4 &o4, const T5 &o5, const T6 &o6,
430 const T7 &o7, const T8 &o8, const T9 &o9,
431 const T10 &o10, const T11 &o11, const T12 &o12,
434 StringPrivate::Composition c(fmt);
435 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
436 .arg(o10).arg(o11).arg(o12).arg(o13);
440 template <typename T1, typename T2, typename T3, typename T4, typename T5,
441 typename T6, typename T7, typename T8, typename T9, typename T10,
442 typename T11, typename T12, typename T13, typename T14>
443 inline std::string compose(const std::string &fmt,
444 const T1 &o1, const T2 &o2, const T3 &o3,
445 const T4 &o4, const T5 &o5, const T6 &o6,
446 const T7 &o7, const T8 &o8, const T9 &o9,
447 const T10 &o10, const T11 &o11, const T12 &o12,
448 const T13 &o13, const T14 &o14)
450 StringPrivate::Composition c(fmt);
451 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
452 .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
456 template <typename T1, typename T2, typename T3, typename T4, typename T5,
457 typename T6, typename T7, typename T8, typename T9, typename T10,
458 typename T11, typename T12, typename T13, typename T14,
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 const T13 &o13, const T14 &o14, const T15 &o15)
467 StringPrivate::Composition c(fmt);
468 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
469 .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
475 #endif // STRING_COMPOSE_H