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.aau.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 namespace StringPrivate
43 // the actual composition class - using string::compose is cleaner, so we
48 // initialize and prepare format string on the form "text %1 text %2 etc."
49 explicit Composition(std::string fmt);
51 // supply an replacement argument starting from %1
53 Composition &arg(const T &obj);
55 // compose and return string
56 std::string str() const;
59 std::ostringstream os;
62 // we store the output as a list - when the output string is requested, the
63 // list is concatenated to a string; this way we can keep iterators into
64 // the list instead of into a string where they're possibly invalidated on
65 // inserting a specification string
66 typedef std::list<std::string> output_list;
69 // the initial parse of the format string fills in the specification map
70 // with positions for each of the various %?s
71 typedef std::multimap<int, output_list::iterator> specification_map;
72 specification_map specs;
75 // helper for converting spec string numbers
76 inline int char_to_int(char c)
89 default: return -1000;
93 inline bool is_number(int n)
114 // implementation of class Composition
115 template <typename T>
116 inline Composition &Composition::arg(const T &obj)
120 std::string rep = os.str();
122 if (!rep.empty()) { // manipulators don't produce output
123 for (specification_map::const_iterator i = specs.lower_bound(arg_no),
124 end = specs.upper_bound(arg_no); i != end; ++i) {
125 output_list::iterator pos = i->second;
128 output.insert(pos, rep);
131 os.str(std::string());
139 inline Composition::Composition(std::string fmt)
142 std::string::size_type b = 0, i = 0;
144 // fill in output with the strings between the %1 %2 %3 etc. and
145 // fill in specs with the positions
146 while (i < fmt.length()) {
147 if (fmt[i] == '%' && i + 1 < fmt.length()) {
148 if (fmt[i + 1] == '%') { // catch %%
149 fmt.replace(i, 2, "%");
152 else if (is_number(fmt[i + 1])) { // aha! a spec!
154 output.push_back(fmt.substr(b, i - b));
156 int n = 1; // number of digits
160 spec_no += char_to_int(fmt[i + n]);
163 } while (i + n < fmt.length() && is_number(fmt[i + n]));
166 output_list::iterator pos = output.end();
167 --pos; // safe since we have just inserted a string>
169 specs.insert(specification_map::value_type(spec_no, pos));
171 // jump over spec string
182 if (i - b > 0) // add the rest of the string
183 output.push_back(fmt.substr(b, i - b));
186 inline std::string Composition::str() const
191 for (output_list::const_iterator i = output.begin(), end = output.end();
199 // now for the real thing(s)
202 // a series of functions which accept a format string on the form "text %1
203 // more %2 less %3" and a number of templated parameters and spits out the
205 template <typename T1>
206 inline std::string compose(const std::string &fmt, const T1 &o1)
208 StringPrivate::Composition c(fmt);
213 template <typename T1, typename T2>
214 inline std::string compose(const std::string &fmt,
215 const T1 &o1, const T2 &o2)
217 StringPrivate::Composition c(fmt);
222 template <typename T1, typename T2, typename T3>
223 inline std::string compose(const std::string &fmt,
224 const T1 &o1, const T2 &o2, const T3 &o3)
226 StringPrivate::Composition c(fmt);
227 c.arg(o1).arg(o2).arg(o3);
231 template <typename T1, typename T2, typename T3, typename T4>
232 inline std::string compose(const std::string &fmt,
233 const T1 &o1, const T2 &o2, const T3 &o3,
236 StringPrivate::Composition c(fmt);
237 c.arg(o1).arg(o2).arg(o3).arg(o4);
241 template <typename T1, typename T2, typename T3, typename T4, typename T5>
242 inline std::string compose(const std::string &fmt,
243 const T1 &o1, const T2 &o2, const T3 &o3,
244 const T4 &o4, const T5 &o5)
246 StringPrivate::Composition c(fmt);
247 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
251 template <typename T1, typename T2, typename T3, typename T4, typename T5,
253 inline std::string compose(const std::string &fmt,
254 const T1 &o1, const T2 &o2, const T3 &o3,
255 const T4 &o4, const T5 &o5, const T6 &o6)
257 StringPrivate::Composition c(fmt);
258 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
262 template <typename T1, typename T2, typename T3, typename T4, typename T5,
263 typename T6, typename T7>
264 inline std::string compose(const std::string &fmt,
265 const T1 &o1, const T2 &o2, const T3 &o3,
266 const T4 &o4, const T5 &o5, const T6 &o6,
269 StringPrivate::Composition c(fmt);
270 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
274 template <typename T1, typename T2, typename T3, typename T4, typename T5,
275 typename T6, typename T7, typename T8>
276 inline std::string compose(const std::string &fmt,
277 const T1 &o1, const T2 &o2, const T3 &o3,
278 const T4 &o4, const T5 &o5, const T6 &o6,
279 const T7 &o7, const T8 &o8)
281 StringPrivate::Composition c(fmt);
282 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
286 template <typename T1, typename T2, typename T3, typename T4, typename T5,
287 typename T6, typename T7, typename T8, typename T9>
288 inline std::string compose(const std::string &fmt,
289 const T1 &o1, const T2 &o2, const T3 &o3,
290 const T4 &o4, const T5 &o5, const T6 &o6,
291 const T7 &o7, const T8 &o8, const T9 &o9)
293 StringPrivate::Composition c(fmt);
294 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
298 template <typename T1, typename T2, typename T3, typename T4, typename T5,
299 typename T6, typename T7, typename T8, typename T9, typename T10>
300 inline std::string compose(const std::string &fmt,
301 const T1 &o1, const T2 &o2, const T3 &o3,
302 const T4 &o4, const T5 &o5, const T6 &o6,
303 const T7 &o7, const T8 &o8, const T9 &o9,
306 StringPrivate::Composition c(fmt);
307 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
312 template <typename T1, typename T2, typename T3, typename T4, typename T5,
313 typename T6, typename T7, typename T8, typename T9, typename T10,
315 inline std::string compose(const std::string &fmt,
316 const T1 &o1, const T2 &o2, const T3 &o3,
317 const T4 &o4, const T5 &o5, const T6 &o6,
318 const T7 &o7, const T8 &o8, const T9 &o9,
319 const T10 &o10, const T11 &o11)
321 StringPrivate::Composition c(fmt);
322 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
327 template <typename T1, typename T2, typename T3, typename T4, typename T5,
328 typename T6, typename T7, typename T8, typename T9, typename T10,
329 typename T11, typename T12>
330 inline std::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,
334 const T10 &o10, const T11 &o11, const T12 &o12)
336 StringPrivate::Composition c(fmt);
337 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
338 .arg(o10).arg(o11).arg(o12);
342 template <typename T1, typename T2, typename T3, typename T4, typename T5,
343 typename T6, typename T7, typename T8, typename T9, typename T10,
344 typename T11, typename T12, typename T13>
345 inline std::string compose(const std::string &fmt,
346 const T1 &o1, const T2 &o2, const T3 &o3,
347 const T4 &o4, const T5 &o5, const T6 &o6,
348 const T7 &o7, const T8 &o8, const T9 &o9,
349 const T10 &o10, const T11 &o11, const T12 &o12,
352 StringPrivate::Composition c(fmt);
353 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
354 .arg(o10).arg(o11).arg(o12).arg(o13);
358 template <typename T1, typename T2, typename T3, typename T4, typename T5,
359 typename T6, typename T7, typename T8, typename T9, typename T10,
360 typename T11, typename T12, typename T13, typename T14>
361 inline std::string compose(const std::string &fmt,
362 const T1 &o1, const T2 &o2, const T3 &o3,
363 const T4 &o4, const T5 &o5, const T6 &o6,
364 const T7 &o7, const T8 &o8, const T9 &o9,
365 const T10 &o10, const T11 &o11, const T12 &o12,
366 const T13 &o13, const T14 &o14)
368 StringPrivate::Composition c(fmt);
369 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
370 .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
374 template <typename T1, typename T2, typename T3, typename T4, typename T5,
375 typename T6, typename T7, typename T8, typename T9, typename T10,
376 typename T11, typename T12, typename T13, typename T14,
378 inline std::string compose(const std::string &fmt,
379 const T1 &o1, const T2 &o2, const T3 &o3,
380 const T4 &o4, const T5 &o5, const T6 &o6,
381 const T7 &o7, const T8 &o8, const T9 &o9,
382 const T10 &o10, const T11 &o11, const T12 &o12,
383 const T13 &o13, const T14 &o14, const T15 &o15)
385 StringPrivate::Composition c(fmt);
386 c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
387 .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
393 #endif // STRING_COMPOSE_H