tinyformat.h raw

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