Rcpp Version 1.0.9
tinyformat.h
Go to the documentation of this file.
1 // #nocov start
2 // tinyformat.h
3 // Copyright (C) 2011, Chris Foster [chris42f (at) gmail (d0t) com]
4 //
5 // Boost Software License - Version 1.0
6 //
7 // Permission is hereby granted, free of charge, to any person or organization
8 // obtaining a copy of the software and accompanying documentation covered by
9 // this license (the "Software") to use, reproduce, display, distribute,
10 // execute, and transmit the Software, and to prepare derivative works of the
11 // Software, and to permit third-parties to whom the Software is furnished to
12 // do so, all subject to the following:
13 //
14 // The copyright notices in the Software and this entire statement, including
15 // the above license grant, this restriction and the following disclaimer,
16 // must be included in all copies of the Software, in whole or in part, and
17 // all derivative works of the Software, unless such copies or derivative
18 // works are solely in the form of machine-executable object code generated by
19 // a source language processor.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24 // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25 // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 // DEALINGS IN THE SOFTWARE.
28 
29 //------------------------------------------------------------------------------
30 // Tinyformat: A minimal type safe printf replacement
31 //
32 // tinyformat.h is a type safe printf replacement library in a single C++
33 // header file. Design goals include:
34 //
35 // * Type safety and extensibility for user defined types.
36 // * C99 printf() compatibility, to the extent possible using std::ostream
37 // * Simplicity and minimalism. A single header file to include and distribute
38 // with your projects.
39 // * Augment rather than replace the standard stream formatting mechanism
40 // * C++98 support, with optional C++11 niceties
41 //
42 //
43 // Main interface example usage
44 // ----------------------------
45 //
46 // To print a date to std::cout:
47 //
48 // std::string weekday = "Wednesday";
49 // const char* month = "July";
50 // size_t day = 27;
51 // long hour = 14;
52 // int min = 44;
53 //
54 // tfm::printf("%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min);
55 //
56 // The strange types here emphasize the type safety of the interface; it is
57 // possible to print a std::string using the "%s" conversion, and a
58 // size_t using the "%d" conversion. A similar result could be achieved
59 // using either of the tfm::format() functions. One prints on a user provided
60 // stream:
61 //
62 // tfm::format(std::cerr, "%s, %s %d, %.2d:%.2d\n",
63 // weekday, month, day, hour, min);
64 //
65 // The other returns a std::string:
66 //
67 // std::string date = tfm::format("%s, %s %d, %.2d:%.2d\n",
68 // weekday, month, day, hour, min);
69 // std::cout << date;
70 //
71 // These are the three primary interface functions. There is also a
72 // convenience function printfln() which appends a newline to the usual result
73 // of printf() for super simple logging.
74 //
75 //
76 // User defined format functions
77 // -----------------------------
78 //
79 // Simulating variadic templates in C++98 is pretty painful since it requires
80 // writing out the same function for each desired number of arguments. To make
81 // this bearable tinyformat comes with a set of macros which are used
82 // internally to generate the API, but which may also be used in user code.
83 //
84 // The three macros TINYFORMAT_ARGTYPES(n), TINYFORMAT_VARARGS(n) and
85 // TINYFORMAT_PASSARGS(n) will generate a list of n argument types,
86 // type/name pairs and argument names respectively when called with an integer
87 // n between 1 and 16. We can use these to define a macro which generates the
88 // desired user defined function with n arguments. To generate all 16 user
89 // defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM. For an
90 // example, see the implementation of printf() at the end of the source file.
91 //
92 // Sometimes it's useful to be able to pass a list of format arguments through
93 // to a non-template function. The FormatList class is provided as a way to do
94 // this by storing the argument list in a type-opaque way. Continuing the
95 // example from above, we construct a FormatList using makeFormatList():
96 //
97 // FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour, min);
98 //
99 // The format list can now be passed into any non-template function and used
100 // via a call to the vformat() function:
101 //
102 // tfm::vformat(std::cout, "%s, %s %d, %.2d:%.2d\n", formatList);
103 //
104 //
105 // Additional API information
106 // --------------------------
107 //
108 // Error handling: Define TINYFORMAT_ERROR to customize the error handling for
109 // format strings which are unsupported or have the wrong number of format
110 // specifiers (calls assert() by default).
111 //
112 // User defined types: Uses operator<< for user defined types by default.
113 // Overload formatValue() for more control.
114 
115 
116 #ifndef TINYFORMAT_H_INCLUDED
117 #define TINYFORMAT_H_INCLUDED
118 
119 namespace tinyformat {}
120 //------------------------------------------------------------------------------
121 // Config section. Customize to your liking!
122 
123 // Namespace alias to encourage brevity
124 namespace tfm = tinyformat;
125 
126 // Error handling; calls assert() by default.
127 // #define TINYFORMAT_ERROR(reasonString) your_error_handler(reasonString)
128 
129 // Define for C++11 variadic templates which make the code shorter & more
130 // general. If you don't define this, C++11 support is autodetected below.
131 // #define TINYFORMAT_USE_VARIADIC_TEMPLATES
132 
133 
134 //------------------------------------------------------------------------------
135 // Implementation details.
136 #include <algorithm>
137 #include <cassert>
138 #include <iostream>
139 #include <sstream>
140 
141 #ifndef TINYFORMAT_ASSERT
142 # define TINYFORMAT_ASSERT(cond) assert(cond)
143 #endif
144 
145 #ifndef TINYFORMAT_ERROR
146 # define TINYFORMAT_ERROR(reason) assert(0 && reason)
147 #endif
148 
149 #if !defined(TINYFORMAT_USE_VARIADIC_TEMPLATES) && !defined(TINYFORMAT_NO_VARIADIC_TEMPLATES)
150 # ifdef __GXX_EXPERIMENTAL_CXX0X__
151 # define TINYFORMAT_USE_VARIADIC_TEMPLATES
152 # endif
153 #endif
154 
155 #if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201
156 // std::showpos is broken on old libstdc++ as provided with OSX. See
157 // http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html
158 # define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
159 #endif
160 
161 #ifdef __APPLE__
162 // Workaround OSX linker warning: xcode uses different default symbol
163 // visibilities for static libs vs executables (see issue #25)
164 # define TINYFORMAT_HIDDEN __attribute__((visibility("hidden")))
165 #else
166 # define TINYFORMAT_HIDDEN
167 #endif
168 
169 namespace tinyformat {
170 
171 //------------------------------------------------------------------------------
172 namespace detail {
173 
174 // Test whether type T1 is convertible to type T2
175 template <typename T1, typename T2>
177 {
178  private:
179  // two types of different size
180  struct fail { char dummy[2]; };
181  struct succeed { char dummy; };
182  // Try to convert a T1 to a T2 by plugging into tryConvert
183  static fail tryConvert(...);
184  static succeed tryConvert(const T2&);
185  static const T1& makeT1();
186  public:
187 # ifdef _MSC_VER
188  // Disable spurious loss of precision warnings in tryConvert(makeT1())
189 # pragma warning(push)
190 # pragma warning(disable:4244)
191 # pragma warning(disable:4267)
192 # endif
193  // Standard trick: the (...) version of tryConvert will be chosen from
194  // the overload set only if the version taking a T2 doesn't match.
195  // Then we compare the sizes of the return types to check which
196  // function matched. Very neat, in a disgusting kind of way :)
197  static const bool value =
198  sizeof(tryConvert(makeT1())) == sizeof(succeed);
199 # ifdef _MSC_VER
200 # pragma warning(pop)
201 # endif
202 };
203 
204 
205 // Detect when a type is not a wchar_t string
206 template<typename T> struct is_wchar { typedef int tinyformat_wchar_is_not_supported; };
207 template<> struct is_wchar<wchar_t*> {};
208 template<> struct is_wchar<const wchar_t*> {};
209 template<int n> struct is_wchar<const wchar_t[n]> {};
210 template<int n> struct is_wchar<wchar_t[n]> {};
211 
212 
213 // Format the value by casting to type fmtT. This default implementation
214 // should never be called.
215 template<typename T, typename fmtT, bool convertible = is_convertible<T, fmtT>::value>
217 {
218  static void invoke(std::ostream& /*out*/, const T& /*value*/) { TINYFORMAT_ASSERT(0); }
219 };
220 // Specialized version for types that can actually be converted to fmtT, as
221 // indicated by the "convertible" template parameter.
222 template<typename T, typename fmtT>
223 struct formatValueAsType<T,fmtT,true>
224 {
225  static void invoke(std::ostream& out, const T& value)
226  { out << static_cast<fmtT>(value); }
227 };
228 
229 #ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
230 template<typename T, bool convertible = is_convertible<T, int>::value>
231 struct formatZeroIntegerWorkaround
232 {
233  static bool invoke(std::ostream& , const T& ) { return false; }
234 };
235 template<typename T>
236 struct formatZeroIntegerWorkaround<T,true>
237 {
238  static bool invoke(std::ostream& out, const T& value)
239  {
240  if (static_cast<int>(value) == 0 && out.flags() & std::ios::showpos)
241  {
242  out << "+0";
243  return true;
244  }
245  return false;
246  }
247 };
248 #endif // TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
249 
250 // Convert an arbitrary type to integer. The version with convertible=false
251 // throws an error.
252 template<typename T, bool convertible = is_convertible<T,int>::value>
254 {
255  static int invoke(const T& /*value*/)
256  {
257  TINYFORMAT_ERROR("tinyformat: Cannot convert from argument type to "
258  "integer for use as variable width or precision");
259  return 0;
260  }
261 };
262 // Specialization for convertToInt when conversion is possible
263 template<typename T>
264 struct convertToInt<T,true>
265 {
266  static int invoke(const T& value) { return static_cast<int>(value); }
267 };
268 
269 // Format at most ntrunc characters to the given stream.
270 template<typename T>
271 inline void formatTruncated(std::ostream& out, const T& value, int ntrunc)
272 {
273  std::ostringstream tmp;
274  tmp << value;
275  std::string result = tmp.str();
276  out.write(result.c_str(), (std::min)(ntrunc, static_cast<int>(result.size())));
277 }
278 #define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type) \
279 inline void formatTruncated(std::ostream& out, type* value, int ntrunc) \
280 { \
281  std::streamsize len = 0; \
282  while(len < ntrunc && value[len] != 0) \
283  ++len; \
284  out.write(value, len); \
285 }
286 // Overload for const char* and char*. Could overload for signed & unsigned
287 // char too, but these are technically unneeded for printf compatibility.
290 #undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR
291 
292 } // namespace detail
293 
294 
295 //------------------------------------------------------------------------------
296 // Variable formatting functions. May be overridden for user-defined types if
297 // desired.
298 
299 
311 template<typename T>
312 inline void formatValue(std::ostream& out, const char* /*fmtBegin*/,
313  const char* fmtEnd, int ntrunc, const T& value)
314 {
315 #ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS
316  // Since we don't support printing of wchar_t using "%ls", make it fail at
317  // compile time in preference to printing as a void* at runtime.
319  (void) DummyType(); // avoid unused type warning with gcc-4.8
320 #endif
321  // The mess here is to support the %c and %p conversions: if these
322  // conversions are active we try to convert the type to a char or const
323  // void* respectively and format that instead of the value itself. For the
324  // %p conversion it's important to avoid dereferencing the pointer, which
325  // could otherwise lead to a crash when printing a dangling (const char*).
326  const bool canConvertToChar = detail::is_convertible<T,char>::value;
327  const bool canConvertToVoidPtr = detail::is_convertible<T, const void*>::value;
328  if(canConvertToChar && *(fmtEnd-1) == 'c')
330  else if(canConvertToVoidPtr && *(fmtEnd-1) == 'p')
332 #ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
333  else if(detail::formatZeroIntegerWorkaround<T>::invoke(out, value)) ;
334 #endif
335  else if(ntrunc >= 0)
336  {
337  // Take care not to overread C strings in truncating conversions like
338  // "%.4s" where at most 4 characters may be read.
339  detail::formatTruncated(out, value, ntrunc);
340  }
341  else
342  out << value;
343 }
344 
345 
346 // Overloaded version for char types to support printing as an integer
347 #define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType) \
348 inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, \
349  const char* fmtEnd, int , charType value) \
350 { \
351  switch(*(fmtEnd-1)) \
352  { \
353  case 'u': case 'd': case 'i': case 'o': case 'X': case 'x': \
354  out << static_cast<int>(value); break; \
355  default: \
356  out << value; break; \
357  } \
358 }
359 // per 3.9.1: char, signed char and unsigned char are all distinct types
363 #undef TINYFORMAT_DEFINE_FORMATVALUE_CHAR
364 
365 
366 //------------------------------------------------------------------------------
367 // Tools for emulating variadic templates in C++98. The basic idea here is
368 // stolen from the boost preprocessor metaprogramming library and cut down to
369 // be just general enough for what we need.
370 
371 #define TINYFORMAT_ARGTYPES(n) TINYFORMAT_ARGTYPES_ ## n
372 #define TINYFORMAT_VARARGS(n) TINYFORMAT_VARARGS_ ## n
373 #define TINYFORMAT_PASSARGS(n) TINYFORMAT_PASSARGS_ ## n
374 #define TINYFORMAT_PASSARGS_TAIL(n) TINYFORMAT_PASSARGS_TAIL_ ## n
375 
376 // To keep it as transparent as possible, the macros below have been generated
377 // using python via the excellent cog.py code generation script. This avoids
378 // the need for a bunch of complex (but more general) preprocessor tricks as
379 // used in boost.preprocessor.
380 //
381 // To rerun the code generation in place, use `cog.py -r tinyformat.h`
382 // (see http://nedbatchelder.com/code/cog). Alternatively you can just create
383 // extra versions by hand.
384 
385 /*[[[cog
386 maxParams = 16
387 
388 def makeCommaSepLists(lineTemplate, elemTemplate, startInd=1):
389  for j in range(startInd,maxParams+1):
390  list = ', '.join([elemTemplate % {'i':i} for i in range(startInd,j+1)])
391  cog.outl(lineTemplate % {'j':j, 'list':list})
392 
393 makeCommaSepLists('#define TINYFORMAT_ARGTYPES_%(j)d %(list)s',
394  'class T%(i)d')
395 
396 cog.outl()
397 makeCommaSepLists('#define TINYFORMAT_VARARGS_%(j)d %(list)s',
398  'const T%(i)d& v%(i)d')
399 
400 cog.outl()
401 makeCommaSepLists('#define TINYFORMAT_PASSARGS_%(j)d %(list)s', 'v%(i)d')
402 
403 cog.outl()
404 cog.outl('#define TINYFORMAT_PASSARGS_TAIL_1')
405 makeCommaSepLists('#define TINYFORMAT_PASSARGS_TAIL_%(j)d , %(list)s',
406  'v%(i)d', startInd = 2)
407 
408 cog.outl()
409 cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n ' +
410  ' '.join(['m(%d)' % (j,) for j in range(1,maxParams+1)]))
411 ]]]*/
412 #define TINYFORMAT_ARGTYPES_1 class T1
413 #define TINYFORMAT_ARGTYPES_2 class T1, class T2
414 #define TINYFORMAT_ARGTYPES_3 class T1, class T2, class T3
415 #define TINYFORMAT_ARGTYPES_4 class T1, class T2, class T3, class T4
416 #define TINYFORMAT_ARGTYPES_5 class T1, class T2, class T3, class T4, class T5
417 #define TINYFORMAT_ARGTYPES_6 class T1, class T2, class T3, class T4, class T5, class T6
418 #define TINYFORMAT_ARGTYPES_7 class T1, class T2, class T3, class T4, class T5, class T6, class T7
419 #define TINYFORMAT_ARGTYPES_8 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8
420 #define TINYFORMAT_ARGTYPES_9 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9
421 #define TINYFORMAT_ARGTYPES_10 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10
422 #define TINYFORMAT_ARGTYPES_11 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11
423 #define TINYFORMAT_ARGTYPES_12 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12
424 #define TINYFORMAT_ARGTYPES_13 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13
425 #define TINYFORMAT_ARGTYPES_14 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14
426 #define TINYFORMAT_ARGTYPES_15 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15
427 #define TINYFORMAT_ARGTYPES_16 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16
428 
429 #define TINYFORMAT_VARARGS_1 const T1& v1
430 #define TINYFORMAT_VARARGS_2 const T1& v1, const T2& v2
431 #define TINYFORMAT_VARARGS_3 const T1& v1, const T2& v2, const T3& v3
432 #define TINYFORMAT_VARARGS_4 const T1& v1, const T2& v2, const T3& v3, const T4& v4
433 #define TINYFORMAT_VARARGS_5 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5
434 #define TINYFORMAT_VARARGS_6 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6
435 #define TINYFORMAT_VARARGS_7 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7
436 #define TINYFORMAT_VARARGS_8 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8
437 #define TINYFORMAT_VARARGS_9 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
438 #define TINYFORMAT_VARARGS_10 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
439 #define TINYFORMAT_VARARGS_11 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
440 #define TINYFORMAT_VARARGS_12 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
441 #define TINYFORMAT_VARARGS_13 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, const T13& v13
442 #define TINYFORMAT_VARARGS_14 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, const T13& v13, const T14& v14
443 #define TINYFORMAT_VARARGS_15 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, const T13& v13, const T14& v14, const T15& v15
444 #define TINYFORMAT_VARARGS_16 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, const T13& v13, const T14& v14, const T15& v15, const T16& v16
445 
446 #define TINYFORMAT_PASSARGS_1 v1
447 #define TINYFORMAT_PASSARGS_2 v1, v2
448 #define TINYFORMAT_PASSARGS_3 v1, v2, v3
449 #define TINYFORMAT_PASSARGS_4 v1, v2, v3, v4
450 #define TINYFORMAT_PASSARGS_5 v1, v2, v3, v4, v5
451 #define TINYFORMAT_PASSARGS_6 v1, v2, v3, v4, v5, v6
452 #define TINYFORMAT_PASSARGS_7 v1, v2, v3, v4, v5, v6, v7
453 #define TINYFORMAT_PASSARGS_8 v1, v2, v3, v4, v5, v6, v7, v8
454 #define TINYFORMAT_PASSARGS_9 v1, v2, v3, v4, v5, v6, v7, v8, v9
455 #define TINYFORMAT_PASSARGS_10 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10
456 #define TINYFORMAT_PASSARGS_11 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11
457 #define TINYFORMAT_PASSARGS_12 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
458 #define TINYFORMAT_PASSARGS_13 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
459 #define TINYFORMAT_PASSARGS_14 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14
460 #define TINYFORMAT_PASSARGS_15 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
461 #define TINYFORMAT_PASSARGS_16 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16
462 
463 #define TINYFORMAT_PASSARGS_TAIL_1
464 #define TINYFORMAT_PASSARGS_TAIL_2 , v2
465 #define TINYFORMAT_PASSARGS_TAIL_3 , v2, v3
466 #define TINYFORMAT_PASSARGS_TAIL_4 , v2, v3, v4
467 #define TINYFORMAT_PASSARGS_TAIL_5 , v2, v3, v4, v5
468 #define TINYFORMAT_PASSARGS_TAIL_6 , v2, v3, v4, v5, v6
469 #define TINYFORMAT_PASSARGS_TAIL_7 , v2, v3, v4, v5, v6, v7
470 #define TINYFORMAT_PASSARGS_TAIL_8 , v2, v3, v4, v5, v6, v7, v8
471 #define TINYFORMAT_PASSARGS_TAIL_9 , v2, v3, v4, v5, v6, v7, v8, v9
472 #define TINYFORMAT_PASSARGS_TAIL_10 , v2, v3, v4, v5, v6, v7, v8, v9, v10
473 #define TINYFORMAT_PASSARGS_TAIL_11 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11
474 #define TINYFORMAT_PASSARGS_TAIL_12 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
475 #define TINYFORMAT_PASSARGS_TAIL_13 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
476 #define TINYFORMAT_PASSARGS_TAIL_14 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14
477 #define TINYFORMAT_PASSARGS_TAIL_15 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
478 #define TINYFORMAT_PASSARGS_TAIL_16 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16
479 
480 #define TINYFORMAT_FOREACH_ARGNUM(m) \
481  m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) m(10) m(11) m(12) m(13) m(14) m(15) m(16)
482 //[[[end]]]
483 
484 
485 
486 namespace detail {
487 
488 // Type-opaque holder for an argument to format(), with associated actions on
489 // the type held as explicit function pointers. This allows FormatArg's for
490 // each argument to be allocated as a homogenous array inside FormatList
491 // whereas a naive implementation based on inheritance does not.
493 {
494  public:
496  : m_value(NULL),
497  m_formatImpl(NULL),
498  m_toIntImpl(NULL)
499  { }
500 
501  template<typename T>
502  FormatArg(const T& value)
503  : m_value(static_cast<const void*>(&value)),
506  { }
507 
508  void format(std::ostream& out, const char* fmtBegin,
509  const char* fmtEnd, int ntrunc) const
510  {
513  m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value);
514  }
515 
516  int toInt() const
517  {
520  return m_toIntImpl(m_value);
521  }
522 
523  private:
524  template<typename T>
525  TINYFORMAT_HIDDEN static void formatImpl(std::ostream& out, const char* fmtBegin,
526  const char* fmtEnd, int ntrunc, const void* value)
527  {
528  formatValue(out, fmtBegin, fmtEnd, ntrunc, *static_cast<const T*>(value));
529  }
530 
531  template<typename T>
532  TINYFORMAT_HIDDEN static int toIntImpl(const void* value)
533  {
534  return convertToInt<T>::invoke(*static_cast<const T*>(value));
535  }
536 
537  const void* m_value;
538  void (*m_formatImpl)(std::ostream& out, const char* fmtBegin,
539  const char* fmtEnd, int ntrunc, const void* value);
540  int (*m_toIntImpl)(const void* value);
541 };
542 
543 
544 // Parse and return an integer from the string c, as atoi()
545 // On return, c is set to one past the end of the integer.
546 inline int parseIntAndAdvance(const char*& c)
547 {
548  int i = 0;
549  for(;*c >= '0' && *c <= '9'; ++c)
550  i = 10*i + (*c - '0');
551  return i;
552 }
553 
554 // Print literal part of format string and return next format spec
555 // position.
556 //
557 // Skips over any occurrences of '%%', printing a literal '%' to the
558 // output. The position of the first % character of the next
559 // nontrivial format spec is returned, or the end of string.
560 inline const char* printFormatStringLiteral(std::ostream& out, const char* fmt)
561 {
562  const char* c = fmt;
563  for(;; ++c)
564  {
565  switch(*c)
566  {
567  case '\0':
568  out.write(fmt, c - fmt);
569  return c;
570  case '%':
571  out.write(fmt, c - fmt);
572  if(*(c+1) != '%')
573  return c;
574  // for "%%", tack trailing % onto next literal section.
575  fmt = ++c;
576  break;
577  default:
578  break;
579  }
580  }
581 }
582 
583 
584 // Parse a format string and set the stream state accordingly.
585 //
586 // The format mini-language recognized here is meant to be the one from C99,
587 // with the form "%[flags][width][.precision][length]type".
588 //
589 // Formatting options which can't be natively represented using the ostream
590 // state are returned in spacePadPositive (for space padded positive numbers)
591 // and ntrunc (for truncating conversions). argIndex is incremented if
592 // necessary to pull out variable width and precision . The function returns a
593 // pointer to the character after the end of the current format spec.
594 inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositive,
595  int& ntrunc, const char* fmtStart,
596  const detail::FormatArg* formatters,
597  int& argIndex, int numFormatters)
598 {
599  if(*fmtStart != '%')
600  {
601  TINYFORMAT_ERROR("tinyformat: Not enough conversion specifiers in format string");
602  return fmtStart;
603  }
604  // Reset stream state to defaults.
605  out.width(0);
606  out.precision(6);
607  out.fill(' ');
608  // Reset most flags; ignore irrelevant unitbuf & skipws.
609  out.unsetf(std::ios::adjustfield | std::ios::basefield |
610  std::ios::floatfield | std::ios::showbase | std::ios::boolalpha |
611  std::ios::showpoint | std::ios::showpos | std::ios::uppercase);
612  bool precisionSet = false;
613  bool widthSet = false;
614  int widthExtra = 0;
615  const char* c = fmtStart + 1;
616  // 1) Parse flags
617  for(;; ++c)
618  {
619  switch(*c)
620  {
621  case '#':
622  out.setf(std::ios::showpoint | std::ios::showbase);
623  continue;
624  case '0':
625  // overridden by left alignment ('-' flag)
626  if(!(out.flags() & std::ios::left))
627  {
628  // Use internal padding so that numeric values are
629  // formatted correctly, eg -00010 rather than 000-10
630  out.fill('0');
631  out.setf(std::ios::internal, std::ios::adjustfield);
632  }
633  continue;
634  case '-':
635  out.fill(' ');
636  out.setf(std::ios::left, std::ios::adjustfield);
637  continue;
638  case ' ':
639  // overridden by show positive sign, '+' flag.
640  if(!(out.flags() & std::ios::showpos))
641  spacePadPositive = true;
642  continue;
643  case '+':
644  out.setf(std::ios::showpos);
645  spacePadPositive = false;
646  widthExtra = 1;
647  continue;
648  default:
649  break;
650  }
651  break;
652  }
653  // 2) Parse width
654  if(*c >= '0' && *c <= '9')
655  {
656  widthSet = true;
657  out.width(parseIntAndAdvance(c));
658  }
659  if(*c == '*')
660  {
661  widthSet = true;
662  int width = 0;
663  if(argIndex < numFormatters)
664  width = formatters[argIndex++].toInt();
665  else
666  TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable width");
667  if(width < 0)
668  {
669  // negative widths correspond to '-' flag set
670  out.fill(' ');
671  out.setf(std::ios::left, std::ios::adjustfield);
672  width = -width;
673  }
674  out.width(width);
675  ++c;
676  }
677  // 3) Parse precision
678  if(*c == '.')
679  {
680  ++c;
681  int precision = 0;
682  if(*c == '*')
683  {
684  ++c;
685  if(argIndex < numFormatters)
686  precision = formatters[argIndex++].toInt();
687  else
688  TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable precision");
689  }
690  else
691  {
692  if(*c >= '0' && *c <= '9')
693  precision = parseIntAndAdvance(c);
694  else if(*c == '-') // negative precisions ignored, treated as zero.
695  parseIntAndAdvance(++c);
696  }
697  out.precision(precision);
698  precisionSet = true;
699  }
700  // 4) Ignore any C99 length modifier
701  while(*c == 'l' || *c == 'h' || *c == 'L' ||
702  *c == 'j' || *c == 'z' || *c == 't')
703  ++c;
704  // 5) We're up to the conversion specifier character.
705  // Set stream flags based on conversion specifier (thanks to the
706  // boost::format class for forging the way here).
707  bool intConversion = false;
708  switch(*c)
709  {
710  case 'u': case 'd': case 'i':
711  out.setf(std::ios::dec, std::ios::basefield);
712  intConversion = true;
713  break;
714  case 'o':
715  out.setf(std::ios::oct, std::ios::basefield);
716  intConversion = true;
717  break;
718  case 'X':
719  out.setf(std::ios::uppercase);
720  // Falls through
721  case 'x': case 'p':
722  out.setf(std::ios::hex, std::ios::basefield);
723  intConversion = true;
724  break;
725  case 'E':
726  out.setf(std::ios::uppercase);
727  // Falls through
728  case 'e':
729  out.setf(std::ios::scientific, std::ios::floatfield);
730  out.setf(std::ios::dec, std::ios::basefield);
731  break;
732  case 'F':
733  out.setf(std::ios::uppercase);
734  // Falls through
735  case 'f':
736  out.setf(std::ios::fixed, std::ios::floatfield);
737  break;
738  case 'G':
739  out.setf(std::ios::uppercase);
740  // Falls through
741  case 'g':
742  out.setf(std::ios::dec, std::ios::basefield);
743  // As in boost::format, let stream decide float format.
744  out.flags(out.flags() & ~std::ios::floatfield);
745  break;
746  case 'a': case 'A':
747  TINYFORMAT_ERROR("tinyformat: the %a and %A conversion specs "
748  "are not supported");
749  break;
750  case 'c':
751  // Handled as special case inside formatValue()
752  break;
753  case 's':
754  if(precisionSet)
755  ntrunc = static_cast<int>(out.precision());
756  // Make %s print booleans as "true" and "false"
757  out.setf(std::ios::boolalpha);
758  break;
759  case 'n':
760  // Not supported - will cause problems!
761  TINYFORMAT_ERROR("tinyformat: %n conversion spec not supported");
762  break;
763  case '\0':
764  TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly "
765  "terminated by end of string");
766  return c;
767  default:
768  break;
769  }
770  if(intConversion && precisionSet && !widthSet)
771  {
772  // "precision" for integers gives the minimum number of digits (to be
773  // padded with zeros on the left). This isn't really supported by the
774  // iostreams, but we can approximately simulate it with the width if
775  // the width isn't otherwise used.
776  out.width(out.precision() + widthExtra);
777  out.setf(std::ios::internal, std::ios::adjustfield);
778  out.fill('0');
779  }
780  return c+1;
781 }
782 
783 
784 //------------------------------------------------------------------------------
785 inline void formatImpl(std::ostream& out, const char* fmt,
786  const detail::FormatArg* formatters,
787  int numFormatters)
788 {
789  // Saved stream state
790  std::streamsize origWidth = out.width();
791  std::streamsize origPrecision = out.precision();
792  std::ios::fmtflags origFlags = out.flags();
793  char origFill = out.fill();
794 
795  for (int argIndex = 0; argIndex < numFormatters; ++argIndex)
796  {
797  // Parse the format string
798  fmt = printFormatStringLiteral(out, fmt);
799  bool spacePadPositive = false;
800  int ntrunc = -1;
801  const char* fmtEnd = streamStateFromFormat(out, spacePadPositive, ntrunc, fmt,
802  formatters, argIndex, numFormatters);
803  if (argIndex >= numFormatters)
804  {
805  // Check args remain after reading any variable width/precision
806  TINYFORMAT_ERROR("tinyformat: Not enough format arguments");
807  return;
808  }
809  const FormatArg& arg = formatters[argIndex];
810  // Format the arg into the stream.
811  if(!spacePadPositive)
812  arg.format(out, fmt, fmtEnd, ntrunc);
813  else
814  {
815  // The following is a special case with no direct correspondence
816  // between stream formatting and the printf() behaviour. Simulate
817  // it crudely by formatting into a temporary string stream and
818  // munging the resulting string.
819  std::ostringstream tmpStream;
820  tmpStream.copyfmt(out);
821  tmpStream.setf(std::ios::showpos);
822  arg.format(tmpStream, fmt, fmtEnd, ntrunc);
823  std::string result = tmpStream.str(); // allocates... yuck.
824  for(size_t i = 0, iend = result.size(); i < iend; ++i)
825  if(result[i] == '+') result[i] = ' ';
826  out << result;
827  }
828  fmt = fmtEnd;
829  }
830 
831  // Print remaining part of format string.
832  fmt = printFormatStringLiteral(out, fmt);
833  if(*fmt != '\0')
834  TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string");
835 
836  // Restore stream state
837  out.width(origWidth);
838  out.precision(origPrecision);
839  out.flags(origFlags);
840  out.fill(origFill);
841 }
842 
843 } // namespace detail
844 
845 
853 {
854  public:
855  FormatList(detail::FormatArg* formatters, int N)
856  : m_formatters(formatters), m_N(N) { }
857 
858  friend void vformat(std::ostream& out, const char* fmt,
859  const FormatList& list);
860 
861  private:
863  int m_N;
864 };
865 
867 typedef const FormatList& FormatListRef;
868 
869 
870 namespace detail {
871 
872 // Format list subclass with fixed storage to avoid dynamic allocation
873 template<int N>
874 class FormatListN : public FormatList
875 {
876  public:
877 #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
878  template<typename... Args>
879  FormatListN(const Args&... args)
880  : FormatList(&m_formatterStore[0], N),
881  m_formatterStore { FormatArg(args)... }
882  { static_assert(sizeof...(args) == N, "Number of args must be N"); }
883 #else // C++98 version
884  void init(int) {}
885 # define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \
886  \
887  template<TINYFORMAT_ARGTYPES(n)> \
888  FormatListN(TINYFORMAT_VARARGS(n)) \
889  : FormatList(&m_formatterStore[0], n) \
890  { TINYFORMAT_ASSERT(n == N); init(0, TINYFORMAT_PASSARGS(n)); } \
891  \
892  template<TINYFORMAT_ARGTYPES(n)> \
893  void init(int i, TINYFORMAT_VARARGS(n)) \
894  { \
895  m_formatterStore[i] = FormatArg(v1); \
896  init(i+1 TINYFORMAT_PASSARGS_TAIL(n)); \
897  }
898 
900 # undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR
901 #endif
902 
903  private:
905 };
906 
907 // Special 0-arg version - MSVC says zero-sized C array in struct is nonstandard
908 template<> class FormatListN<0> : public FormatList
909 {
910  public: FormatListN() : FormatList(0, 0) {}
911 };
912 
913 } // namespace detail
914 
915 
916 //------------------------------------------------------------------------------
917 // Primary API functions
918 
919 #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
920 
927 template<typename... Args>
928 detail::FormatListN<sizeof...(Args)> makeFormatList(const Args&... args)
929 {
930  return detail::FormatListN<sizeof...(args)>(args...);
931 }
932 
933 #else // C++98 version
934 
936 {
937  return detail::FormatListN<0>();
938 }
939 #define TINYFORMAT_MAKE_MAKEFORMATLIST(n) \
940 template<TINYFORMAT_ARGTYPES(n)> \
941 detail::FormatListN<n> makeFormatList(TINYFORMAT_VARARGS(n)) \
942 { \
943  return detail::FormatListN<n>(TINYFORMAT_PASSARGS(n)); \
944 }
946 #undef TINYFORMAT_MAKE_MAKEFORMATLIST
947 
948 #endif
949 
954 inline void vformat(std::ostream& out, const char* fmt, FormatListRef list)
955 {
956  detail::formatImpl(out, fmt, list.m_formatters, list.m_N);
957 }
958 
959 
960 #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
961 
963 template<typename... Args>
964 void format(std::ostream& out, const char* fmt, const Args&... args)
965 {
966  vformat(out, fmt, makeFormatList(args...));
967 }
968 
971 template<typename... Args>
972 std::string format(const char* fmt, const Args&... args)
973 {
974  std::ostringstream oss;
975  format(oss, fmt, args...);
976  return oss.str();
977 }
978 
980 template<typename... Args>
981 void printf(const char* fmt, const Args&... args)
982 {
983  format(std::cout, fmt, args...);
984 }
985 
986 template<typename... Args>
987 void printfln(const char* fmt, const Args&... args)
988 {
989  format(std::cout, fmt, args...);
990  std::cout << '\n';
991 }
992 
993 
994 #else // C++98 version
995 
996 inline void format(std::ostream& out, const char* fmt)
997 {
998  vformat(out, fmt, makeFormatList());
999 }
1000 
1001 inline std::string format(const char* fmt)
1002 {
1003  std::ostringstream oss;
1004  format(oss, fmt);
1005  return oss.str();
1006 }
1007 
1008 inline void printf(const char* fmt)
1009 {
1010  format(std::cout, fmt);
1011 }
1012 
1013 inline void printfln(const char* fmt)
1014 {
1015  format(std::cout, fmt);
1016  std::cout << '\n';
1017 }
1018 
1019 #define TINYFORMAT_MAKE_FORMAT_FUNCS(n) \
1020  \
1021 template<TINYFORMAT_ARGTYPES(n)> \
1022 void format(std::ostream& out, const char* fmt, TINYFORMAT_VARARGS(n)) \
1023 { \
1024  vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n))); \
1025 } \
1026  \
1027 template<TINYFORMAT_ARGTYPES(n)> \
1028 std::string format(const char* fmt, TINYFORMAT_VARARGS(n)) \
1029 { \
1030  std::ostringstream oss; \
1031  format(oss, fmt, TINYFORMAT_PASSARGS(n)); \
1032  return oss.str(); \
1033 } \
1034  \
1035 template<TINYFORMAT_ARGTYPES(n)> \
1036 void printf(const char* fmt, TINYFORMAT_VARARGS(n)) \
1037 { \
1038  format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \
1039 } \
1040  \
1041 template<TINYFORMAT_ARGTYPES(n)> \
1042 void printfln(const char* fmt, TINYFORMAT_VARARGS(n)) \
1043 { \
1044  format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \
1045  std::cout << '\n'; \
1046 }
1047 
1049 #undef TINYFORMAT_MAKE_FORMAT_FUNCS
1050 
1051 #endif
1052 
1053 
1054 } // namespace tinyformat
1055 
1056 #endif // TINYFORMAT_H_INCLUDED
1057 // #nocov end
friend void vformat(std::ostream &out, const char *fmt, const FormatList &list)
FormatList(detail::FormatArg *formatters, int N)
Definition: tinyformat.h:855
const detail::FormatArg * m_formatters
Definition: tinyformat.h:862
static TINYFORMAT_HIDDEN void formatImpl(std::ostream &out, const char *fmtBegin, const char *fmtEnd, int ntrunc, const void *value)
Definition: tinyformat.h:525
void(* m_formatImpl)(std::ostream &out, const char *fmtBegin, const char *fmtEnd, int ntrunc, const void *value)
Definition: tinyformat.h:538
static TINYFORMAT_HIDDEN int toIntImpl(const void *value)
Definition: tinyformat.h:532
int(* m_toIntImpl)(const void *value)
Definition: tinyformat.h:540
void format(std::ostream &out, const char *fmtBegin, const char *fmtEnd, int ntrunc) const
Definition: tinyformat.h:508
traits::enable_if< helpers::decays_to_ctype< typename std::iterator_traits< InputIterator >::value_type >::value, typename helpers::ctype< typename std::iterator_traits< InputIterator >::value_type >::type >::type min(InputIterator begin, InputIterator end)
Definition: algorithm.h:370
void formatImpl(std::ostream &out, const char *fmt, const detail::FormatArg *formatters, int numFormatters)
Definition: tinyformat.h:785
void formatTruncated(std::ostream &out, const T &value, int ntrunc)
Definition: tinyformat.h:271
int parseIntAndAdvance(const char *&c)
Definition: tinyformat.h:546
const char * streamStateFromFormat(std::ostream &out, bool &spacePadPositive, int &ntrunc, const char *fmtStart, const detail::FormatArg *formatters, int &argIndex, int numFormatters)
Definition: tinyformat.h:594
const char * printFormatStringLiteral(std::ostream &out, const char *fmt)
Definition: tinyformat.h:560
void vformat(std::ostream &out, const char *fmt, FormatListRef list)
Definition: tinyformat.h:954
void formatValue(std::ostream &out, const char *, const char *fmtEnd, int ntrunc, const T &value)
Definition: tinyformat.h:312
void printf(const char *fmt)
Definition: tinyformat.h:1008
void printfln(const char *fmt)
Definition: tinyformat.h:1013
detail::FormatListN< 0 > makeFormatList()
Definition: tinyformat.h:935
const FormatList & FormatListRef
Reference to type-opaque format list for passing to vformat()
Definition: tinyformat.h:867
void format(std::ostream &out, const char *fmt)
Definition: tinyformat.h:996
static int invoke(const T &value)
Definition: tinyformat.h:266
static int invoke(const T &)
Definition: tinyformat.h:255
static void invoke(std::ostream &out, const T &value)
Definition: tinyformat.h:225
static void invoke(std::ostream &, const T &)
Definition: tinyformat.h:218
static succeed tryConvert(const T2 &)
#define TINYFORMAT_HIDDEN
Definition: tinyformat.h:166
#define TINYFORMAT_ERROR(reason)
Definition: tinyformat.h:146
#define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type)
Definition: tinyformat.h:278
#define TINYFORMAT_MAKE_MAKEFORMATLIST(n)
Definition: tinyformat.h:939
#define TINYFORMAT_MAKE_FORMAT_FUNCS(n)
Definition: tinyformat.h:1019
#define TINYFORMAT_ASSERT(cond)
Definition: tinyformat.h:142
#define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n)
Definition: tinyformat.h:885
#define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType)
Definition: tinyformat.h:347
#define TINYFORMAT_FOREACH_ARGNUM(m)
Definition: tinyformat.h:480