]> Git Repo - VerusCoin.git/blobdiff - src/tinyformat.h
test
[VerusCoin.git] / src / tinyformat.h
index 04b51f0adcd4ec82d9dda535f4bda14602340214..e0b5bde76c187399544c11b87ca48efe9dae684e 100644 (file)
@@ -67,7 +67,9 @@
 //                                  weekday, month, day, hour, min);
 //   std::cout << date;
 //
-// These are the three primary interface functions.
+// 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
 // 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
 // --------------------------
@@ -109,7 +123,7 @@ namespace tinyformat {}
 namespace tfm = tinyformat;
 
 // Error handling; calls assert() by default.
-// #define TINYFORMAT_ERROR(reasonString) your_error_handler(reasonString)
+#define TINYFORMAT_ERROR(reasonString) throw std::runtime_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.
@@ -118,9 +132,11 @@ namespace tfm = tinyformat;
 
 //------------------------------------------------------------------------------
 // Implementation details.
+#include <algorithm>
 #include <cassert>
 #include <iostream>
 #include <sstream>
+#include <stdexcept>
 
 #ifndef TINYFORMAT_ERROR
 #   define TINYFORMAT_ERROR(reason) assert(0 && reason)
@@ -132,20 +148,20 @@ namespace tfm = tinyformat;
 #   endif
 #endif
 
-#ifdef __GNUC__
-#   define TINYFORMAT_NOINLINE __attribute__((noinline))
-#elif defined(_MSC_VER)
-#   define TINYFORMAT_NOINLINE __declspec(noinline)
-#else
-#   define TINYFORMAT_NOINLINE
-#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 {
 
 //------------------------------------------------------------------------------
@@ -246,6 +262,29 @@ 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
 
 
@@ -254,18 +293,20 @@ struct convertToInt<T,true>
 // desired.
 
 
-// Format a value into a stream. Called from format() for all types 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).
-//
-// By default, formatValue() uses the usual stream insertion operator
-// operator<< to format the type T, with special cases for the %c and %p
-// conversions.
+/// 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, const T& value)
+                        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
@@ -287,6 +328,12 @@ inline void formatValue(std::ostream& out, const char* /*fmtBegin*/,
 #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;
 }
@@ -295,7 +342,7 @@ inline void formatValue(std::ostream& out, const char* /*fmtBegin*/,
 // 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, charType value)           \
+                        const char* fmtEnd, int /**/, charType value) \
 {                                                                     \
     switch(*(fmtEnd-1))                                               \
     {                                                                 \
@@ -434,225 +481,98 @@ cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n    ' +
 
 namespace detail {
 
-// Class holding current position in format string and an output stream into
-// which arguments are formatted.
-class FormatIterator
+// 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:
-        // Flags for features not representable with standard stream state
-        enum ExtraFormatFlags
-        {
-            Flag_None                = 0,
-            Flag_TruncateToPrecision = 1<<0, // truncate length to stream precision()
-            Flag_SpacePadPositive    = 1<<1, // pad positive values with spaces
-            Flag_VariableWidth       = 1<<2, // variable field width in arg list
-            Flag_VariablePrecision   = 1<<3  // variable field precision in arg list
-        };
-
-        // out is the output stream, fmt is the full format string
-        FormatIterator(std::ostream& out, const char* fmt)
-            : m_out(out),
-            m_fmt(fmt),
-            m_extraFlags(Flag_None),
-            m_wantWidth(false),
-            m_wantPrecision(false),
-            m_variableWidth(0),
-            m_variablePrecision(0),
-            m_origWidth(out.width()),
-            m_origPrecision(out.precision()),
-            m_origFlags(out.flags()),
-            m_origFill(out.fill())
+        FormatArg() {}
+
+        template<typename T>
+        FormatArg(const T& value)
+            : m_value(static_cast<const void*>(&value)),
+            m_formatImpl(&formatImpl<T>),
+            m_toIntImpl(&toIntImpl<T>)
         { }
 
-        // Print remaining part of format string.
-        void finish()
+        void format(std::ostream& out, const char* fmtBegin,
+                    const char* fmtEnd, int ntrunc) const
         {
+/*<<<<<<< HEAD
             // It would be nice if we could do this from the destructor, but we
-            // can't if TINFORMAT_ERROR is used to throw an exception!
+            // can't if TINYFORMAT_ERROR is used to throw an exception!
             m_fmt = printFormatStringLiteral(m_out, m_fmt);
             if(*m_fmt != '\0')
                 TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string");
+=======*/
+            m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value);
         }
 
-        ~FormatIterator()
+        int toInt() const
         {
-            // Restore stream state
-            m_out.width(m_origWidth);
-            m_out.precision(m_origPrecision);
-            m_out.flags(m_origFlags);
-            m_out.fill(m_origFill);
+            return m_toIntImpl(m_value);
         }
 
-        template<typename T>
-        void accept(const T& value);
-
     private:
-        // Parse and return an integer from the string c, as atoi()
-        // On return, c is set to one past the end of the integer.
-        static int parseIntAndAdvance(const char*& c)
+        template<typename T>
+        TINYFORMAT_HIDDEN static void formatImpl(std::ostream& out, const char* fmtBegin,
+                        const char* fmtEnd, int ntrunc, const void* value)
         {
-            int i = 0;
-            for(;*c >= '0' && *c <= '9'; ++c)
-                i = 10*i + (*c - '0');
-            return i;
+            formatValue(out, fmtBegin, fmtEnd, ntrunc, *static_cast<const T*>(value));
         }
 
-        // Format at most truncLen characters of a C string to the given
-        // stream.  Return true if formatting proceeded (generic version always
-        // returns false)
         template<typename T>
-        static bool formatCStringTruncate(std::ostream& /*out*/, const T& /*value*/,
-                                        std::streamsize /*truncLen*/)
+        TINYFORMAT_HIDDEN static int toIntImpl(const void* value)
         {
-            return false;
-        }
-#       define TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(type)            \
-        static bool formatCStringTruncate(std::ostream& out, type* value,  \
-                                        std::streamsize truncLen)          \
-        {                                                                  \
-            std::streamsize len = 0;                                       \
-            while(len < truncLen && value[len] != 0)                       \
-                ++len;                                                     \
-            out.write(value, len);                                         \
-            return true;                                                   \
-        }
-        // Overload for const char* and char*.  Could overload for signed &
-        // unsigned char too, but these are technically unneeded for printf
-        // compatibility.
-        TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(const char)
-        TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(char)
-#       undef TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE
-
-        // 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.
-        static const char* printFormatStringLiteral(std::ostream& out,
-                                                    const char* fmt)
-        {
-            const char* c = fmt;
-            for(; true; ++c)
-            {
-                switch(*c)
-                {
-                    case '\0':
-                        out.write(fmt, static_cast<std::streamsize>(c - fmt));
-                        return c;
-                    case '%':
-                        out.write(fmt, static_cast<std::streamsize>(c - fmt));
-                        if(*(c+1) != '%')
-                            return c;
-                        // for "%%", tack trailing % onto next literal section.
-                        fmt = ++c;
-                        break;
-                }
-            }
+            return convertToInt<T>::invoke(*static_cast<const T*>(value));
         }
 
-        static const char* streamStateFromFormat(std::ostream& out,
-                                                 unsigned int& extraFlags,
-                                                 const char* fmtStart,
-                                                 int variableWidth,
-                                                 int variablePrecision);
-
-        // Private copy & assign: Kill gcc warnings with -Weffc++
-        FormatIterator(const FormatIterator&);
-        FormatIterator& operator=(const FormatIterator&);
-
-        // Stream, current format string & state
-        std::ostream& m_out;
-        const char* m_fmt;
-        unsigned int m_extraFlags;
-        // State machine info for handling of variable width & precision
-        bool m_wantWidth;
-        bool m_wantPrecision;
-        int m_variableWidth;
-        int m_variablePrecision;
-        // Saved stream state
-        std::streamsize m_origWidth;
-        std::streamsize m_origPrecision;
-        std::ios::fmtflags m_origFlags;
-        char m_origFill;
+        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);
 };
 
 
-// Accept a value for formatting into the internal stream.
-template<typename T>
-TINYFORMAT_NOINLINE  // < greatly reduces bloat in optimized builds
-void FormatIterator::accept(const T& 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)
 {
-    // Parse the format string
-    const char* fmtEnd = 0;
-    if(m_extraFlags == Flag_None && !m_wantWidth && !m_wantPrecision)
-    {
-        m_fmt = printFormatStringLiteral(m_out, m_fmt);
-        fmtEnd = streamStateFromFormat(m_out, m_extraFlags, m_fmt, 0, 0);
-        m_wantWidth     = (m_extraFlags & Flag_VariableWidth) != 0;
-        m_wantPrecision = (m_extraFlags & Flag_VariablePrecision) != 0;
-    }
-    // Consume value as variable width and precision specifier if necessary
-    if(m_extraFlags & (Flag_VariableWidth | Flag_VariablePrecision))
-    {
-        if(m_wantWidth || m_wantPrecision)
-        {
-            int v = convertToInt<T>::invoke(value);
-            if(m_wantWidth)
-            {
-                m_variableWidth = v;
-                m_wantWidth = false;
-            }
-            else if(m_wantPrecision)
-            {
-                m_variablePrecision = v;
-                m_wantPrecision = false;
-            }
-            return;
-        }
-        // If we get here, we've set both the variable precision and width as
-        // required and we need to rerun the stream state setup to insert these.
-        fmtEnd = streamStateFromFormat(m_out, m_extraFlags, m_fmt,
-                                       m_variableWidth, m_variablePrecision);
-    }
+    int i = 0;
+    for(;*c >= '0' && *c <= '9'; ++c)
+        i = 10*i + (*c - '0');
+    return i;
+}
 
-    // Format the value into the stream.
-    if(!(m_extraFlags & (Flag_SpacePadPositive | Flag_TruncateToPrecision)))
-        formatValue(m_out, m_fmt, fmtEnd, value);
-    else
+// 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)
     {
-        // The following are special cases where there's no direct
-        // correspondence between stream formatting and the printf() behaviour.
-        // Instead, we simulate the behaviour crudely by formatting into a
-        // temporary string stream and munging the resulting string.
-        std::ostringstream tmpStream;
-        tmpStream.copyfmt(m_out);
-        if(m_extraFlags & Flag_SpacePadPositive)
-            tmpStream.setf(std::ios::showpos);
-        // formatCStringTruncate is required for truncating conversions like
-        // "%.4s" where at most 4 characters of the c-string should be read.
-        // If we didn't include this special case, we might read off the end.
-        if(!( (m_extraFlags & Flag_TruncateToPrecision) &&
-             formatCStringTruncate(tmpStream, value, m_out.precision()) ))
-        {
-            // Not a truncated c-string; just format normally.
-            formatValue(tmpStream, m_fmt, fmtEnd, value);
-        }
-        std::string result = tmpStream.str(); // allocates... yuck.
-        if(m_extraFlags & Flag_SpacePadPositive)
+        switch(*c)
         {
-            for(size_t i = 0, iend = result.size(); i < iend; ++i)
-                if(result[i] == '+')
-                    result[i] = ' ';
+            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;
         }
-        if((m_extraFlags & Flag_TruncateToPrecision) &&
-           (int)result.size() > (int)m_out.precision())
-            m_out.write(result.c_str(), m_out.precision());
-        else
-            m_out << result;
     }
-    m_extraFlags = Flag_None;
-    m_fmt = fmtEnd;
 }
 
 
@@ -662,13 +582,14 @@ void FormatIterator::accept(const T& value)
 // with the form "%[flags][width][.precision][length]type".
 //
 // Formatting options which can't be natively represented using the ostream
-// state are returned in the extraFlags parameter which is a bitwise
-// combination of values from the ExtraFormatFlags enum.
-inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
-                                                         unsigned int& extraFlags,
-                                                         const char* fmtStart,
-                                                         int variableWidth,
-                                                         int variablePrecision)
+// 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 != '%')
     {
@@ -683,9 +604,9 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
     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);
-    extraFlags = Flag_None;
     bool precisionSet = false;
     bool widthSet = false;
+    int widthExtra = 0;
     const char* c = fmtStart + 1;
     // 1) Parse flags
     for(;; ++c)
@@ -712,12 +633,15 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
             case ' ':
                 // overridden by show positive sign, '+' flag.
                 if(!(out.flags() & std::ios::showpos))
-                    extraFlags |= Flag_SpacePadPositive;
+                    spacePadPositive = true;
                 continue;
             case '+':
                 out.setf(std::ios::showpos);
-                extraFlags &= ~Flag_SpacePadPositive;
+                spacePadPositive = false;
+                widthExtra = 1;
                 continue;
+            default:
+                break;
         }
         break;
     }
@@ -730,15 +654,19 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
     if(*c == '*')
     {
         widthSet = true;
-        if(variableWidth < 0)
+        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);
-            variableWidth = -variableWidth;
+            width = -width;
         }
-        out.width(variableWidth);
-        extraFlags |= Flag_VariableWidth;
+        out.width(width);
         ++c;
     }
     // 3) Parse precision
@@ -749,8 +677,10 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
         if(*c == '*')
         {
             ++c;
-            extraFlags |= Flag_VariablePrecision;
-            precision = variablePrecision;
+            if(argIndex < numFormatters)
+                precision = formatters[argIndex++].toInt();
+            else
+                TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable precision");
         }
         else
         {
@@ -813,7 +743,7 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
             break;
         case 's':
             if(precisionSet)
-                extraFlags |= Flag_TruncateToPrecision;
+                ntrunc = static_cast<int>(out.precision());
             // Make %s print booleans as "true" and "false"
             out.setf(std::ios::boolalpha);
             break;
@@ -825,6 +755,8 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
             TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly "
                              "terminated by end of string");
             return c;
+        default:
+            break;
     }
     if(intConversion && precisionSet && !widthSet)
     {
@@ -832,7 +764,7 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
         // 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());
+        out.width(out.precision() + widthExtra);
         out.setf(std::ios::internal, std::ios::adjustfield);
         out.fill('0');
     }
@@ -840,171 +772,285 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
 }
 
 
-
 //------------------------------------------------------------------------------
-// Private format function on top of which the public interface is implemented.
-// We enforce a mimimum of one value to be formatted to prevent bugs looking like
-//
-//   const char* myStr = "100% broken";
-//   printf(myStr);   // Parses % as a format specifier
-#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
-
-template<typename T1>
-void format(FormatIterator& fmtIter, const T1& value1)
+inline void formatImpl(std::ostream& out, const char* fmt,
+                       const detail::FormatArg* formatters,
+                       int numFormatters)
 {
-    fmtIter.accept(value1);
-    fmtIter.finish();
+    // 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);
+            std::string result = tmpStream.str(); // allocates... yuck.
+            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' && 0 ) // disabled due to complaints
+        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);
 }
 
-// General version for C++11
-template<typename T1, typename... Args>
-void format(FormatIterator& fmtIter, const T1& value1, const Args&... args)
+} // 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
 {
-    fmtIter.accept(value1);
-    format(fmtIter, args...);
-}
+    public:
+        FormatList(detail::FormatArg* formatters, int N)
+            : m_formatters(formatters), m_N(N) { }
 
-#else
+        friend void vformat(std::ostream& out, const char* fmt,
+                            const FormatList& list);
+
+    private:
+        const detail::FormatArg* m_formatters;
+        int m_N;
+};
 
-inline void format(FormatIterator& fmtIter)
+/// 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
 {
-    fmtIter.finish();
-}
+    public:
+#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
+        template<typename... Args>
+        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)>                       \
+        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));             \
+        }
 
-// General version for C++98
-#define TINYFORMAT_MAKE_FORMAT_DETAIL(n)                                  \
-template<TINYFORMAT_ARGTYPES(n)>                                          \
-void format(detail::FormatIterator& fmtIter, TINYFORMAT_VARARGS(n))       \
-{                                                                         \
-    fmtIter.accept(v1);                                                   \
-    format(fmtIter TINYFORMAT_PASSARGS_TAIL(n));                          \
-}
+        TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR)
+#       undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR
+#endif
 
-TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_DETAIL)
-#undef TINYFORMAT_MAKE_FORMAT_DETAIL
+    private:
+        FormatArg m_formatterStore[N];
+};
 
-#endif // End C++98 variadic template emulation for format()
+// 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
 
 
 //------------------------------------------------------------------------------
-// Implement all the main interface functions here in terms of detail::format()
+// Primary API functions
 
 #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
 
-// C++11 - the simple case
-template<typename T1, typename... Args>
-void format(std::ostream& out, const char* fmt, const T1& v1, const Args&... args)
+/// 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)
 {
-    detail::FormatIterator fmtIter(out, fmt);
-    format(fmtIter, v1, args...);
+    return detail::FormatListN<sizeof...(args)>(args...);
 }
 
-template<typename T1, typename... Args>
-std::string format(const char* fmt, const T1& v1, const 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, v1, args...);
+    format(oss, fmt, args...);
     return oss.str();
 }
 
-template<typename T1, typename... Args>
-std::string format(const std::string &fmt, const T1& v1, const Args&... args)
+/// 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.c_str(), v1, args...);
+    format(oss, fmt);
     return oss.str();
 }
 
-template<typename T1, typename... Args>
-void printf(const char* fmt, const T1& v1, const Args&... args)
+inline void printf(const char* fmt)
 {
-    format(std::cout, fmt, v1, args...);
+    format(std::cout, fmt);
 }
 
-#else
+inline void printfln(const char* fmt)
+{
+    format(std::cout, fmt);
+    std::cout << '\n';
+}
 
-// C++98 - define the interface functions using the wrapping macros
 #define TINYFORMAT_MAKE_FORMAT_FUNCS(n)                                   \
                                                                           \
 template<TINYFORMAT_ARGTYPES(n)>                                          \
 void format(std::ostream& out, const char* fmt, TINYFORMAT_VARARGS(n))    \
 {                                                                         \
-    tinyformat::detail::FormatIterator fmtIter(out, fmt);                 \
-    tinyformat::detail::format(fmtIter, TINYFORMAT_PASSARGS(n));          \
+    vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n)));            \
 }                                                                         \
                                                                           \
 template<TINYFORMAT_ARGTYPES(n)>                                          \
 std::string format(const char* fmt, TINYFORMAT_VARARGS(n))                \
 {                                                                         \
     std::ostringstream oss;                                               \
-    tinyformat::format(oss, fmt, TINYFORMAT_PASSARGS(n));                 \
+    format(oss, fmt, TINYFORMAT_PASSARGS(n));                             \
     return oss.str();                                                     \
 }                                                                         \
                                                                           \
 template<TINYFORMAT_ARGTYPES(n)>                                          \
-std::string format(const std::string &fmt, TINYFORMAT_VARARGS(n))         \
+void printf(const char* fmt, TINYFORMAT_VARARGS(n))                       \
 {                                                                         \
-    std::ostringstream oss;                                               \
-    tinyformat::format(oss, fmt.c_str(), TINYFORMAT_PASSARGS(n));         \
-    return oss.str();                                                     \
+    format(std::cout, fmt, TINYFORMAT_PASSARGS(n));                       \
 }                                                                         \
                                                                           \
 template<TINYFORMAT_ARGTYPES(n)>                                          \
-void printf(const char* fmt, TINYFORMAT_VARARGS(n))                       \
+void printfln(const char* fmt, TINYFORMAT_VARARGS(n))                     \
 {                                                                         \
-    tinyformat::format(std::cout, fmt, TINYFORMAT_PASSARGS(n));           \
+    format(std::cout, fmt, TINYFORMAT_PASSARGS(n));                       \
+    std::cout << '\n';                                                    \
 }
 
 TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS)
 #undef TINYFORMAT_MAKE_FORMAT_FUNCS
-#endif
 
+#endif
 
-//------------------------------------------------------------------------------
-// Define deprecated wrapping macro for backward compatibility in tinyformat
-// 1.x.  Will be removed in version 2!
-#define TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS
-#define TINYFORMAT_WRAP_FORMAT_N(n, returnType, funcName, funcDeclSuffix,  \
-                                 bodyPrefix, streamName, bodySuffix)       \
-template<TINYFORMAT_ARGTYPES(n)>                                           \
-returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt,     \
-                    TINYFORMAT_VARARGS(n)) funcDeclSuffix                  \
-{                                                                          \
-    bodyPrefix                                                             \
-    tinyformat::format(streamName, fmt, TINYFORMAT_PASSARGS(n));           \
-    bodySuffix                                                             \
-}                                                                          \
-
-#define TINYFORMAT_WRAP_FORMAT(returnType, funcName, funcDeclSuffix,       \
-                               bodyPrefix, streamName, bodySuffix)         \
-inline                                                                     \
-returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt      \
-                    ) funcDeclSuffix                                       \
-{                                                                          \
-    bodyPrefix                                                             \
-    tinyformat::detail::FormatIterator(streamName, fmt).finish();          \
-    bodySuffix                                                             \
-}                                                                          \
-TINYFORMAT_WRAP_FORMAT_N(1 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(2 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(3 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(4 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(5 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(6 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(7 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(8 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(9 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(10, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(11, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(12, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(13, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(14, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(15, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(16, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-
+// 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
This page took 0.051474 seconds and 4 git commands to generate.