OpenImageIO
 All Classes Files Friends Macros Pages
tinyformat.h
1 // tinyformat.h
2 // Copyright (C) 2011, Chris Foster [chris42f (at) gmail (d0t) com]
3 //
4 // Boost Software License - Version 1.0
5 //
6 // Permission is hereby granted, free of charge, to any person or organization
7 // obtaining a copy of the software and accompanying documentation covered by
8 // this license (the "Software") to use, reproduce, display, distribute,
9 // execute, and transmit the Software, and to prepare derivative works of the
10 // Software, and to permit third-parties to whom the Software is furnished to
11 // do so, all subject to the following:
12 //
13 // The copyright notices in the Software and this entire statement, including
14 // the above license grant, this restriction and the following disclaimer,
15 // must be included in all copies of the Software, in whole or in part, and
16 // all derivative works of the Software, unless such copies or derivative
17 // works are solely in the form of machine-executable object code generated by
18 // a source language processor.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 // DEALINGS IN THE SOFTWARE.
27 
28 //------------------------------------------------------------------------------
29 // Tinyformat: A minimal type safe printf-replacement library for C++
30 //
31 // This library aims to support 95% of casual C++ string formatting needs with
32 // a single lightweight header file. Anything you can do with this library
33 // can also be done with the standard C++ streams, but probably with
34 // considerably more typing :)
35 //
36 // Design goals:
37 //
38 // * Simplicity and minimalism. A single header file to include and distribute
39 // with your own projects.
40 // * Type safety and extensibility for user defined types.
41 // * Parse standard C99 format strings, and support most features.
42 // * Support as many commonly used ``printf()`` features as practical without
43 // compromising on simplicity.
44 //
45 //
46 // Example usage
47 // -------------
48 //
49 // To print the date, we might have
50 //
51 // std::string weekday = "Wednesday";
52 // const char* month = "July";
53 // long day = 27;
54 // int hour = 14;
55 // int min = 44;
56 //
57 // tfm::format(std::cout, "%s, %s %d, %.2d:%.2d\n",
58 // weekday, month, day, hour, min);
59 //
60 // (The types here are intentionally odd to emphasize the type safety of the
61 // interface.) The same thing could be achieved using either of the two
62 // convenience functions. One returns a std::string:
63 //
64 // std::string date = tfm::format("%s, %s %d, %.2d:%.2d\n",
65 // weekday, month, day, hour, min);
66 // std::cout << date;
67 //
68 // The other prints to the std::cout stream:
69 //
70 // tfm::printf("%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min);
71 //
72 //
73 // Brief outline of functionality
74 // ------------------------------
75 //
76 // (For full docs, see the accompanying README)
77 //
78 //
79 // Interface functions:
80 //
81 // template<typename T1, typename T2, ...>
82 // void format(std::ostream& stream, const char* formatString,
83 // const T1& value1, const T2& value1, ...)
84 //
85 // template<typename T1, typename T2, ...>
86 // std::string format(const char* formatString,
87 // const T1& value1, const T2& value1, ...)
88 //
89 // template<typename T1, typename T2, ...>
90 // void printf(const char* formatString,
91 // const T1& value1, const T2& value1, ...)
92 //
93 //
94 // Error handling: Define TINYFORMAT_ERROR to customize the error handling for
95 // format strings which are unsupported or have the wrong number of format
96 // specifiers (calls assert() by default).
97 //
98 // User defined types: Uses operator<< for user defined types by default.
99 // Overload formatValue() for more control.
100 //
101 // Wrapping tfm::format inside a user defined format function: See the macros
102 // TINYFORMAT_WRAP_FORMAT and TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS.
103 
104 
105 
106 #ifndef TINYFORMAT_H_INCLUDED
107 #define TINYFORMAT_H_INCLUDED
108 
109 namespace tinyformat {}
110 //------------------------------------------------------------------------------
111 // Config section. Customize to your liking!
112 
113 // Namespace alias to encourage brevity
114 namespace tfm = tinyformat;
115 
116 // Error handling; calls assert() by default.
117 // #define TINYFORMAT_ERROR(reasonString) your_error_handler(reasonString)
118 
119 // Define for C++0x variadic templates which make the code shorter & more
120 // general. If you don't define this, C++0x support is autodetected below.
121 // #define TINYFORMAT_USE_VARIADIC_TEMPLATES
122 
123 
124 //------------------------------------------------------------------------------
125 // Implementation details.
126 #include <cassert>
127 #include <iostream>
128 #include <sstream>
129 
130 #ifndef TINYFORMAT_ERROR
131 # define TINYFORMAT_ERROR(reason) assert(0 && reason)
132 #endif
133 
134 #if !defined(TINYFORMAT_USE_VARIADIC_TEMPLATES) && !defined(TINYFORMAT_NO_VARIADIC_TEMPLATES)
135 # ifdef __GXX_EXPERIMENTAL_CXX0X__
136 # define TINYFORMAT_USE_VARIADIC_TEMPLATES
137 # endif
138 #endif
139 
140 #ifdef __GNUC__
141 # define TINYFORMAT_NOINLINE __attribute__((noinline))
142 #elif defined(_MSC_VER)
143 # define TINYFORMAT_NOINLINE __declspec(noinline)
144 #else
145 # define TINYFORMAT_NOINLINE
146 #endif
147 
148 
149 namespace tinyformat {
150 
151 //------------------------------------------------------------------------------
152 namespace detail {
153 
154 // Test whether type T1 is convertible to type T2
155 template <typename T1, typename T2>
157 {
158  private:
159  // two types of different size
160  struct fail { char dummy[2]; };
161  struct succeed { char dummy; };
162  // Try to convert a T1 to a T2 by plugging into tryConvert
163  static fail tryConvert(...);
164  static succeed tryConvert(const T2&);
165  static const T1& makeT1();
166  public:
167 # ifdef _MSC_VER
168  // Disable spurious loss of precision warning in tryConvert(makeT1())
169 # pragma warning(push)
170 # pragma warning(disable:4244)
171 # endif
172  // Standard trick: the (...) version of tryConvert will be chosen from
173  // the overload set only if the version taking a T2 doesn't match.
174  // Then we compare the sizes of the return types to check which
175  // function matched. Very neat, in a disgusting kind of way :)
176  static const bool value =
177  sizeof(tryConvert(makeT1())) == sizeof(succeed);
178 # ifdef _MSC_VER
179 # pragma warning(pop)
180 # endif
181 };
182 
183 
184 // Format the value by casting to type fmtT. This default implementation
185 // should never be called.
186 template<typename T, typename fmtT, bool convertible = is_convertible<T, fmtT>::value>
188 {
189  static void invoke(std::ostream& out, const T& value) { assert(0); }
190 };
191 // Specialized version for types that can actually be converted to fmtT, as
192 // indicated by the "convertible" template parameter.
193 template<typename T, typename fmtT>
194 struct formatValueAsType<T,fmtT,true>
195 {
196  static void invoke(std::ostream& out, const T& value)
197  { out << static_cast<fmtT>(value); }
198 };
199 
200 
201 // Convert an arbitrary type to integer. The version with convertible=false
202 // throws an error.
203 template<typename T, bool convertible = is_convertible<T,int>::value>
205 {
206  static int invoke(const T& value)
207  {
208  TINYFORMAT_ERROR("tinyformat: Cannot convert from argument type to "
209  "integer for use as variable width or precision");
210  return 0;
211  }
212 };
213 // Specialization for convertToInt when conversion is possible
214 template<typename T>
215 struct convertToInt<T,true>
216 {
217  static int invoke(const T& value) { return static_cast<int>(value); }
218 };
219 
220 } // namespace detail
221 
222 
223 //------------------------------------------------------------------------------
224 // Variable formatting functions. May be overridden for user-defined types if
225 // desired.
226 
227 
228 // Format a value into a stream. Called from format() for all types by default.
229 //
230 // Users may override this for their own types. When this function is called,
231 // the stream flags will have been modified according to the format string.
232 // The format specification is provided in the range [fmtBegin, fmtEnd).
233 //
234 // By default, formatValue() uses the usual stream insertion operator
235 // operator<< to format the type T, with special cases for the %c and %p
236 // conversions.
237 template<typename T>
238 inline void formatValue(std::ostream& out, const char* fmtBegin,
239  const char* fmtEnd, const T& value)
240 {
241  // The mess here is to support the %c and %p conversions: if these
242  // conversions are active we try to convert the type to a char or const
243  // void* respectively and format that instead of the value itself. For the
244  // %p conversion it's important to avoid dereferencing the pointer, which
245  // could otherwise lead to a crash when printing a dangling (const char*).
246  const bool canConvertToChar = detail::is_convertible<T,char>::value;
247  const bool canConvertToVoidPtr = detail::is_convertible<T, const void*>::value;
248  if(canConvertToChar && *(fmtEnd-1) == 'c')
250  else if(canConvertToVoidPtr && *(fmtEnd-1) == 'p')
252  else
253  out << value;
254 }
255 
256 
257 // Overloaded version for char types to support printing as an integer
258 #define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType) \
259 inline void formatValue(std::ostream& out, const char* fmtBegin, \
260  const char* fmtEnd, charType value) \
261 { \
262  switch(*(fmtEnd-1)) \
263  { \
264  case 'u': case 'd': case 'i': case 'o': case 'X': case 'x': \
265  out << static_cast<int>(value); break; \
266  default: \
267  out << value; break; \
268  } \
269 }
270 // per 3.9.1: char, signed char and unsigned char are all distinct types
271 TINYFORMAT_DEFINE_FORMATVALUE_CHAR(char)
272 TINYFORMAT_DEFINE_FORMATVALUE_CHAR(signed char)
273 TINYFORMAT_DEFINE_FORMATVALUE_CHAR(unsigned char)
274 #undef TINYFORMAT_DEFINE_FORMATVALUE_CHAR
275 
276 
277 namespace detail {
278 
279 // Class holding current position in format string and an output stream into
280 // which arguments are formatted.
282 {
283  public:
284  // Flags for features not representable with standard stream state
285  enum ExtraFormatFlags
286  {
287  Flag_TruncateToPrecision = 1<<0, // truncate length to stream precision()
288  Flag_SpacePadPositive = 1<<1, // pad positive values with spaces
289  Flag_VariableWidth = 1<<2, // variable field width in arg list
290  Flag_VariablePrecision = 1<<3, // variable field precision in arg list
291  };
292 
293  // out is the output stream, fmt is the full format string
294  FormatIterator(std::ostream& out, const char* fmt)
295  : m_out(out),
296  m_fmt(fmt),
297  m_extraFlags(0),
298  m_wantWidth(false),
299  m_wantPrecision(false),
300  m_variableWidth(0),
301  m_variablePrecision(0),
302  m_origWidth(out.width()),
303  m_origPrecision(out.precision()),
304  m_origFlags(out.flags()),
305  m_origFill(out.fill())
306  { }
307 
308  // Print remaining part of format string.
309  void finish()
310  {
311  // It would be nice if we could do this from the destructor, but we
312  // can't if TINFORMAT_ERROR is used to throw an exception!
313  m_fmt = printFormatStringLiteral(m_out, m_fmt);
314  if(*m_fmt != '\0')
315  TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string");
316  }
317 
318  ~FormatIterator()
319  {
320  // Restore stream state
321  m_out.width(m_origWidth);
322  m_out.precision(m_origPrecision);
323  m_out.flags(m_origFlags);
324  m_out.fill(m_origFill);
325  }
326 
327  template<typename T>
328  void accept(const T& value);
329 
330  private:
331  // Parse and return an integer from the string c, as atoi()
332  // On return, c is set to one past the end of the integer.
333  static int parseIntAndAdvance(const char*& c)
334  {
335  int i = 0;
336  for(;*c >= '0' && *c <= '9'; ++c)
337  i = 10*i + (*c - '0');
338  return i;
339  }
340 
341  // Format at most truncLen characters of a C string to the given
342  // stream. Return true if formatting proceeded (generic version always
343  // returns false)
344  template<typename T>
345  static bool formatCStringTruncate(std::ostream& out, const T& value,
346  std::streamsize truncLen)
347  {
348  return false;
349  }
350 # define TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(type) \
351  static bool formatCStringTruncate(std::ostream& out, type* value, \
352  std::streamsize truncLen) \
353  { \
354  std::streamsize len = 0; \
355  while(len < truncLen && value[len] != 0) \
356  ++len; \
357  out.write(value, len); \
358  return true; \
359  }
360  // Overload for const char* and char*. Could overload for signed &
361  // unsigned char too, but these are technically unneeded for printf
362  // compatibility.
363  TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(const char)
364  TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(char)
365 # undef TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE
366 
367  // Print literal part of format string and return next format spec
368  // position.
369  //
370  // Skips over any occurrences of '%%', printing a literal '%' to the
371  // output. The position of the first % character of the next
372  // nontrivial format spec is returned, or the end of string.
373  static const char* printFormatStringLiteral(std::ostream& out,
374  const char* fmt)
375  {
376  const char* c = fmt;
377  for(; true; ++c)
378  {
379  switch(*c)
380  {
381  case '\0':
382  out.write(fmt, static_cast<std::streamsize>(c - fmt));
383  return c;
384  case '%':
385  out.write(fmt, static_cast<std::streamsize>(c - fmt));
386  if(*(c+1) != '%')
387  return c;
388  // for "%%", tack trailing % onto next literal section.
389  fmt = ++c;
390  break;
391  }
392  }
393  }
394 
395  static const char* streamStateFromFormat(std::ostream& out,
396  unsigned int& extraFlags,
397  const char* fmtStart,
398  int variableWidth,
399  int variablePrecision);
400 
401  // Stream, current format string & state
402  std::ostream& m_out;
403  const char* m_fmt;
404  unsigned int m_extraFlags;
405  // State machine info for handling of variable width & precision
406  bool m_wantWidth;
407  bool m_wantPrecision;
408  int m_variableWidth;
409  int m_variablePrecision;
410  // Saved stream state
411  std::streamsize m_origWidth;
412  std::streamsize m_origPrecision;
413  std::ios::fmtflags m_origFlags;
414  char m_origFill;
415 };
416 
417 
418 // Accept a value for formatting into the internal stream.
419 template<typename T>
420 TINYFORMAT_NOINLINE //< greatly reduces bloat in optimized builds
421 void FormatIterator::accept(const T& value)
422 {
423  // Parse the format string
424  const char* fmtEnd = 0;
425  if(m_extraFlags == 0 && !m_wantWidth && !m_wantPrecision)
426  {
427  m_fmt = printFormatStringLiteral(m_out, m_fmt);
428  fmtEnd = streamStateFromFormat(m_out, m_extraFlags, m_fmt, 0, 0);
429  m_wantWidth = (m_extraFlags & Flag_VariableWidth) != 0;
430  m_wantPrecision = (m_extraFlags & Flag_VariablePrecision) != 0;
431  }
432  // Consume value as variable width and precision specifier if necessary
433  if(m_extraFlags & (Flag_VariableWidth | Flag_VariablePrecision))
434  {
435  if(m_wantWidth || m_wantPrecision)
436  {
437  int v = convertToInt<T>::invoke(value);
438  if(m_wantWidth)
439  {
440  m_variableWidth = v;
441  m_wantWidth = false;
442  }
443  else if(m_wantPrecision)
444  {
445  m_variablePrecision = v;
446  m_wantPrecision = false;
447  }
448  return;
449  }
450  // If we get here, we've set both the variable precision and width as
451  // required and we need to rerun the stream state setup to insert these.
452  fmtEnd = streamStateFromFormat(m_out, m_extraFlags, m_fmt,
453  m_variableWidth, m_variablePrecision);
454  }
455 
456  // Format the value into the stream.
457  if(!(m_extraFlags & (Flag_SpacePadPositive | Flag_TruncateToPrecision)))
458  formatValue(m_out, m_fmt, fmtEnd, value);
459  else
460  {
461  // The following are special cases where there's no direct
462  // correspondence between stream formatting and the printf() behaviour.
463  // Instead, we simulate the behaviour crudely by formatting into a
464  // temporary string stream and munging the resulting string.
465  std::ostringstream tmpStream;
466  tmpStream.copyfmt(m_out);
467  if(m_extraFlags & Flag_SpacePadPositive)
468  tmpStream.setf(std::ios::showpos);
469  // formatCStringTruncate is required for truncating conversions like
470  // "%.4s" where at most 4 characters of the c-string should be read.
471  // If we didn't include this special case, we might read off the end.
472  if(!( (m_extraFlags & Flag_TruncateToPrecision) &&
473  formatCStringTruncate(tmpStream, value, m_out.precision()) ))
474  {
475  // Not a truncated c-string; just format normally.
476  formatValue(tmpStream, m_fmt, fmtEnd, value);
477  }
478  std::string result = tmpStream.str(); // allocates... yuck.
479  if(m_extraFlags & Flag_SpacePadPositive)
480  {
481  for(size_t i = 0, iend = result.size(); i < iend; ++i)
482  if(result[i] == '+')
483  result[i] = ' ';
484  }
485  if((m_extraFlags & Flag_TruncateToPrecision) &&
486  (int)result.size() > (int)m_out.precision())
487  m_out.write(result.c_str(), m_out.precision());
488  else
489  m_out << result;
490  }
491  m_extraFlags = 0;
492  m_fmt = fmtEnd;
493 }
494 
495 
496 // Parse a format string and set the stream state accordingly.
497 //
498 // The format mini-language recognized here is meant to be the one from C99,
499 // with the form "%[flags][width][.precision][length]type".
500 //
501 // Formatting options which can't be natively represented using the ostream
502 // state are returned in the extraFlags parameter which is a bitwise
503 // combination of values from the ExtraFormatFlags enum.
504 inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
505  unsigned int& extraFlags,
506  const char* fmtStart,
507  int variableWidth,
508  int variablePrecision)
509 {
510  if(*fmtStart != '%')
511  {
512  TINYFORMAT_ERROR("tinyformat: Not enough conversion specifiers in format string");
513  return fmtStart;
514  }
515  // Reset stream state to defaults.
516  out.width(0);
517  out.precision(6);
518  out.fill(' ');
519  // Reset most flags; ignore irrelevant unitbuf & skipws.
520  out.unsetf(std::ios::adjustfield | std::ios::basefield |
521  std::ios::floatfield | std::ios::showbase | std::ios::boolalpha |
522  std::ios::showpoint | std::ios::showpos | std::ios::uppercase);
523  extraFlags = 0;
524  bool precisionSet = false;
525  bool widthSet = false;
526  const char* c = fmtStart + 1;
527  // 1) Parse flags
528  for(;; ++c)
529  {
530  switch(*c)
531  {
532  case '#':
533  out.setf(std::ios::showpoint | std::ios::showbase);
534  continue;
535  case '0':
536  // overridden by left alignment ('-' flag)
537  if(!(out.flags() & std::ios::left))
538  {
539  // Use internal padding so that numeric values are
540  // formatted correctly, eg -00010 rather than 000-10
541  out.fill('0');
542  out.setf(std::ios::internal, std::ios::adjustfield);
543  }
544  continue;
545  case '-':
546  out.fill(' ');
547  out.setf(std::ios::left, std::ios::adjustfield);
548  continue;
549  case ' ':
550  // overridden by show positive sign, '+' flag.
551  if(!(out.flags() & std::ios::showpos))
552  extraFlags |= Flag_SpacePadPositive;
553  continue;
554  case '+':
555  out.setf(std::ios::showpos);
556  extraFlags &= ~Flag_SpacePadPositive;
557  continue;
558  }
559  break;
560  }
561  // 2) Parse width
562  if(*c >= '0' && *c <= '9')
563  {
564  widthSet = true;
565  out.width(parseIntAndAdvance(c));
566  }
567  if(*c == '*')
568  {
569  widthSet = true;
570  if(variableWidth < 0)
571  {
572  // negative widths correspond to '-' flag set
573  out.fill(' ');
574  out.setf(std::ios::left, std::ios::adjustfield);
575  variableWidth = -variableWidth;
576  }
577  out.width(variableWidth);
578  extraFlags |= Flag_VariableWidth;
579  ++c;
580  }
581  // 3) Parse precision
582  if(*c == '.')
583  {
584  ++c;
585  int precision = 0;
586  if(*c == '*')
587  {
588  ++c;
589  extraFlags |= Flag_VariablePrecision;
590  precision = variablePrecision;
591  }
592  else
593  {
594  if(*c >= '0' && *c <= '9')
595  precision = parseIntAndAdvance(c);
596  else if(*c == '-') // negative precisions ignored, treated as zero.
597  parseIntAndAdvance(++c);
598  }
599  out.precision(precision);
600  precisionSet = true;
601  }
602  // 4) Ignore any C99 length modifier
603  while(*c == 'l' || *c == 'h' || *c == 'L' ||
604  *c == 'j' || *c == 'z' || *c == 't')
605  ++c;
606  // 5) We're up to the conversion specifier character.
607  // Set stream flags based on conversion specifier (thanks to the
608  // boost::format class for forging the way here).
609  bool intConversion = false;
610  switch(*c)
611  {
612  case 'u': case 'd': case 'i':
613  out.setf(std::ios::dec, std::ios::basefield);
614  intConversion = true;
615  break;
616  case 'o':
617  out.setf(std::ios::oct, std::ios::basefield);
618  intConversion = true;
619  break;
620  case 'X':
621  out.setf(std::ios::uppercase);
622  case 'x': case 'p':
623  out.setf(std::ios::hex, std::ios::basefield);
624  intConversion = true;
625  break;
626  case 'E':
627  out.setf(std::ios::uppercase);
628  case 'e':
629  out.setf(std::ios::scientific, std::ios::floatfield);
630  out.setf(std::ios::dec, std::ios::basefield);
631  break;
632  case 'F':
633  out.setf(std::ios::uppercase);
634  case 'f':
635  out.setf(std::ios::fixed, std::ios::floatfield);
636  break;
637  case 'G':
638  out.setf(std::ios::uppercase);
639  case 'g':
640  out.setf(std::ios::dec, std::ios::basefield);
641  // As in boost::format, let stream decide float format.
642  out.flags(out.flags() & ~std::ios::floatfield);
643  break;
644  case 'a': case 'A':
645  break; // C99 hexadecimal floating point?? punt!
646  case 'c':
647  // Handled as special case inside formatValue()
648  break;
649  case 's':
650  if(precisionSet)
651  extraFlags |= Flag_TruncateToPrecision;
652  // Make %s print booleans as "true" and "false"
653  out.setf(std::ios::boolalpha);
654  break;
655  case 'n':
656  // Not supported - will cause problems!
657  TINYFORMAT_ERROR("tinyformat: %n conversion spec not supported");
658  break;
659  case '\0':
660  TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly "
661  "terminated by end of string");
662  return c;
663  }
664  if(intConversion && precisionSet && !widthSet)
665  {
666  // "precision" for integers gives the minimum number of digits (to be
667  // padded with zeros on the left). This isn't really supported by the
668  // iostreams, but we can approximately simulate it with the width if
669  // the width isn't otherwise used.
670  out.width(out.precision());
671  out.setf(std::ios::internal, std::ios::adjustfield);
672  out.fill('0');
673  }
674  return c+1;
675 }
676 
677 
678 
679 //------------------------------------------------------------------------------
680 // Private format function on top of which the public interface is implemented
681 inline void format(FormatIterator& fmtIter)
682 {
683  fmtIter.finish();
684 }
685 
686 // Define N-argument format function.
687 //
688 // There's two cases here: c++0x and c++98.
689 #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
690 
691 // First, the simple definition for C++0x:
692 template<typename T1, typename... Args>
693 void format(FormatIterator& fmtIter, const T1& value1, const Args&... args)
694 {
695  fmtIter.accept(value1);
696  format(fmtIter, args...);
697 }
698 
699 #else
700 
701 // For C++98 we don't have variadic templates so we need to generate code
702 // outside the language. We could do this with some ugly macros but instead
703 // let's use a short snippet of python code with the help of the excellent cog
704 // code generation script ( http://nedbatchelder.com/code/cog/ )
705 
706 /*[[[cog
707 
708 maxParams = 12
709 
710 # prepend a comma if the string isn't empty.
711 def prependComma(str):
712  return '' if str == '' else ', ' + str
713 
714 # Append backslashes to lines so they appear as a macro in C++
715 # lineLen is the desired padding before the backslash
716 def formatAsMacro(str, lineLen=75):
717  lines = str.splitlines()
718  lines = [l+' '*max(1, lineLen-len(l)) for l in lines]
719  return '\\\n'.join(lines) + '\\'
720 
721 # Fill out the given string template.
722 def fillTemplate(template, minParams=0, formatFunc=lambda s: s):
723  for i in range(minParams,maxParams+1):
724  paramRange = range(1,i+1)
725  templateSpec = ', '.join(['typename T%d' % (j,) for j in paramRange])
726  if templateSpec == '':
727  templateSpec = 'inline'
728  else:
729  templateSpec = 'template<%s>' % (templateSpec,)
730  paramList = prependComma(', '.join(['const T%d& v%d' % (j,j)
731  for j in paramRange]))
732  argList = prependComma(', '.join(['v%d' % (j,) for j in paramRange]))
733  argListNoHead = prependComma(', '.join(['v%d' % (j,)
734  for j in paramRange[1:]]))
735  cog.outl(formatFunc(template % locals()))
736 
737 fillTemplate(
738 '''%(templateSpec)s
739 void format(FormatIterator& fmtIter %(paramList)s)
740 {
741  fmtIter.accept(v1);
742  format(fmtIter%(argListNoHead)s);
743 }''', minParams=1)
744 
745 ]]]*/
746 template<typename T1>
747 void format(FormatIterator& fmtIter , const T1& v1)
748 {
749  fmtIter.accept(v1);
750  format(fmtIter);
751 }
752 template<typename T1, typename T2>
753 void format(FormatIterator& fmtIter , const T1& v1, const T2& v2)
754 {
755  fmtIter.accept(v1);
756  format(fmtIter, v2);
757 }
758 template<typename T1, typename T2, typename T3>
759 void format(FormatIterator& fmtIter , const T1& v1, const T2& v2, const T3& v3)
760 {
761  fmtIter.accept(v1);
762  format(fmtIter, v2, v3);
763 }
764 template<typename T1, typename T2, typename T3, typename T4>
765 void format(FormatIterator& fmtIter , const T1& v1, const T2& v2, const T3& v3, const T4& v4)
766 {
767  fmtIter.accept(v1);
768  format(fmtIter, v2, v3, v4);
769 }
770 template<typename T1, typename T2, typename T3, typename T4, typename T5>
771 void format(FormatIterator& fmtIter , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5)
772 {
773  fmtIter.accept(v1);
774  format(fmtIter, v2, v3, v4, v5);
775 }
776 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
777 void format(FormatIterator& fmtIter , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6)
778 {
779  fmtIter.accept(v1);
780  format(fmtIter, v2, v3, v4, v5, v6);
781 }
782 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
783 void format(FormatIterator& fmtIter , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7)
784 {
785  fmtIter.accept(v1);
786  format(fmtIter, v2, v3, v4, v5, v6, v7);
787 }
788 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
789 void format(FormatIterator& fmtIter , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8)
790 {
791  fmtIter.accept(v1);
792  format(fmtIter, v2, v3, v4, v5, v6, v7, v8);
793 }
794 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
795 void format(FormatIterator& fmtIter , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9)
796 {
797  fmtIter.accept(v1);
798  format(fmtIter, v2, v3, v4, v5, v6, v7, v8, v9);
799 }
800 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10>
801 void format(FormatIterator& fmtIter , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10)
802 {
803  fmtIter.accept(v1);
804  format(fmtIter, v2, v3, v4, v5, v6, v7, v8, v9, v10);
805 }
806 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11>
807 void format(FormatIterator& fmtIter , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11)
808 {
809  fmtIter.accept(v1);
810  format(fmtIter, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
811 }
812 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12>
813 void format(FormatIterator& fmtIter , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12)
814 {
815  fmtIter.accept(v1);
816  format(fmtIter, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
817 }
818 //[[[end]]]
819 
820 #endif // End C++98 variadic template emulation for format()
821 
822 } // namespace detail
823 
824 
825 //------------------------------------------------------------------------------
826 // Define the macro TINYFORMAT_WRAP_FORMAT, which can be used to wrap a call
827 // to tfm::format for C++98 support.
828 //
829 // We make this available in both C++0x and C++98 mode for convenience so that
830 // users can choose not to write out the C++0x version if they're primarily
831 // interested in C++98 support, but still have things work with C++0x.
832 //
833 // Note that TINYFORMAT_WRAP_EXTRA_ARGS cannot be a macro parameter because it
834 // must expand to a comma separated list (or nothing, as used for printf below)
835 
836 /*[[[cog
837 cog.outl(formatAsMacro(
838 '''#define TINYFORMAT_WRAP_FORMAT(returnType, funcName, funcDeclSuffix,
839  bodyPrefix, streamName, bodySuffix)'''))
840 
841 fillTemplate(
842 r'''%(templateSpec)s
843 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt
844  %(paramList)s) funcDeclSuffix
845 {
846  bodyPrefix
847  tinyformat::detail::FormatIterator fmtIter(streamName, fmt);
848  tinyformat::detail::format(fmtIter%(argList)s);
849  bodySuffix
850 }''', minParams=0, formatFunc=formatAsMacro)
851 cog.outl()
852 
853 ]]]*/
854 #ifndef TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS
855 #define TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS
856 #endif
857 
858 
859 #define TINYFORMAT_WRAP_FORMAT(returnType, funcName, funcDeclSuffix, \
860  bodyPrefix, streamName, bodySuffix) \
861 inline \
862 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
863  ) funcDeclSuffix \
864 { \
865  bodyPrefix \
866  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
867  tinyformat::detail::format(fmtIter); \
868  bodySuffix \
869 } \
870 template<typename T1> \
871 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
872  , const T1& v1) funcDeclSuffix \
873 { \
874  bodyPrefix \
875  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
876  tinyformat::detail::format(fmtIter, v1); \
877  bodySuffix \
878 } \
879 template<typename T1, typename T2> \
880 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
881  , const T1& v1, const T2& v2) funcDeclSuffix \
882 { \
883  bodyPrefix \
884  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
885  tinyformat::detail::format(fmtIter, v1, v2); \
886  bodySuffix \
887 } \
888 template<typename T1, typename T2, typename T3> \
889 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
890  , const T1& v1, const T2& v2, const T3& v3) funcDeclSuffix \
891 { \
892  bodyPrefix \
893  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
894  tinyformat::detail::format(fmtIter, v1, v2, v3); \
895  bodySuffix \
896 } \
897 template<typename T1, typename T2, typename T3, typename T4> \
898 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
899  , const T1& v1, const T2& v2, const T3& v3, const T4& v4) funcDeclSuffix \
900 { \
901  bodyPrefix \
902  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
903  tinyformat::detail::format(fmtIter, v1, v2, v3, v4); \
904  bodySuffix \
905 } \
906 template<typename T1, typename T2, typename T3, typename T4, typename T5> \
907 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
908  , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5) funcDeclSuffix \
909 { \
910  bodyPrefix \
911  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
912  tinyformat::detail::format(fmtIter, v1, v2, v3, v4, v5); \
913  bodySuffix \
914 } \
915 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> \
916 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
917  , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6) funcDeclSuffix \
918 { \
919  bodyPrefix \
920  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
921  tinyformat::detail::format(fmtIter, v1, v2, v3, v4, v5, v6); \
922  bodySuffix \
923 } \
924 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> \
925 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
926  , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7) funcDeclSuffix \
927 { \
928  bodyPrefix \
929  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
930  tinyformat::detail::format(fmtIter, v1, v2, v3, v4, v5, v6, v7); \
931  bodySuffix \
932 } \
933 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> \
934 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
935  , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8) funcDeclSuffix \
936 { \
937  bodyPrefix \
938  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
939  tinyformat::detail::format(fmtIter, v1, v2, v3, v4, v5, v6, v7, v8); \
940  bodySuffix \
941 } \
942 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> \
943 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
944  , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9) funcDeclSuffix \
945 { \
946  bodyPrefix \
947  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
948  tinyformat::detail::format(fmtIter, v1, v2, v3, v4, v5, v6, v7, v8, v9); \
949  bodySuffix \
950 } \
951 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10> \
952 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
953  , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10) funcDeclSuffix \
954 { \
955  bodyPrefix \
956  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
957  tinyformat::detail::format(fmtIter, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); \
958  bodySuffix \
959 } \
960 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11> \
961 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
962  , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11) funcDeclSuffix \
963 { \
964  bodyPrefix \
965  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
966  tinyformat::detail::format(fmtIter, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); \
967  bodySuffix \
968 } \
969 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12> \
970 returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
971  , const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12) funcDeclSuffix \
972 { \
973  bodyPrefix \
974  tinyformat::detail::FormatIterator fmtIter(streamName, fmt); \
975  tinyformat::detail::format(fmtIter, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); \
976  bodySuffix \
977 } \
978 
979 //[[[end]]]
980 
981 
982 //------------------------------------------------------------------------------
983 // Implement all the main interface functions here in terms of detail::format()
984 
985 // Again, there's two cases.
986 #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
987 
988 // C++0x - the simple case
989 template<typename... Args>
990 void format(std::ostream& out, const char* fmt, const Args&... args)
991 {
992  detail::FormatIterator fmtIter(out, fmt);
993  format(fmtIter, args...);
994 }
995 
996 template<typename... Args>
997 std::string format(const char* fmt, const Args&... args)
998 {
999  std::ostringstream oss;
1000  format(oss, fmt, args...);
1001  return oss.str();
1002 }
1003 
1004 template<typename... Args>
1005 void printf(const char* fmt, const Args&... args)
1006 {
1007  format(std::cout, fmt, args...);
1008 }
1009 
1010 #else
1011 
1012 // C++98 - define the convenience functions using the wrapping macros
1013 
1014 // template<typename... Args>
1015 // void format(std::ostream& out, const char* fmt, const Args&... args)
1016 #undef TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS
1017 #define TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS std::ostream& out,
1018 TINYFORMAT_WRAP_FORMAT(void, format, /*empty*/, /*empty*/, out, /*empty*/)
1019 #undef TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS
1020 
1021 // Define to nothing for format & printf; leave defined for convenience.
1022 #define TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS
1023 
1024 // std::string format(const char* fmt, const Args&... args);
1025 TINYFORMAT_WRAP_FORMAT(std::string, format, /*empty*/,
1026  std::ostringstream oss;, oss,
1027  return oss.str();)
1028 
1029 // void printf(const char* fmt, const Args&... args)
1030 TINYFORMAT_WRAP_FORMAT(void, printf, /*empty*/, /*empty*/, std::cout, /*empty*/)
1031 
1032 #endif
1033 
1034 } // namespace tinyformat
1035 
1036 #endif // TINYFORMAT_H_INCLUDED