text: // tinyformat.h
  // Copyright (C) 2011, Chris Foster [chris42f (at) gmail (d0t) com]
  //
  // Boost Software License - Version 1.0
  //
  // Permission is hereby granted, free of charge, to any person or organization
  // obtaining a copy of the software and accompanying documentation covered by
  // this license (the "Software") to use, reproduce, display, distribute,
  // execute, and transmit the Software, and to prepare derivative works of the
  // Software, and to permit third-parties to whom the Software is furnished to
  // do so, all subject to the following:
  //
  // The copyright notices in the Software and this entire statement, including
  // the above license grant, this restriction and the following disclaimer,
  // must be included in all copies of the Software, in whole or in part, and
  // all derivative works of the Software, unless such copies or derivative
  // works are solely in the form of machine-executable object code generated by
  // a source language processor.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
  // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
  // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
  // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  // DEALINGS IN THE SOFTWARE.
  
  //------------------------------------------------------------------------------
  // Tinyformat: A minimal type safe printf replacement
  //
  // tinyformat.h is a type safe printf replacement library in a single C++
  // header file.  Design goals include:
  //
  // * Type safety and extensibility for user defined types.
  // * C99 printf() compatibility, to the extent possible using std::ostream
  // * Simplicity and minimalism.  A single header file to include and distribute
  //   with your projects.
  // * Augment rather than replace the standard stream formatting mechanism
  // * C++98 support, with optional C++11 niceties
  //
  //
  // Main interface example usage
  // ----------------------------
  //
  // To print a date to std::cout:
  //
  //   std::string weekday = "Wednesday";
  //   const char* month = "July";
  //   size_t day = 27;
  //   long hour = 14;
  //   int min = 44;
  //
  //   tfm::printf("%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min);
  //
  // The strange types here emphasize the type safety of the interface; it is
  // possible to print a std::string using the "%s" conversion, and a
  // size_t using the "%d" conversion.  A similar result could be achieved
  // using either of the tfm::format() functions.  One prints on a user provided
  // stream:
  //
  //   tfm::format(std::cerr, "%s, %s %d, %.2d:%.2d\n",
  //               weekday, month, day, hour, min);
  //
  // The other returns a std::string:
  //
  //   std::string date = tfm::format("%s, %s %d, %.2d:%.2d\n",
  //                                  weekday, month, day, hour, min);
  //   std::cout << date;
  //
  // These are the three primary interface functions.  There is also a
  // convenience function printfln() which appends a newline to the usual result
  // of printf() for super simple logging.
  //
  //
  // User defined format functions
  // -----------------------------
  //
  // Simulating variadic templates in C++98 is pretty painful since it requires
  // writing out the same function for each desired number of arguments.  To make
  // this bearable tinyformat comes with a set of macros which are used
  // internally to generate the API, but which may also be used in user code.
  //
  // The three macros TINYFORMAT_ARGTYPES(n), TINYFORMAT_VARARGS(n) and
  // TINYFORMAT_PASSARGS(n) will generate a list of n argument types,
  // type/name pairs and argument names respectively when called with an integer
  // n between 1 and 16.  We can use these to define a macro which generates the
  // desired user defined function with n arguments.  To generate all 16 user
  // defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM.  For an
  // example, see the implementation of printf() at the end of the source file.
  //
  // Sometimes it's useful to be able to pass a list of format arguments through
  // to a non-template function.  The FormatList class is provided as a way to do
  // this by storing the argument list in a type-opaque way.  Continuing the
  // example from above, we construct a FormatList using makeFormatList():
  //
  //   FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour,
  //   min);
  //
  // The format list can now be passed into any non-template function and used
  // via a call to the vformat() function:
  //
  //   tfm::vformat(std::cout, "%s, %s %d, %.2d:%.2d\n", formatList);
  //
  //
  // Additional API information
  // --------------------------
  //
  // Error handling: Define TINYFORMAT_ERROR to customize the error handling for
  // format strings which are unsupported or have the wrong number of format
  // specifiers (calls assert() by default).
  //
  // User defined types: Uses operator<< for user defined types by default.
  // Overload formatValue() for more control.
  
  #ifndef TINYFORMAT_H_INCLUDED
  #define TINYFORMAT_H_INCLUDED
  
  namespace tinyformat {}
  //------------------------------------------------------------------------------
  // Config section.  Customize to your liking!
  
  // Namespace alias to encourage brevity
  namespace tfm = tinyformat;
  
  // Error handling; calls assert() by default.
  #define TINYFORMAT_ERROR(reasonString)                                         \
      throw tinyformat::format_error(reasonString)
  
  // Define for C++11 variadic templates which make the code shorter & more
  // general.  If you don't define this, C++11 support is autodetected below.
  #define TINYFORMAT_USE_VARIADIC_TEMPLATES
  
  //------------------------------------------------------------------------------
  // Implementation details.
  #include <algorithm>
  #include <cassert>
  #include <iostream>
  #include <sstream>
  #include <stdexcept>
  
  #ifndef TINYFORMAT_ERROR
  #define TINYFORMAT_ERROR(reason) assert(0 && reason)
  #endif
  
  #if !defined(TINYFORMAT_USE_VARIADIC_TEMPLATES) &&                             \
      !defined(TINYFORMAT_NO_VARIADIC_TEMPLATES)
  #ifdef __GXX_EXPERIMENTAL_CXX0X__
  #define TINYFORMAT_USE_VARIADIC_TEMPLATES
  #endif
  #endif
  
  #if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201
  //  std::showpos is broken on old libstdc++ as provided with OSX.  See
  //  http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html
  #define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
  #endif
  
  #ifdef __APPLE__
  // Workaround OSX linker warning: Xcode uses different default symbol
  // visibilities for static libs vs executables (see issue #25)
  #define TINYFORMAT_HIDDEN __attribute__((visibility("hidden")))
  #else
  #define TINYFORMAT_HIDDEN
  #endif
  
  namespace tinyformat {
  
  class format_error : public std::runtime_error {
  public:
      format_error(const std::string &what) : std::runtime_error(what) {}
  };
  
  //------------------------------------------------------------------------------
  namespace detail {
  
      // Test whether type T1 is convertible to type T2
      template <typename T1, typename T2> struct is_convertible {
      private:
          // two types of different size
          struct fail {
              char dummy[2];
          };
          struct succeed {
              char dummy;
          };
          // Try to convert a T1 to a T2 by plugging into tryConvert
          static fail tryConvert(...);
          static succeed tryConvert(const T2 &);
          static const T1 &makeT1();
  
      public:
  #ifdef _MSC_VER
  // Disable spurious loss of precision warnings in tryConvert(makeT1())
  #pragma warning(push)
  #pragma warning(disable : 4244)
  #pragma warning(disable : 4267)
  #endif
          // Standard trick: the (...) version of tryConvert will be chosen from
          // the overload set only if the version taking a T2 doesn't match. Then
          // we compare the sizes of the return types to check which function
          // matched.  Very neat, in a disgusting kind of way :)
          static const bool value =
              sizeof(tryConvert(makeT1())) == sizeof(succeed);
  #ifdef _MSC_VER
  #pragma warning(pop)
  #endif
      };
  
      // Detect when a type is not a wchar_t string
      template <typename T> struct is_wchar {
          typedef int tinyformat_wchar_is_not_supported;
      };
      template <> struct is_wchar<wchar_t *> {};
      template <> struct is_wchar<const wchar_t *> {};
      template <int n> struct is_wchar<const wchar_t[n]> {};
      template <int n> struct is_wchar<wchar_t[n]> {};
  
      // Format the value by casting to type fmtT. This default implementation
      // should never be called.
      template <typename T, typename fmtT,
                bool convertible = is_convertible<T, fmtT>::value>
      struct formatValueAsType {
          static void invoke(std::ostream & /*out*/, const T & /*value*/) {
              assert(0);
          }
      };
  
      // Specialized version for types that can actually be converted to fmtT, as
      // indicated by the "convertible" template parameter.
      template <typename T, typename fmtT>
      struct formatValueAsType<T, fmtT, true> {
          static void invoke(std::ostream &out, const T &value) {
              out << static_cast<fmtT>(value);
          }
      };
  
  #ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
      template <typename T, bool convertible = is_convertible<T, int>::value>
      struct formatZeroIntegerWorkaround {
          static bool invoke(std::ostream & /**/, const T & /**/) {
              return false;
          }
      };
      template <typename T> struct formatZeroIntegerWorkaround<T, true> {
          static bool invoke(std::ostream &out, const T &value) {
              if (static_cast<int>(value) == 0 &&
                  out.flags() & std::ios::showpos) {
                  out << "+0";
                  return true;
              }
              return false;
          }
      };
  #endif // TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
  
      // Convert an arbitrary type to integer.  The version with convertible=false
      // throws an error.
      template <typename T, bool convertible = is_convertible<T, int>::value>
      struct convertToInt {
          static int invoke(const T & /*value*/) {
              TINYFORMAT_ERROR("tinyformat: Cannot convert from argument type to "
                               "integer for use as variable width or precision");
              return 0;
          }
      };
      // Specialization for convertToInt when conversion is possible
      template <typename T> struct convertToInt<T, true> {
          static int invoke(const T &value) { return static_cast<int>(value); }
      };
  
      // Format at most ntrunc characters to the given stream.
      template <typename T>
      inline void formatTruncated(std::ostream &out, const T &value, int ntrunc) {
          std::ostringstream tmp;
          tmp << value;
          std::string result = tmp.str();
          out.write(result.c_str(),
                    (std::min)(ntrunc, static_cast<int>(result.size())));
      }
  #define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type)                          \
      inline void formatTruncated(std::ostream &out, type *value, int ntrunc) {  \
          std::streamsize len = 0;                                               \
          while (len < ntrunc && value[len] != 0)                                \
              ++len;                                                             \
          out.write(value, len);                                                 \
      }
      // Overload for const char* and char*. Could overload for signed & unsigned
      // char too, but these are technically unneeded for printf compatibility.
      TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const char)
      TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(char)
  #undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR
  
  } // namespace detail
  
  //------------------------------------------------------------------------------
  // Variable formatting functions.  May be overridden for user-defined types if
  // desired.
  
  /// Format a value into a stream, delegating to operator<< by default.
  ///
  /// Users may override this for their own types.  When this function is called,
  /// the stream flags will have been modified according to the format string.
  /// The format specification is provided in the range [fmtBegin, fmtEnd).  For
  /// truncating conversions, ntrunc is set to the desired maximum number of
  /// characters, for example "%.7s" calls formatValue with ntrunc = 7.
  ///
  /// By default, formatValue() uses the usual stream insertion operator
  /// operator<< to format the type T, with special cases for the %c and %p
  /// conversions.
  template <typename T>
  inline void formatValue(std::ostream &out, const char * /*fmtBegin*/,
                          const char *fmtEnd, int ntrunc, const T &value) {
  #ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS
      // Since we don't support printing of wchar_t using "%ls", make it fail at
      // compile time in preference to printing as a void* at runtime.
      typedef typename detail::is_wchar<T>::tinyformat_wchar_is_not_supported
          DummyType;
      (void)DummyType(); // avoid unused type warning with gcc-4.8
  #endif
      // The mess here is to support the %c and %p conversions: if these
      // conversions are active we try to convert the type to a char or const
      // void* respectively and format that instead of the value itself. For the
      // %p conversion it's important to avoid dereferencing the pointer, which
      // could otherwise lead to a crash when printing a dangling (const char*).
      const bool canConvertToChar = detail::is_convertible<T, char>::value;
      const bool canConvertToVoidPtr =
          detail::is_convertible<T, const void *>::value;
      if (canConvertToChar && *(fmtEnd - 1) == 'c')
          detail::formatValueAsType<T, char>::invoke(out, value);
      else if (canConvertToVoidPtr && *(fmtEnd - 1) == 'p')
          detail::formatValueAsType<T, const void *>::invoke(out, value);
  #ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
      else if (detail::formatZeroIntegerWorkaround<T>::invoke(out, value)) /**/
          ;
  #endif
      else if (ntrunc >= 0) {
          // Take care not to overread C strings in truncating conversions like
          // "%.4s" where at most 4 characters may be read.
          detail::formatTruncated(out, value, ntrunc);
      } else
          out << value;
  }
  
  // Overloaded version for char types to support printing as an integer
  #define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType)                           \
      inline void formatValue(std::ostream &out, const char * /*fmtBegin*/,      \
                              const char *fmtEnd, int /**/, charType value) {    \
          switch (*(fmtEnd - 1)) {                                               \
              case 'u':                                                          \
              case 'd':                                                          \
              case 'i':                                                          \
              case 'o':                                                          \
              case 'X':                                                          \
              case 'x':                                                          \
                  out << static_cast<int>(value);                                \
                  break;                                                         \
              default:                                                           \
                  out << value;                                                  \
                  break;                                                         \
          }                                                                      \
      }
  // per 3.9.1: char, signed char and uint8_t are all distinct types
  TINYFORMAT_DEFINE_FORMATVALUE_CHAR(char)
  TINYFORMAT_DEFINE_FORMATVALUE_CHAR(signed char)
  TINYFORMAT_DEFINE_FORMATVALUE_CHAR(uint8_t)
  #undef TINYFORMAT_DEFINE_FORMATVALUE_CHAR
  
  //------------------------------------------------------------------------------
  // Tools for emulating variadic templates in C++98.  The basic idea here is
  // stolen from the boost preprocessor metaprogramming library and cut down to
  // be just general enough for what we need.
  
  #define TINYFORMAT_ARGTYPES(n) TINYFORMAT_ARGTYPES_##n
  #define TINYFORMAT_VARARGS(n) TINYFORMAT_VARARGS_##n
  #define TINYFORMAT_PASSARGS(n) TINYFORMAT_PASSARGS_##n
  #define TINYFORMAT_PASSARGS_TAIL(n) TINYFORMAT_PASSARGS_TAIL_##n
  
  // To keep it as transparent as possible, the macros below have been generated
  // using python via the excellent cog.py code generation script.  This avoids
  // the need for a bunch of complex (but more general) preprocessor tricks as
  // used in boost.preprocessor.
  //
  // To rerun the code generation in place, use `cog.py -r tinyformat.h`
  // (see http://nedbatchelder.com/code/cog).  Alternatively you can just create
  // extra versions by hand.
  
  /*[[[cog
  maxParams = 16
  
  def makeCommaSepLists(lineTemplate, elemTemplate, startInd=1):
      for j in range(startInd,maxParams+1):
          list = ', '.join([elemTemplate % {'i':i} for i in range(startInd,j+1)])
          cog.outl(lineTemplate % {'j':j, 'list':list})
  
  makeCommaSepLists('#define TINYFORMAT_ARGTYPES_%(j)d %(list)s',
                    'class T%(i)d')
  
  cog.outl()
  makeCommaSepLists('#define TINYFORMAT_VARARGS_%(j)d %(list)s',
                    'const T%(i)d& v%(i)d')
  
  cog.outl()
  makeCommaSepLists('#define TINYFORMAT_PASSARGS_%(j)d %(list)s', 'v%(i)d')
  
  cog.outl()
  cog.outl('#define TINYFORMAT_PASSARGS_TAIL_1')
  makeCommaSepLists('#define TINYFORMAT_PASSARGS_TAIL_%(j)d , %(list)s',
                    'v%(i)d', startInd = 2)
  
  cog.outl()
  cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n    ' +
           ' '.join(['m(%d)' % (j,) for j in range(1,maxParams+1)]))
  ]]]*/
  #define TINYFORMAT_ARGTYPES_1 class T1
  #define TINYFORMAT_ARGTYPES_2 class T1, class T2
  #define TINYFORMAT_ARGTYPES_3 class T1, class T2, class T3
  #define TINYFORMAT_ARGTYPES_4 class T1, class T2, class T3, class T4
  #define TINYFORMAT_ARGTYPES_5 class T1, class T2, class T3, class T4, class T5
  #define TINYFORMAT_ARGTYPES_6                                                  \
      class T1, class T2, class T3, class T4, class T5, class T6
  #define TINYFORMAT_ARGTYPES_7                                                  \
      class T1, class T2, class T3, class T4, class T5, class T6, class T7
  #define TINYFORMAT_ARGTYPES_8                                                  \
      class T1, class T2, class T3, class T4, class T5, class T6, class T7,      \
          class T8
  #define TINYFORMAT_ARGTYPES_9                                                  \
      class T1, class T2, class T3, class T4, class T5, class T6, class T7,      \
          class T8, class T9
  #define TINYFORMAT_ARGTYPES_10                                                 \
      class T1, class T2, class T3, class T4, class T5, class T6, class T7,      \
          class T8, class T9, class T10
  #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
  #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
  #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
  #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
  #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
  #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
  
  #define TINYFORMAT_VARARGS_1 const T1 &v1
  #define TINYFORMAT_VARARGS_2 const T1 &v1, const T2 &v2
  #define TINYFORMAT_VARARGS_3 const T1 &v1, const T2 &v2, const T3 &v3
  #define TINYFORMAT_VARARGS_4                                                   \
      const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4
  #define TINYFORMAT_VARARGS_5                                                   \
      const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5
  #define TINYFORMAT_VARARGS_6                                                   \
      const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5,      \
          const T6 &v6
  #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
  #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
  #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
  #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
  #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
  #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
  #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
  #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
  #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
  #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
  
  #define TINYFORMAT_PASSARGS_1 v1
  #define TINYFORMAT_PASSARGS_2 v1, v2
  #define TINYFORMAT_PASSARGS_3 v1, v2, v3
  #define TINYFORMAT_PASSARGS_4 v1, v2, v3, v4
  #define TINYFORMAT_PASSARGS_5 v1, v2, v3, v4, v5
  #define TINYFORMAT_PASSARGS_6 v1, v2, v3, v4, v5, v6
  #define TINYFORMAT_PASSARGS_7 v1, v2, v3, v4, v5, v6, v7
  #define TINYFORMAT_PASSARGS_8 v1, v2, v3, v4, v5, v6, v7, v8
  #define TINYFORMAT_PASSARGS_9 v1, v2, v3, v4, v5, v6, v7, v8, v9
  #define TINYFORMAT_PASSARGS_10 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10
  #define TINYFORMAT_PASSARGS_11 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11
  #define TINYFORMAT_PASSARGS_12 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
  #define TINYFORMAT_PASSARGS_13                                                 \
      v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
  #define TINYFORMAT_PASSARGS_14                                                 \
      v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14
  #define TINYFORMAT_PASSARGS_15                                                 \
      v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
  #define TINYFORMAT_PASSARGS_16                                                 \
      v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16
  
  #define TINYFORMAT_PASSARGS_TAIL_1
  #define TINYFORMAT_PASSARGS_TAIL_2 , v2
  #define TINYFORMAT_PASSARGS_TAIL_3 , v2, v3
  #define TINYFORMAT_PASSARGS_TAIL_4 , v2, v3, v4
  #define TINYFORMAT_PASSARGS_TAIL_5 , v2, v3, v4, v5
  #define TINYFORMAT_PASSARGS_TAIL_6 , v2, v3, v4, v5, v6
  #define TINYFORMAT_PASSARGS_TAIL_7 , v2, v3, v4, v5, v6, v7
  #define TINYFORMAT_PASSARGS_TAIL_8 , v2, v3, v4, v5, v6, v7, v8
  #define TINYFORMAT_PASSARGS_TAIL_9 , v2, v3, v4, v5, v6, v7, v8, v9
  #define TINYFORMAT_PASSARGS_TAIL_10 , v2, v3, v4, v5, v6, v7, v8, v9, v10
  #define TINYFORMAT_PASSARGS_TAIL_11 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11
  #define TINYFORMAT_PASSARGS_TAIL_12                                            \
      , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
  #define TINYFORMAT_PASSARGS_TAIL_13                                            \
      , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
  #define TINYFORMAT_PASSARGS_TAIL_14                                            \
      , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14
  #define TINYFORMAT_PASSARGS_TAIL_15                                            \
      , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
  #define TINYFORMAT_PASSARGS_TAIL_16                                            \
      , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16
  
  #define TINYFORMAT_FOREACH_ARGNUM(m)                                           \
      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)
  //[[[end]]]
  
  namespace detail {
  
      // Type-opaque holder for an argument to format(), with associated actions
      // on the type held as explicit function pointers. This allows FormatArg's
      // for each argument to be allocated as a homogenous array inside FormatList
      // whereas a naive implementation based on inheritance does not.
      class FormatArg {
      public:
          FormatArg()
              : m_value(nullptr), m_formatImpl(nullptr), m_toIntImpl(nullptr) {}
  
          template <typename T>
          explicit FormatArg(const T &value)
              : m_value(static_cast<const void *>(&value)),
                m_formatImpl(&formatImpl<T>), m_toIntImpl(&toIntImpl<T>) {}
  
          void format(std::ostream &out, const char *fmtBegin, const char *fmtEnd,
                      int ntrunc) const {
              assert(m_value);
              assert(m_formatImpl);
              m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value);
          }
  
          int toInt() const {
              assert(m_value);
              assert(m_toIntImpl);
              return m_toIntImpl(m_value);
          }
  
      private:
          template <typename T>
          TINYFORMAT_HIDDEN static void
          formatImpl(std::ostream &out, const char *fmtBegin, const char *fmtEnd,
                     int ntrunc, const void *value) {
              formatValue(out, fmtBegin, fmtEnd, ntrunc,
                          *static_cast<const T *>(value));
          }
  
          template <typename T>
          TINYFORMAT_HIDDEN static int toIntImpl(const void *value) {
              return convertToInt<T>::invoke(*static_cast<const T *>(value));
          }
  
          const void *m_value;
          void (*m_formatImpl)(std::ostream &out, const char *fmtBegin,
                               const char *fmtEnd, int ntrunc, const void *value);
          int (*m_toIntImpl)(const void *value);
      };
  
      // Parse and return an integer from the string c, as atoi()
      // On return, c is set to one past the end of the integer.
      inline int parseIntAndAdvance(const char *&c) {
          int i = 0;
          for (; *c >= '0' && *c <= '9'; ++c)
              i = 10 * i + (*c - '0');
          return i;
      }
  
      // Print literal part of format string and return next format spec position.
      //
      // Skips over any occurrences of '%%', printing a literal '%' to the output.
      // The position of the first % character of the next nontrivial format spec
      // is returned, or the end of string.
      inline const char *printFormatStringLiteral(std::ostream &out,
                                                  const char *fmt) {
          const char *c = fmt;
          for (;; ++c) {
              switch (*c) {
                  case '\0':
                      out.write(fmt, c - fmt);
                      return c;
                  case '%':
                      out.write(fmt, c - fmt);
                      if (*(c + 1) != '%') return c;
                      // for "%%", tack trailing % onto next literal section.
                      fmt = ++c;
                      break;
                  default:
                      break;
              }
          }
      }
  
      // Parse a format string and set the stream state accordingly.
      //
      // The format mini-language recognized here is meant to be the one from C99,
      // with the form "%[flags][width][.precision][length]type".
      //
      // Formatting options which can't be natively represented using the ostream
      // state are returned in spacePadPositive (for space padded positive
      // numbers) and ntrunc (for truncating conversions). argIndex is incremented
      // if necessary to pull out variable width and precision. The function
      // returns a pointer to the character after the end of the current format
      // spec.
      inline const char *
      streamStateFromFormat(std::ostream &out, bool &spacePadPositive,
                            int &ntrunc, const char *fmtStart,
                            const detail::FormatArg *formatters, int &argIndex,
                            int numFormatters) {
          if (*fmtStart != '%') {
              TINYFORMAT_ERROR("tinyformat: Not enough conversion specifiers in "
                               "format string");
              return fmtStart;
          }
          // Reset stream state to defaults.
          out.width(0);
          out.precision(6);
          out.fill(' ');
          // Reset most flags; ignore irrelevant unitbuf & skipws.
          out.unsetf(std::ios::adjustfield | std::ios::basefield |
                     std::ios::floatfield | std::ios::showbase |
                     std::ios::boolalpha | std::ios::showpoint |
                     std::ios::showpos | std::ios::uppercase);
          bool precisionSet = false;
          bool widthSet = false;
          int widthExtra = 0;
          const char *c = fmtStart + 1;
          // 1) Parse flags
          for (;; ++c) {
              switch (*c) {
                  case '#':
                      out.setf(std::ios::showpoint | std::ios::showbase);
                      continue;
                  case '0':
                      // overridden by left alignment ('-' flag)
                      if (!(out.flags() & std::ios::left)) {
                          // Use internal padding so that numeric values are
                          // formatted correctly, eg -00010 rather than 000-10
                          out.fill('0');
                          out.setf(std::ios::internal, std::ios::adjustfield);
                      }
                      continue;
                  case '-':
                      out.fill(' ');
                      out.setf(std::ios::left, std::ios::adjustfield);
                      continue;
                  case ' ':
                      // overridden by show positive sign, '+' flag.
                      if (!(out.flags() & std::ios::showpos))
                          spacePadPositive = true;
                      continue;
                  case '+':
                      out.setf(std::ios::showpos);
                      spacePadPositive = false;
                      widthExtra = 1;
                      continue;
                  default:
                      break;
              }
              break;
          }
          // 2) Parse width
          if (*c >= '0' && *c <= '9') {
              widthSet = true;
              out.width(parseIntAndAdvance(c));
          }
          if (*c == '*') {
              widthSet = true;
              int width = 0;
              if (argIndex < numFormatters)
                  width = formatters[argIndex++].toInt();
              else
                  TINYFORMAT_ERROR(
                      "tinyformat: Not enough arguments to read variable width");
              if (width < 0) {
                  // negative widths correspond to '-' flag set
                  out.fill(' ');
                  out.setf(std::ios::left, std::ios::adjustfield);
                  width = -width;
              }
              out.width(width);
              ++c;
          }
          // 3) Parse precision
          if (*c == '.') {
              ++c;
              int precision = 0;
              if (*c == '*') {
                  ++c;
                  if (argIndex < numFormatters)
                      precision = formatters[argIndex++].toInt();
                  else
                      TINYFORMAT_ERROR("tinyformat: Not enough arguments to read "
                                       "variable precision");
              } else {
                  if (*c >= '0' && *c <= '9') {
                      precision = parseIntAndAdvance(c);
                  } else if (*c == '-') {
                      // negative precisions ignored, treated as zero.
                      parseIntAndAdvance(++c);
                  }
              }
              out.precision(precision);
              precisionSet = true;
          }
          // 4) Ignore any C99 length modifier
          while (*c == 'l' || *c == 'h' || *c == 'L' || *c == 'j' || *c == 'z' ||
                 *c == 't')
              ++c;
          // 5) We're up to the conversion specifier character.
          // Set stream flags based on conversion specifier (thanks to the
          // boost::format class for forging the way here).
          bool intConversion = false;
          switch (*c) {
              case 'u':
              case 'd':
              case 'i':
                  out.setf(std::ios::dec, std::ios::basefield);
                  intConversion = true;
                  break;
              case 'o':
                  out.setf(std::ios::oct, std::ios::basefield);
                  intConversion = true;
                  break;
              case 'X':
                  out.setf(std::ios::uppercase);
              // FALLTHROUGH
              case 'x':
              case 'p':
                  out.setf(std::ios::hex, std::ios::basefield);
                  intConversion = true;
                  break;
              case 'E':
                  out.setf(std::ios::uppercase);
              // FALLTHROUGH
              case 'e':
                  out.setf(std::ios::scientific, std::ios::floatfield);
                  out.setf(std::ios::dec, std::ios::basefield);
                  break;
              case 'F':
                  out.setf(std::ios::uppercase);
              // FALLTHROUGH
              case 'f':
                  out.setf(std::ios::fixed, std::ios::floatfield);
                  break;
              case 'G':
                  out.setf(std::ios::uppercase);
              // FALLTHROUGH
              case 'g':
                  out.setf(std::ios::dec, std::ios::basefield);
                  // As in boost::format, let stream decide float format.
                  out.flags(out.flags() & ~std::ios::floatfield);
                  break;
              case 'a':
              case 'A':
                  TINYFORMAT_ERROR("tinyformat: the %a and %A conversion specs "
                                   "are not supported");
                  break;
              case 'c':
                  // Handled as special case inside formatValue()
                  break;
              case 's':
                  if (precisionSet) ntrunc = static_cast<int>(out.precision());
                  // Make %s print booleans as "true" and "false"
                  out.setf(std::ios::boolalpha);
                  break;
              case 'n':
                  // Not supported - will cause problems!
                  TINYFORMAT_ERROR(
                      "tinyformat: %n conversion spec not supported");
                  break;
              case '\0':
                  TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly "
                                   "terminated by end of string");
                  return c;
              default:
                  break;
          }
          if (intConversion && precisionSet && !widthSet) {
              // "precision" for integers gives the minimum number of digits (to
              // be padded with zeros on the left). This isn't really supported by
              // the iostreams, but we can approximately simulate it with the
              // width if the width isn't otherwise used.
              out.width(out.precision() + widthExtra);
              out.setf(std::ios::internal, std::ios::adjustfield);
              out.fill('0');
          }
          return c + 1;
      }
  
      //------------------------------------------------------------------------------
      inline void formatImpl(std::ostream &out, const char *fmt,
                             const detail::FormatArg *formatters,
                             int numFormatters) {
          // Saved stream state
          std::streamsize origWidth = out.width();
          std::streamsize origPrecision = out.precision();
          std::ios::fmtflags origFlags = out.flags();
          char origFill = out.fill();
  
          for (int argIndex = 0; argIndex < numFormatters; ++argIndex) {
              // Parse the format string
              fmt = printFormatStringLiteral(out, fmt);
              bool spacePadPositive = false;
              int ntrunc = -1;
              const char *fmtEnd =
                  streamStateFromFormat(out, spacePadPositive, ntrunc, fmt,
                                        formatters, argIndex, numFormatters);
              if (argIndex >= numFormatters) {
                  // Check args remain after reading any variable width/precision
                  TINYFORMAT_ERROR("tinyformat: Not enough format arguments");
                  return;
              }
              const FormatArg &arg = formatters[argIndex];
              // Format the arg into the stream.
              if (!spacePadPositive)
                  arg.format(out, fmt, fmtEnd, ntrunc);
              else {
                  // The following is a special case with no direct correspondence
                  // between stream formatting and the printf() behaviour.
                  // Simulate it crudely by formatting into a temporary string
                  // stream and munging the resulting string.
                  std::ostringstream tmpStream;
                  tmpStream.copyfmt(out);
                  tmpStream.setf(std::ios::showpos);
                  arg.format(tmpStream, fmt, fmtEnd, ntrunc);
                  // allocates... yuck.
                  std::string result = tmpStream.str();
                  for (size_t i = 0, iend = result.size(); i < iend; ++i)
                      if (result[i] == '+') result[i] = ' ';
                  out << result;
              }
              fmt = fmtEnd;
          }
  
          // Print remaining part of format string.
          fmt = printFormatStringLiteral(out, fmt);
          if (*fmt != '\0')
              TINYFORMAT_ERROR(
                  "tinyformat: Too many conversion specifiers in format string");
  
          // Restore stream state
          out.width(origWidth);
          out.precision(origPrecision);
          out.flags(origFlags);
          out.fill(origFill);
      }
  
  } // namespace detail
  
  /// List of template arguments format(), held in a type-opaque way.
  ///
  /// A const reference to FormatList (typedef'd as FormatListRef) may be
  /// conveniently used to pass arguments to non-template functions: All type
  /// information has been stripped from the arguments, leaving just enough of a
  /// common interface to perform formatting as required.
  class FormatList {
  public:
      FormatList(detail::FormatArg *formatters, int N)
          : m_formatters(formatters), m_N(N) {}
  
      friend void vformat(std::ostream &out, const char *fmt,
                          const FormatList &list);
  
  private:
      const detail::FormatArg *m_formatters;
      int m_N;
  };
  
  /// Reference to type-opaque format list for passing to vformat()
  typedef const FormatList &FormatListRef;
  
  namespace detail {
  
      // Format list subclass with fixed storage to avoid dynamic allocation
      template <int N> class FormatListN : public FormatList {
      public:
  #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
          template <typename... Args>
          explicit FormatListN(const Args &... args)
              : FormatList(&m_formatterStore[0], N), m_formatterStore{
                                                         FormatArg(args)...} {
              static_assert(sizeof...(args) == N, "Number of args must be N");
          }
  #else // C++98 version
          void init(int) {}
  #define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n)                              \
                                                                                 \
      template <TINYFORMAT_ARGTYPES(n)>                                          \
      explicit FormatListN(TINYFORMAT_VARARGS(n))                                \
          : FormatList(&m_formatterStore[0], n) {                                \
          assert(n == N);                                                        \
          init(0, TINYFORMAT_PASSARGS(n));                                       \
      }                                                                          \
                                                                                 \
      template <TINYFORMAT_ARGTYPES(n)>                                          \
      void init(int i, TINYFORMAT_VARARGS(n)) {                                  \
          m_formatterStore[i] = FormatArg(v1);                                   \
          init(i + 1 TINYFORMAT_PASSARGS_TAIL(n));                               \
      }
  
          TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR)
  #undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR
  #endif
  
      private:
          FormatArg m_formatterStore[N];
      };
  
      // Special 0-arg version - MSVC says zero-sized C array in struct is
      // nonstandard.
      template <> class FormatListN<0> : public FormatList {
      public:
          FormatListN() : FormatList(0, 0) {}
      };
  
  } // namespace detail
  
  //------------------------------------------------------------------------------
  // Primary API functions
  
  #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
  
  /// Make type-agnostic format list from list of template arguments.
  ///
  /// The exact return type of this function is an implementation detail and
  /// shouldn't be relied upon.  Instead it should be stored as a FormatListRef:
  ///
  ///   FormatListRef formatList = makeFormatList( /*...*/ );
  template <typename... Args>
  detail::FormatListN<sizeof...(Args)> makeFormatList(const Args &... args) {
      return detail::FormatListN<sizeof...(args)>(args...);
  }
  
  #else // C++98 version
  
  inline detail::FormatListN<0> makeFormatList() {
      return detail::FormatListN<0>();
  }
  #define TINYFORMAT_MAKE_MAKEFORMATLIST(n)                                      \
      template <TINYFORMAT_ARGTYPES(n)>                                          \
      detail::FormatListN<n> makeFormatList(TINYFORMAT_VARARGS(n)) {             \
          return detail::FormatListN<n>(TINYFORMAT_PASSARGS(n));                 \
      }
  TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_MAKEFORMATLIST)
  #undef TINYFORMAT_MAKE_MAKEFORMATLIST
  
  #endif
  
  /// Format list of arguments to the stream according to the given format string.
  ///
  /// The name vformat() is chosen for the semantic similarity to vprintf(): the
  /// list of format arguments is held in a single function argument.
  inline void vformat(std::ostream &out, const char *fmt, FormatListRef list) {
      detail::formatImpl(out, fmt, list.m_formatters, list.m_N);
  }
  
  #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
  
  /// Format list of arguments to the stream according to given format string.
  template <typename... Args>
  void format(std::ostream &out, const char *fmt, const Args &... args) {
      vformat(out, fmt, makeFormatList(args...));
  }
  
  /// Format list of arguments according to the given format string and return the
  /// result as a string.
  template <typename... Args>
  std::string format(const char *fmt, const Args &... args) {
      std::ostringstream oss;
      format(oss, fmt, args...);
      return oss.str();
  }
  
  /// Format list of arguments to std::cout, according to the given format string
  template <typename... Args> void printf(const char *fmt, const Args &... args) {
      format(std::cout, fmt, args...);
  }
  
  template <typename... Args>
  void printfln(const char *fmt, const Args &... args) {
      format(std::cout, fmt, args...);
      std::cout << '\n';
  }
  
  #else // C++98 version
  
  inline void format(std::ostream &out, const char *fmt) {
      vformat(out, fmt, makeFormatList());
  }
  
  inline std::string format(const char *fmt) {
      std::ostringstream oss;
      format(oss, fmt);
      return oss.str();
  }
  
  inline void printf(const char *fmt) {
      format(std::cout, fmt);
  }
  
  inline void printfln(const char *fmt) {
      format(std::cout, fmt);
      std::cout << '\n';
  }
  
  #define TINYFORMAT_MAKE_FORMAT_FUNCS(n)                                        \
                                                                                 \
      template <TINYFORMAT_ARGTYPES(n)>                                          \
      void format(std::ostream &out, const char *fmt, TINYFORMAT_VARARGS(n)) {   \
          vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n)));             \
      }                                                                          \
                                                                                 \
      template <TINYFORMAT_ARGTYPES(n)>                                          \
      std::string format(const char *fmt, TINYFORMAT_VARARGS(n)) {               \
          std::ostringstream oss;                                                \
          format(oss, fmt, TINYFORMAT_PASSARGS(n));                              \
          return oss.str();                                                      \
      }                                                                          \
                                                                                 \
      template <TINYFORMAT_ARGTYPES(n)>                                          \
      void printf(const char *fmt, TINYFORMAT_VARARGS(n)) {                      \
          format(std::cout, fmt, TINYFORMAT_PASSARGS(n));                        \
      }                                                                          \
                                                                                 \
      template <TINYFORMAT_ARGTYPES(n)>                                          \
      void printfln(const char *fmt, TINYFORMAT_VARARGS(n)) {                    \
          format(std::cout, fmt, TINYFORMAT_PASSARGS(n));                        \
          std::cout << '\n';                                                     \
      }
  
  TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS)
  #undef TINYFORMAT_MAKE_FORMAT_FUNCS
  
  #endif
  
  // Added for Bitcoin Core
  template <typename... Args>
  std::string format(const std::string &fmt, const Args &... args) {
      std::ostringstream oss;
      format(oss, fmt.c_str(), args...);
      return oss.str();
  }
  
  } // namespace tinyformat
  
  #define strprintf tfm::format
  
  #endif // TINYFORMAT_H_INCLUDED
  