1 /* Defines String::compose(fmt, arg...) for easy, i18n-friendly
2 * composition of strings.
6 * Copyright (c) 2002 Ole Laursen <olau@hardworking.dk>.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 // Basic usage is like
27 // std::cout << String::compose("This is a %1x%2 matrix.", rows, cols);
29 // See http://www.cs.auc.dk/~olau/compose/ or the included README.compose for
33 #ifndef STRING_COMPOSE_H
34 #define STRING_COMPOSE_H
39 #include <map> // for multimap
41 #include "pbd/libpbd_visibility.h"
43 namespace StringPrivate
45 // the actual composition class - using string::compose is cleaner, so we
47 class LIBPBD_API Composition
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 // specialization to catch strings (C++ and C)
58 Composition &arg(const std::string &str);
59 Composition &arg(char const * const cstr);
61 // compose and return string
62 std::string str() const;
65 std::ostringstream os;
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;
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;
81 // helper for converting spec string numbers
82 inline int char_to_int(char c)
95 default: return -1000;
99 inline bool is_number(int n)
120 // implementation of class Composition
121 template <typename T>
122 inline Composition &Composition::arg(const T &obj)
126 std::string rep = os.str();
128 if (!rep.empty()) { // manipulators don't produce output
129 for (specification_map::const_iterator i = specs.lower_bound(arg_no),
130 end = specs.upper_bound(arg_no); i != end; ++i) {
131 output_list::iterator pos = i->second;
134 output.insert(pos, rep);
137 os.str(std::string());
145 inline Composition &Composition::arg(const std::string &str)
147 /* specialization to ensure that empty strings show up
150 for (specification_map::const_iterator i = specs.lower_bound(arg_no),
151 end = specs.upper_bound(arg_no); i != end; ++i) {
152 output_list::iterator pos = i->second;
155 output.insert(pos, str);
163 inline Composition &Composition::arg(char const * const cstr)
165 /* specialization to ensure that empty C strings show up
168 for (specification_map::const_iterator i = specs.lower_bound(arg_no),
169 end = specs.upper_bound(arg_no); i != end; ++i) {
170 output_list::iterator pos = i->second;
173 output.insert(pos, std::string (cstr));
181 inline Composition::Composition(std::string fmt)
184 std::string::size_type b = 0, i = 0;
186 // fill in output with the strings between the %1 %2 %3 etc. and
187 // fill in specs with the positions
188 while (i < fmt.length()) {
189 if (fmt[i] == '%' && i + 1 < fmt.length()) {
190 if (fmt[i + 1] == '%') { // catch %%
191 fmt.replace(i, 2, "%");
194 else if (is_number(fmt[i + 1])) { // aha! a spec!
196 output.push_back(fmt.substr(b, i - b));
198 int n = 1; // number of digits
202 spec_no += char_to_int(fmt[i + n]);
205 } while (i + n < fmt.length() && is_number(fmt[i + n]));
208 output_list::iterator pos = output.end();
209 --pos; // safe since we have just inserted a string>
211 specs.insert(specification_map::value_type(spec_no, pos));
213 // jump over spec string
224 if (i - b > 0) // add the rest of the string
225 output.push_back(fmt.substr(b, i - b));
228 inline std::string Composition::str() const
233 for (output_list::const_iterator i = output.begin(), end = output.end();
241 // now for the real thing(s)
244 // a series of functions which accept a format string on the form "text %1
245 // more %2 less %3" and a number of templated parameters and spits out the
247 template <typename T1>
248 inline std::string string_compose(const std::string &fmt, const T1 &o1)
250 StringPrivate::Composition c(fmt);
255 template <typename T1, typename T2>
256 inline std::string string_compose(const std::string &fmt,
257 const T1 &o1, const T2 &o2)
259 StringPrivate::Composition c(fmt);
264 template <typename T1, typename T2, typename T3>
265 inline std::string string_compose(const std::string &fmt,
266 const T1 &o1, const T2 &o2, const T3 &o3)
268 StringPrivate::Composition c(fmt);
269 c.arg(o1).arg(o2).arg(o3);
273 template <typename T1, typename T2, typename T3, typename T4>
274 inline std::string string_compose(const std::string &fmt,
275 const T1 &o1, const T2 &o2, const T3 &o3,
278 StringPrivate::Composition c(fmt);
279 c.arg(o1).arg(o2).arg(o3).arg(o4);
283 template <typename T1, typename T2, typename T3, typename T4, typename T5>
284 inline std::string string_compose(const std::string &fmt,
285 const T1 &o1, const T2 &o2, const T3 &o3,
286 const T4 &o4, const T5 &o5)
288 StringPrivate::Composition c(fmt);
289 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
293 template <typename T1, typename T2, typename T3, typename T4, typename T5,
295 inline std::string string_compose(const std::string &fmt,
296 const T1 &o1, const T2 &o2, const T3 &o3,
297 const T4 &o4, const T5 &o5, const T6 &o6)
299 StringPrivate::Composition c(fmt);
300 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
304 template <typename T1, typename T2, typename T3, typename T4, typename T5,
305 typename T6, typename T7>
306 inline std::string string_compose(const std::string &fmt,
307 const T1 &o1, const T2 &o2, const T3 &o3,
308 const T4 &o4, const T5 &o5, const T6 &o6,
311 StringPrivate::Composition c(fmt);
312 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
316 template <typename T1, typename T2, typename T3, typename T4, typename T5,
317 typename T6, typename T7, typename T8>
318 inline std::string string_compose(const std::string &fmt,
319 const T1 &o1, const T2 &o2, const T3 &o3,
320 const T4 &o4, const T5 &o5, const T6 &o6,
321 const T7 &o7, const T8 &o8)
323 StringPrivate::Composition c(fmt);
324 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
328 template <typename T1, typename T2, typename T3, typename T4, typename T5,
329 typename T6, typename T7, typename T8, typename T9>
330 inline std::string string_compose(const std::string &fmt,
331 const T1 &o1, const T2 &o2, const T3 &o3,
332 const T4 &o4, const T5 &o5, const T6 &o6,
333 const T7 &o7, const T8 &o8, const T9 &o9)
335 StringPrivate::Composition c(fmt);
336 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
340 template <typename T1, typename T2, typename T3, typename T4, typename T5,
341 typename T6, typename T7, typename T8, typename T9, typename T10>
342 inline std::string string_compose(const std::string &fmt,
343 const T1 &o1, const T2 &o2, const T3 &o3,
344 const T4 &o4, const T5 &o5, const T6 &o6,
345 const T7 &o7, const T8 &o8, const T9 &o9,
348 StringPrivate::Composition c(fmt);
349 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
354 template <typename T1, typename T2, typename T3, typename T4, typename T5,
355 typename T6, typename T7, typename T8, typename T9, typename T10,
357 inline std::string string_compose(const std::string &fmt,
358 const T1 &o1, const T2 &o2, const T3 &o3,
359 const T4 &o4, const T5 &o5, const T6 &o6,
360 const T7 &o7, const T8 &o8, const T9 &o9,
361 const T10 &o10, const T11 &o11)
363 StringPrivate::Composition c(fmt);
364 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
369 template <typename T1, typename T2, typename T3, typename T4, typename T5,
370 typename T6, typename T7, typename T8, typename T9, typename T10,
371 typename T11, typename T12>
372 inline std::string string_compose(const std::string &fmt,
373 const T1 &o1, const T2 &o2, const T3 &o3,
374 const T4 &o4, const T5 &o5, const T6 &o6,
375 const T7 &o7, const T8 &o8, const T9 &o9,
376 const T10 &o10, const T11 &o11, const T12 &o12)
378 StringPrivate::Composition c(fmt);
379 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
380 .arg(o10).arg(o11).arg(o12);
384 template <typename T1, typename T2, typename T3, typename T4, typename T5,
385 typename T6, typename T7, typename T8, typename T9, typename T10,
386 typename T11, typename T12, typename T13>
387 inline std::string 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, const T11 &o11, const T12 &o12,
394 StringPrivate::Composition c(fmt);
395 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
396 .arg(o10).arg(o11).arg(o12).arg(o13);
400 template <typename T1, typename T2, typename T3, typename T4, typename T5,
401 typename T6, typename T7, typename T8, typename T9, typename T10,
402 typename T11, typename T12, typename T13, typename T14>
403 inline std::string string_compose(const std::string &fmt,
404 const T1 &o1, const T2 &o2, const T3 &o3,
405 const T4 &o4, const T5 &o5, const T6 &o6,
406 const T7 &o7, const T8 &o8, const T9 &o9,
407 const T10 &o10, const T11 &o11, const T12 &o12,
408 const T13 &o13, const T14 &o14)
410 StringPrivate::Composition c(fmt);
411 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
412 .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
416 template <typename T1, typename T2, typename T3, typename T4, typename T5,
417 typename T6, typename T7, typename T8, typename T9, typename T10,
418 typename T11, typename T12, typename T13, typename T14,
420 inline std::string string_compose(const std::string &fmt,
421 const T1 &o1, const T2 &o2, const T3 &o3,
422 const T4 &o4, const T5 &o5, const T6 &o6,
423 const T7 &o7, const T8 &o8, const T9 &o9,
424 const T10 &o10, const T11 &o11, const T12 &o12,
425 const T13 &o13, const T14 &o14, const T15 &o15)
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).arg(o13).arg(o14).arg(o15);
435 #endif // STRING_COMPOSE_H