@ -67,7 +67,9 @@
// weekday, month, day, hour, min);
// weekday, month, day, hour, min);
// std::cout << date;
// 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
// User defined format functions
@ -86,6 +88,18 @@
// defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM. For an
// defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM. For an
// example, see the implementation of printf() at the end of the source file.
// 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
// Additional API information
// --------------------------
// --------------------------
@ -118,6 +132,7 @@ namespace tfm = tinyformat;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Implementation details.
// Implementation details.
# include <algorithm>
# include <cassert>
# include <cassert>
# include <iostream>
# include <iostream>
# include <sstream>
# include <sstream>
@ -133,20 +148,20 @@ namespace tfm = tinyformat;
# endif
# endif
# 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
# if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201
// std::showpos is broken on old libstdc++ as provided with OSX. See
// std::showpos is broken on old libstdc++ as provided with OSX. See
// http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html
// http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html
# define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
# define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
# endif
# 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 {
namespace tinyformat {
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
@ -247,6 +262,29 @@ struct convertToInt<T,true>
static int invoke ( const T & value ) { return static_cast < int > ( value ) ; }
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
} // namespace detail
@ -255,18 +293,20 @@ struct convertToInt<T,true>
// desired.
// desired.
// Format a value into a stream. Called from format() for all types by default.
/// Format a value into a stream, delegating to operator<< by default.
//
///
// Users may override this for their own types. When this function is called,
/// 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 stream flags will have been modified according to the format string.
// The format specification is provided in the range [fmtBegin, fmtEnd).
/// The format specification is provided in the range [fmtBegin, fmtEnd). For
//
/// truncating conversions, ntrunc is set to the desired maximum number of
// By default, formatValue() uses the usual stream insertion operator
/// characters, for example "%.7s" calls formatValue with ntrunc = 7.
// operator<< to format the type T, with special cases for the %c and %p
///
// conversions.
/// 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 >
template < typename T >
inline void formatValue ( std : : ostream & out , const char * /*fmtBegin*/ ,
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
# ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS
// Since we don't support printing of wchar_t using "%ls", make it fail at
// Since we don't support printing of wchar_t using "%ls", make it fail at
@ -288,6 +328,12 @@ inline void formatValue(std::ostream& out, const char* /*fmtBegin*/,
# ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
# ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
else if ( detail : : formatZeroIntegerWorkaround < T > : : invoke ( out , value ) ) /**/ ;
else if ( detail : : formatZeroIntegerWorkaround < T > : : invoke ( out , value ) ) /**/ ;
# endif
# 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
else
out < < value ;
out < < value ;
}
}
@ -296,7 +342,7 @@ inline void formatValue(std::ostream& out, const char* /*fmtBegin*/,
// Overloaded version for char types to support printing as an integer
// Overloaded version for char types to support printing as an integer
# define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType) \
# define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType) \
inline void formatValue ( std : : ostream & out , const char * /*fmtBegin*/ , \
inline void formatValue ( std : : ostream & out , const char * /*fmtBegin*/ , \
const char * fmtEnd , charType value ) \
const char * fmtEnd , int /**/ , charType value ) \
{ \
{ \
switch ( * ( fmtEnd - 1 ) ) \
switch ( * ( fmtEnd - 1 ) ) \
{ \
{ \
@ -435,225 +481,91 @@ cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n ' +
namespace detail {
namespace detail {
// Class holding current position in format string and an output stream into
// Type-opaque holder for an argument to format(), with associated actions on
// which arguments are formatted.
// the type held as explicit function pointers. This allows FormatArg's for
class FormatIterator
// each argument to be allocated as a homogenous array inside FormatList
// whereas a naive implementation based on inheritance does not.
class FormatArg
{
{
public :
public :
// Flags for features not representable with standard stream state
FormatArg ( ) { }
enum ExtraFormatFlags
{
template < typename T >
Flag_None = 0 ,
FormatArg ( const T & value )
Flag_TruncateToPrecision = 1 < < 0 , // truncate length to stream precision()
: m_value ( static_cast < const void * > ( & value ) ) ,
Flag_SpacePadPositive = 1 < < 1 , // pad positive values with spaces
m_formatImpl ( & formatImpl < T > ) ,
Flag_VariableWidth = 1 < < 2 , // variable field width in arg list
m_toIntImpl ( & toIntImpl < T > )
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 ( ) )
{ }
{ }
// Print remaining part of format string.
void format ( std : : ostream & out , const char * fmtBegin ,
void finish ( )
const char * fmtEnd , int ntrunc ) const
{
{
// It would be nice if we could do this from the destructor, but we
m_formatImpl ( out , fmtBegin , fmtEnd , ntrunc , m_value ) ;
// can't if TINFORMAT_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 " ) ;
}
}
~ FormatIterator ( )
int toInt ( ) const
{
{
// Restore stream state
return m_toIntImpl ( m_value ) ;
m_out . width ( m_origWidth ) ;
m_out . precision ( m_origPrecision ) ;
m_out . flags ( m_origFlags ) ;
m_out . fill ( m_origFill ) ;
}
}
template < typename T >
void accept ( const T & value ) ;
private :
private :
// Parse and return an integer from the string c, as atoi()
template < typename T >
// On return, c is set to one past the end of the integer.
TINYFORMAT_HIDDEN static void formatImpl ( std : : ostream & out , const char * fmtBegin ,
static int parseIntAndAdvance ( const char * & c )
const char * fmtEnd , int ntrunc , const void * value )
{
{
int i = 0 ;
formatValue ( out , fmtBegin , fmtEnd , ntrunc , * static_cast < const T * > ( value ) ) ;
for ( ; * c > = ' 0 ' & & * c < = ' 9 ' ; + + c )
i = 10 * i + ( * c - ' 0 ' ) ;
return i ;
}
}
// 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 >
template < typename T >
static bool formatCStringTruncate ( std : : ostream & /*out*/ , const T & /*value*/ ,
TINYFORMAT_HIDDEN static int toIntImpl ( const void * value )
std : : streamsize /*truncLen*/ )
{
{
return false ;
return convertToInt < T > : : invoke ( * static_cast < const T * > ( value ) ) ;
}
# 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 ;
}
}
}
}
static const char * streamStateFromFormat ( std : : ostream & out ,
const void * m_value ;
unsigned int & extraFlags ,
void ( * m_formatImpl ) ( std : : ostream & out , const char * fmtBegin ,
const char * fmtStart ,
const char * fmtEnd , int ntrunc , const void * value ) ;
int variableWidth ,
int ( * m_toIntImpl ) ( const void * value ) ;
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 ;
} ;
} ;
// Accept a value for formatting into the internal stream.
// Parse and return an integer from the string c, as atoi()
template < typename T >
// On return, c is set to one past the end of the integer.
TINYFORMAT_NOINLINE // < greatly reduces bloat in optimized builds
inline int parseIntAndAdvance ( const char * & c )
void FormatIterator : : accept ( const T & value )
{
{
// Parse the format string
int i = 0 ;
const char * fmtEnd = 0 ;
for ( ; * c > = ' 0 ' & & * c < = ' 9 ' ; + + c )
if ( m_extraFlags = = Flag_None & & ! m_wantWidth & & ! m_wantPrecision )
i = 10 * i + ( * c - ' 0 ' ) ;
{
return i ;
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 ) ;
}
// Format the value into the stream.
// Print literal part of format string and return next format spec
if ( ! ( m_extraFlags & ( Flag_SpacePadPositive | Flag_TruncateToPrecision ) ) )
// position.
formatValue ( m_out , m_fmt , fmtEnd , value ) ;
//
else
// 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
switch ( * c )
// 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 )
{
{
for ( size_t i = 0 , iend = result . size ( ) ; i < iend ; + + i )
case ' \0 ' :
if ( result [ i ] = = ' + ' )
out . write ( fmt , c - fmt ) ;
result [ i ] = ' ' ;
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 ;
}
}
@ -663,13 +575,14 @@ void FormatIterator::accept(const T& value)
// with the form "%[flags][width][.precision][length]type".
// with the form "%[flags][width][.precision][length]type".
//
//
// Formatting options which can't be natively represented using the ostream
// Formatting options which can't be natively represented using the ostream
// state are returned in the extraFlags parameter which is a bitwise
// state are returned in spacePadPositive (for space padded positive numbers)
// combination of values from the ExtraFormatFlags enum.
// and ntrunc (for truncating conversions). argIndex is incremented if
inline const char * FormatIterator : : streamStateFromFormat ( std : : ostream & out ,
// necessary to pull out variable width and precision . The function returns a
unsigned int & extraFlags ,
// pointer to the character after the end of the current format spec.
const char * fmtStart ,
inline const char * streamStateFromFormat ( std : : ostream & out , bool & spacePadPositive ,
int variableWidth ,
int & ntrunc , const char * fmtStart ,
int variablePrecision )
const detail : : FormatArg * formatters ,
int & argIndex , int numFormatters )
{
{
if ( * fmtStart ! = ' % ' )
if ( * fmtStart ! = ' % ' )
{
{
@ -684,9 +597,9 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
out . unsetf ( std : : ios : : adjustfield | std : : ios : : basefield |
out . unsetf ( std : : ios : : adjustfield | std : : ios : : basefield |
std : : ios : : floatfield | std : : ios : : showbase | std : : ios : : boolalpha |
std : : ios : : floatfield | std : : ios : : showbase | std : : ios : : boolalpha |
std : : ios : : showpoint | std : : ios : : showpos | std : : ios : : uppercase ) ;
std : : ios : : showpoint | std : : ios : : showpos | std : : ios : : uppercase ) ;
extraFlags = Flag_None ;
bool precisionSet = false ;
bool precisionSet = false ;
bool widthSet = false ;
bool widthSet = false ;
int widthExtra = 0 ;
const char * c = fmtStart + 1 ;
const char * c = fmtStart + 1 ;
// 1) Parse flags
// 1) Parse flags
for ( ; ; + + c )
for ( ; ; + + c )
@ -713,12 +626,15 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
case ' ' :
case ' ' :
// overridden by show positive sign, '+' flag.
// overridden by show positive sign, '+' flag.
if ( ! ( out . flags ( ) & std : : ios : : showpos ) )
if ( ! ( out . flags ( ) & std : : ios : : showpos ) )
extraFlags | = Flag_SpacePadPositiv e;
spacePadPositive = tru e;
continue ;
continue ;
case ' + ' :
case ' + ' :
out . setf ( std : : ios : : showpos ) ;
out . setf ( std : : ios : : showpos ) ;
extraFlags & = ~ Flag_SpacePadPositive ;
spacePadPositive = false ;
widthExtra = 1 ;
continue ;
continue ;
default :
break ;
}
}
break ;
break ;
}
}
@ -731,15 +647,19 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
if ( * c = = ' * ' )
if ( * c = = ' * ' )
{
{
widthSet = true ;
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
// negative widths correspond to '-' flag set
out . fill ( ' ' ) ;
out . fill ( ' ' ) ;
out . setf ( std : : ios : : left , std : : ios : : adjustfield ) ;
out . setf ( std : : ios : : left , std : : ios : : adjustfield ) ;
variableWidth = - variableWidth ;
width = - w idth;
}
}
out . width ( variableWidth ) ;
out . width ( width ) ;
extraFlags | = Flag_VariableWidth ;
+ + c ;
+ + c ;
}
}
// 3) Parse precision
// 3) Parse precision
@ -750,8 +670,10 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
if ( * c = = ' * ' )
if ( * c = = ' * ' )
{
{
+ + c ;
+ + c ;
extraFlags | = Flag_VariablePrecision ;
if ( argIndex < numFormatters )
precision = variablePrecision ;
precision = formatters [ argIndex + + ] . toInt ( ) ;
else
TINYFORMAT_ERROR ( " tinyformat: Not enough arguments to read variable precision " ) ;
}
}
else
else
{
{
@ -814,7 +736,7 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
break ;
break ;
case ' s ' :
case ' s ' :
if ( precisionSet )
if ( precisionSet )
extraFlags | = Flag_TruncateToPrecision ;
ntrunc = static_cast < int > ( out . precision ( ) ) ;
// Make %s print booleans as "true" and "false"
// Make %s print booleans as "true" and "false"
out . setf ( std : : ios : : boolalpha ) ;
out . setf ( std : : ios : : boolalpha ) ;
break ;
break ;
@ -826,6 +748,8 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
TINYFORMAT_ERROR ( " tinyformat: Conversion spec incorrectly "
TINYFORMAT_ERROR ( " tinyformat: Conversion spec incorrectly "
" terminated by end of string " ) ;
" terminated by end of string " ) ;
return c ;
return c ;
default :
break ;
}
}
if ( intConversion & & precisionSet & & ! widthSet )
if ( intConversion & & precisionSet & & ! widthSet )
{
{
@ -833,7 +757,7 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
// padded with zeros on the left). This isn't really supported by the
// padded with zeros on the left). This isn't really supported by the
// iostreams, but we can approximately simulate it with the width if
// iostreams, but we can approximately simulate it with the width if
// the width isn't otherwise used.
// the width isn't otherwise used.
out . width ( out . precision ( ) ) ;
out . width ( out . precision ( ) + widthExtra ) ;
out . setf ( std : : ios : : internal , std : : ios : : adjustfield ) ;
out . setf ( std : : ios : : internal , std : : ios : : adjustfield ) ;
out . fill ( ' 0 ' ) ;
out . fill ( ' 0 ' ) ;
}
}
@ -841,170 +765,282 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Private format function on top of which the public interface is implemented.
inline void formatImpl ( std : : ostream & out , const char * fmt ,
// We enforce a mimimum of one value to be formatted to prevent bugs looking like
const detail : : FormatArg * formatters ,
//
int numFormatters )
// 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 )
{
{
fmtIter . accept ( value1 ) ;
// Saved stream state
fmtIter . finish ( ) ;
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 ' )
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
} // namespace detail
template < typename T1 , typename . . . Args >
void format ( FormatIterator & fmtIter , const T1 & value1 , const Args & . . . args )
/// 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 ) ;
public :
format ( fmtIter , args . . . ) ;
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 ) ;
inline void format ( FormatIterator & fmtIter )
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
{
{
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
TINYFORMAT_FOREACH_ARGNUM ( TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR )
# define TINYFORMAT_MAKE_FORMAT_DETAIL(n) \
# undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR
template < TINYFORMAT_ARGTYPES ( n ) > \
# endif
void format ( detail : : FormatIterator & fmtIter , TINYFORMAT_VARARGS ( n ) ) \
{ \
fmtIter . accept ( v1 ) ; \
format ( fmtIter TINYFORMAT_PASSARGS_TAIL ( n ) ) ; \
}
TINYFORMAT_FOREACH_ARGNUM ( TINYFORMAT_MAKE_FORMAT_DETAIL )
private :
# undef TINYFORMAT_MAKE_FORMAT_DETAIL
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
} // namespace detail
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Implement all the main interface functions here in terms of detail::format()
// Primary API functions
# ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
# ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
// C++11 - the simple case
/// Make type-agnostic format list from list of template arguments.
template < typename T1 , typename . . . Args >
///
void format ( std : : ostream & out , const char * fmt , const T1 & v1 , const Args & . . . args )
/// 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 ) ;
return detail : : FormatListN < sizeof . . . ( args ) > ( args . . . ) ;
format ( fmtIter , v1 , args . . . ) ;
}
}
template < typename T1 , typename . . . Args >
# else // C++98 version
std : : string format ( const char * fmt , const T1 & v1 , const Args & . . . args )
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 ;
std : : ostringstream oss ;
format ( oss , fmt , v1 , args . . . ) ;
format ( oss , fmt , args . . . ) ;
return oss . str ( ) ;
return oss . str ( ) ;
}
}
template < typename T1 , typename . . . Args >
/// Format list of arguments to std::cout, according to the given format string
std : : string format ( const std : : string & fmt , const T1 & v1 , const Args & . . . args )
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 ;
std : : ostringstream oss ;
format ( oss , fmt . c_str ( ) , v1 , args . . . ) ;
format ( oss , fmt ) ;
return oss . str ( ) ;
return oss . str ( ) ;
}
}
template < typename T1 , typename . . . Args >
inline void printf ( const char * fmt )
void printf ( const char * fmt , const T1 & v1 , const Args & . . . args )
{
{
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) \
# define TINYFORMAT_MAKE_FORMAT_FUNCS(n) \
\
\
template < TINYFORMAT_ARGTYPES ( n ) > \
template < TINYFORMAT_ARGTYPES ( n ) > \
void format ( std : : ostream & out , const char * fmt , TINYFORMAT_VARARGS ( n ) ) \
void format ( std : : ostream & out , const char * fmt , TINYFORMAT_VARARGS ( n ) ) \
{ \
{ \
tinyformat : : detail : : FormatIterator fmtIter ( out , fmt ) ; \
vformat ( out , fmt , makeFormatList ( TINYFORMAT_PASSARGS ( n ) ) ) ; \
tinyformat : : detail : : format ( fmtIter , TINYFORMAT_PASSARGS ( n ) ) ; \
} \
} \
\
\
template < TINYFORMAT_ARGTYPES ( n ) > \
template < TINYFORMAT_ARGTYPES ( n ) > \
std : : string format ( const char * fmt , TINYFORMAT_VARARGS ( n ) ) \
std : : string format ( const char * fmt , TINYFORMAT_VARARGS ( n ) ) \
{ \
{ \
std : : ostringstream oss ; \
std : : ostringstream oss ; \
tinyformat : : format ( oss , fmt , TINYFORMAT_PASSARGS ( n ) ) ; \
format ( oss , fmt , TINYFORMAT_PASSARGS ( n ) ) ; \
return oss . str ( ) ; \
return oss . str ( ) ; \
} \
} \
\
\
template < TINYFORMAT_ARGTYPES ( n ) > \
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 ; \
format ( std : : cout , fmt , TINYFORMAT_PASSARGS ( n ) ) ; \
tinyformat : : format ( oss , fmt . c_str ( ) , TINYFORMAT_PASSARGS ( n ) ) ; \
return oss . str ( ) ; \
} \
} \
\
\
template < TINYFORMAT_ARGTYPES ( 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 )
TINYFORMAT_FOREACH_ARGNUM ( TINYFORMAT_MAKE_FORMAT_FUNCS )
# undef 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
} // namespace tinyformat