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