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