@ -33,6 +33,7 @@
//
// * Type safety and extensibility for user defined types.
// * C99 printf() compatibility, to the extent possible using std::ostream
// * POSIX extension for positional arguments
// * Simplicity and minimalism. A single header file to include and distribute
// with your projects.
// * Augment rather than replace the standard stream formatting mechanism
@ -42,7 +43,7 @@
// Main interface example usage
// ----------------------------
//
// To print a date to std::cout :
// To print a date to std::cout for American usage :
//
// std::string weekday = "Wednesday";
// const char* month = "July";
@ -52,6 +53,14 @@
//
// tfm::printf("%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min);
//
// POSIX extension for positional arguments is available.
// The ability to rearrange formatting arguments is an important feature
// for localization because the word order may vary in different languages.
//
// Previous example for German usage. Arguments are reordered:
//
// tfm::printf("%1$s, %3$d. %2$s, %4$d:%5$.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
@ -133,12 +142,17 @@ namespace tfm = tinyformat;
//------------------------------------------------------------------------------
// Implementation details.
# include <algorithm>
# include <cassert>
# include <iostream>
# include <sstream>
# include <stdexcept>
# include <stdexcept> // Added for Bitcoin Core
# ifndef TINYFORMAT_ASSERT
# include <cassert>
# define TINYFORMAT_ASSERT(cond) assert(cond)
# endif
# ifndef TINYFORMAT_ERROR
# include <cassert>
# define TINYFORMAT_ERROR(reason) assert(0 && reason)
# endif
@ -149,13 +163,13 @@ namespace tfm = tinyformat;
# endif
# 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 mac OS. 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
// Workaround mac OS linker warning: Xcode uses different default symbol
// visibilities for static libs vs executables (see issue #25)
# define TINYFORMAT_HIDDEN __attribute__((visibility("hidden")))
# else
@ -164,6 +178,7 @@ namespace tfm = tinyformat;
namespace tinyformat {
// Added for Bitcoin Core
class format_error : public std : : runtime_error
{
public :
@ -218,7 +233,7 @@ template<int n> struct is_wchar<wchar_t[n]> {};
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 ) ; }
static void invoke ( std : : ostream & /*out*/ , const T & /*value*/ ) { TINYFORMAT_ASSERT ( 0 ) ; }
} ;
// Specialized version for types that can actually be converted to fmtT, as
// indicated by the "convertible" template parameter.
@ -240,8 +255,7 @@ struct formatZeroIntegerWorkaround<T,true>
{
static bool invoke ( std : : ostream & out , const T & value )
{
if ( static_cast < int > ( value ) = = 0 & & out . flags ( ) & std : : ios : : showpos )
{
if ( static_cast < int > ( value ) = = 0 & & out . flags ( ) & std : : ios : : showpos ) {
out < < " +0 " ;
return true ;
}
@ -282,7 +296,7 @@ inline void formatTruncated(std::ostream& out, const T& value, int ntrunc)
inline void formatTruncated ( std : : ostream & out , type * value , int ntrunc ) \
{ \
std : : streamsize len = 0 ; \
while ( len < ntrunc & & value [ len ] ! = 0 ) \
while ( len < ntrunc & & value [ len ] ! = 0 ) \
+ + len ; \
out . write ( value , len ) ; \
}
@ -328,15 +342,14 @@ inline void formatValue(std::ostream& out, const char* /*fmtBegin*/,
// 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 ' )
if ( canConvertToChar & & * ( fmtEnd - 1 ) = = ' c ' )
detail : : formatValueAsType < T , char > : : invoke ( out , value ) ;
else if ( canConvertToVoidPtr & & * ( fmtEnd - 1 ) = = ' p ' )
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 ) ) /**/ ;
else if ( detail : : formatZeroIntegerWorkaround < T > : : invoke ( out , value ) ) /**/ ;
# endif
else if ( ntrunc > = 0 )
{
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 ) ;
@ -351,8 +364,7 @@ inline void formatValue(std::ostream& out, const char* /*fmtBegin*/,
inline void formatValue ( std : : ostream & out , const char * /*fmtBegin*/ , \
const char * fmtEnd , int /**/ , charType value ) \
{ \
switch ( * ( fmtEnd - 1 ) ) \
{ \
switch ( * ( fmtEnd - 1 ) ) { \
case ' u ' : case ' d ' : case ' i ' : case ' o ' : case ' X ' : case ' x ' : \
out < < static_cast < int > ( value ) ; break ; \
default : \
@ -490,19 +502,19 @@ 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 homogen ous array inside FormatList
// each argument to be allocated as a homogen e ous 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 )
{ }
: m_value ( NULL ) ,
m_formatImpl ( NULL ) ,
m_toIntImpl ( NULL )
{ }
template < typename T >
explicit FormatArg ( const T & value )
FormatArg ( const T & value )
: m_value ( static_cast < const void * > ( & value ) ) ,
m_formatImpl ( & formatImpl < T > ) ,
m_toIntImpl ( & toIntImpl < T > )
@ -511,15 +523,15 @@ class FormatArg
void format ( std : : ostream & out , const char * fmtBegin ,
const char * fmtEnd , int ntrunc ) const
{
assert ( m_value ) ;
assert ( m_formatImpl ) ;
TINYFORMAT_ASSERT ( m_value ) ;
TINYFORMAT_ASSERT ( m_formatImpl ) ;
m_formatImpl ( out , fmtBegin , fmtEnd , ntrunc , m_value ) ;
}
int toInt ( ) const
{
assert ( m_value ) ;
assert ( m_toIntImpl ) ;
TINYFORMAT_ASSERT ( m_value ) ;
TINYFORMAT_ASSERT ( m_toIntImpl ) ;
return m_toIntImpl ( m_value ) ;
}
@ -549,36 +561,68 @@ class FormatArg
inline int parseIntAndAdvance ( const char * & c )
{
int i = 0 ;
for ( ; * c > = ' 0 ' & & * c < = ' 9 ' ; + + c )
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.
// Parse width or precision `n` from format string pointer `c`, and advance it
// to the next character. If an indirection is requested with `*`, the argument
// is read from `args[argIndex]` and `argIndex` is incremented (or read
// from `args[n]` in positional mode). Returns true if one or more
// characters were read.
inline bool parseWidthOrPrecision ( int & n , const char * & c , bool positionalMode ,
const detail : : FormatArg * args ,
int & argIndex , int numArgs )
{
if ( * c > = ' 0 ' & & * c < = ' 9 ' ) {
n = parseIntAndAdvance ( c ) ;
}
else if ( * c = = ' * ' ) {
+ + c ;
n = 0 ;
if ( positionalMode ) {
int pos = parseIntAndAdvance ( c ) - 1 ;
if ( * c ! = ' $ ' )
TINYFORMAT_ERROR ( " tinyformat: Non-positional argument used after a positional one " ) ;
if ( pos > = 0 & & pos < numArgs )
n = args [ pos ] . toInt ( ) ;
else
TINYFORMAT_ERROR ( " tinyformat: Positional argument out of range " ) ;
+ + c ;
}
else {
if ( argIndex < numArgs )
n = args [ argIndex + + ] . toInt ( ) ;
else
TINYFORMAT_ERROR ( " tinyformat: Not enough arguments to read variable width or precision " ) ;
}
}
else {
return false ;
}
return true ;
}
// 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.
// 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 ) ;
for ( ; ; + + c ) {
if ( * c = = ' \0 ' ) {
out . write ( fmt , c - fmt ) ;
return c ;
}
else if ( * c = = ' % ' ) {
out . write ( fmt , c - fmt ) ;
if ( * ( c + 1 ) ! = ' % ' )
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 ;
// for "%%", tack trailing % onto next literal section.
fmt = + + c ;
}
}
}
@ -587,23 +631,43 @@ inline const char* printFormatStringLiteral(std::ostream& out, const char* fmt)
// 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".
// with the form "%[flags][width][.precision][length]type" with POSIX
// positional arguments extension.
//
// POSIX positional arguments extension:
// Conversions can be applied to the nth argument after the format in
// the argument list, rather than to the next unused argument. In this case,
// the conversion specifier character % (see below) is replaced by the sequence
// "%n$", where n is a decimal integer in the range [1,{NL_ARGMAX}],
// giving the position of the argument in the argument list. This feature
// provides for the definition of format strings that select arguments
// in an order appropriate to specific languages.
//
// The format can contain either numbered argument conversion specifications
// (that is, "%n$" and "*m$"), or unnumbered argument conversion specifications
// (that is, % and * ), but not both. The only exception to this is that %%
// can be mixed with the "%n$" form. The results of mixing numbered and
// unnumbered argument specifications in a format string are undefined.
// When numbered argument specifications are used, specifying the Nth argument
// requires that all the leading arguments, from the first to the (N-1)th,
// are specified in the format string.
//
// In format strings containing the "%n$" form of conversion specification,
// numbered arguments in the argument list can be referenced from the format
// string as many times as required.
//
// 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 ,
inline const char * streamStateFromFormat ( std : : ostream & out , bool & positionalMode ,
bool & spacePadPositive ,
int & ntrunc , const char * fmtStart ,
const detail : : FormatArg * formatters ,
int & argIndex , int numFormatters )
const detail : : FormatArg * arg s,
int & argIndex , int num Arg s)
{
if ( * fmtStart ! = ' % ' )
{
TINYFORMAT_ERROR ( " tinyformat: Not enough conversion specifiers in format string " ) ;
return fmtStart ;
}
TINYFORMAT_ASSERT ( * fmtStart = = ' % ' ) ;
// Reset stream state to defaults.
out . width ( 0 ) ;
out . precision ( 6 ) ;
@ -616,100 +680,113 @@ inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositi
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 ;
// 1) Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag.
if ( * c > = ' 0 ' & & * c < = ' 9 ' ) {
const char tmpc = * c ;
int value = parseIntAndAdvance ( c ) ;
if ( * c = = ' $ ' ) {
// value is an argument index
if ( value > 0 & & value < = numArgs )
argIndex = value - 1 ;
else
TINYFORMAT_ERROR ( " tinyformat: Positional argument out of range " ) ;
+ + c ;
positionalMode = true ;
}
else if ( positionalMode ) {
TINYFORMAT_ERROR ( " tinyformat: Non-positional argument used after a positional one " ) ;
}
else {
if ( tmpc = = ' 0 ' ) {
// 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 ) ;
}
if ( value ! = 0 ) {
// Nonzero value means that we parsed width.
widthSet = true ;
out . width ( value ) ;
}
}
break ;
}
// 2) Parse width
if ( * c > = ' 0 ' & & * c < = ' 9 ' )
{
widthSet = true ;
out . width ( parseIntAndAdvance ( c ) ) ;
else if ( positionalMode ) {
TINYFORMAT_ERROR ( " tinyformat: Non-positional argument used after a positional one " ) ;
}
if ( * c = = ' * ' )
{
widthSet = true ;
// 2) Parse flags and width if we did not do it in previous step.
if ( ! widthSet ) {
// 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 ;
}
// Parse width
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 ;
widthSet = parseWidthOrPrecision ( width , c , positionalMode ,
args , argIndex , numArgs ) ;
if ( widthSet ) {
if ( width < 0 ) {
// negative widths correspond to '-' flag set
out . fill ( ' ' ) ;
out . setf ( std : : ios : : left , std : : ios : : adjustfield ) ;
width = - width ;
}
out. width ( width ) ;
}
out . width ( width ) ;
+ + c ;
}
// 3) Parse precision
if ( * c = = ' . ' )
{
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 ;
parseWidthOrPrecision ( precision , c , positionalMode ,
args , argIndex , numArgs ) ;
// Presence of `.` indicates precision set, unless the inferred value
// was negative in which case the default is used.
precisionSet = precision > = 0 ;
if ( precisionSet )
out . precision ( precision ) ;
}
// 4) Ignore any C99 length modifier
while ( * c = = ' l ' | | * c = = ' h ' | | * c = = ' L ' | |
* c = = ' j ' | | * c = = ' z ' | | * c = = ' t ' )
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 )
{
switch ( * c ) {
case ' u ' : case ' d ' : case ' i ' :
out . setf ( std : : ios : : dec , std : : ios : : basefield ) ;
intConversion = true ;
@ -738,6 +815,18 @@ inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositi
case ' f ' :
out . setf ( std : : ios : : fixed , std : : ios : : floatfield ) ;
break ;
case ' A ' :
out . setf ( std : : ios : : uppercase ) ;
// Falls through
case ' a ' :
# ifdef _MSC_VER
// Workaround https://developercommunity.visualstudio.com/content/problem/520472/hexfloat-stream-output-does-not-ignore-precision-a.html
// by always setting maximum precision on MSVC to avoid precision
// loss for doubles.
out . precision ( 13 ) ;
# endif
out . setf ( std : : ios : : fixed | std : : ios : : scientific , std : : ios : : floatfield ) ;
break ;
case ' G ' :
out . setf ( std : : ios : : uppercase ) ;
// Falls through
@ -746,17 +835,13 @@ inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositi
// 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 )
if ( precisionSet )
ntrunc = static_cast < int > ( out . precision ( ) ) ;
// Make %s print b ooleans as "true" and "false"
// Make %s print B ooleans as "true" and "false"
out . setf ( std : : ios : : boolalpha ) ;
break ;
case ' n ' :
@ -770,8 +855,7 @@ inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositi
default :
break ;
}
if ( intConversion & & precisionSet & & ! widthSet )
{
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
@ -786,8 +870,8 @@ inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositi
//------------------------------------------------------------------------------
inline void formatImpl ( std : : ostream & out , const char * fmt ,
const detail : : FormatArg * form atte rs,
int num Formatter s)
const detail : : FormatArg * arg s,
int num Arg s)
{
// Saved stream state
std : : streamsize origWidth = out . width ( ) ;
@ -795,26 +879,34 @@ inline void formatImpl(std::ostream& out, const char* fmt,
std : : ios : : fmtflags origFlags = out . flags ( ) ;
char origFill = out . fill ( ) ;
for ( int argIndex = 0 ; argIndex < numFormatters ; + + argIndex )
{
// Parse the format string
// "Positional mode" means all format specs should be of the form "%n$..."
// with `n` an integer. We detect this in `streamStateFromFormat`.
bool positionalMode = false ;
int argIndex = 0 ;
while ( true ) {
fmt = printFormatStringLiteral ( out , fmt ) ;
if ( * fmt = = ' \0 ' ) {
if ( ! positionalMode & & argIndex < numArgs ) {
TINYFORMAT_ERROR ( " tinyformat: Not enough conversion specifiers in format string " ) ;
}
break ;
}
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 " ) ;
const char * fmtEnd = streamStateFromFormat ( out , positionalMode, spacePadPositive, ntrunc , fmt ,
args, argIndex , numArg s) ;
// NB: argIndex may be incremented by reading variable width/precision
// in `streamStateFromFormat`, so do the bounds check here.
if ( argIndex > = numArgs ) {
TINYFORMAT_ERROR ( " tinyformat: Too many conversion specifiers in format string " ) ;
return ;
}
const FormatArg & arg = form atte rs[ argIndex ] ;
const FormatArg & arg = arg s[ argIndex ] ;
// Format the arg into the stream.
if ( ! spacePadPositive )
if ( ! spacePadPositive ) {
arg . format ( out , fmt , fmtEnd , ntrunc ) ;
else
{
}
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
@ -824,18 +916,17 @@ inline void formatImpl(std::ostream& out, const char* fmt,
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 ] = ' ' ;
for ( size_t i = 0 , iend = result . size ( ) ; i < iend ; + + i ) {
if ( result [ i ] = = ' + ' )
result [ i ] = ' ' ;
}
out < < result ;
}
if ( ! positionalMode )
+ + argIndex ;
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 ) ;
@ -855,14 +946,14 @@ inline void formatImpl(std::ostream& out, const char* fmt,
class FormatList
{
public :
FormatList ( detail : : FormatArg * form atte rs, int N )
: m_ form atte rs( form atte rs) , m_N ( N ) { }
FormatList ( detail : : FormatArg * arg s, int N )
: m_ arg s( arg s) , m_N ( N ) { }
friend void vformat ( std : : ostream & out , const char * fmt ,
const FormatList & list ) ;
private :
const detail : : FormatArg * m_ form atte rs;
const detail : : FormatArg * m_ arg s;
int m_N ;
} ;
@ -879,29 +970,33 @@ class FormatListN : public FormatList
public :
# ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
template < typename . . . Args >
explicit FormatListN ( const Args & . . . 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 ) > \
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 ) ) ; \
# define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \
\
template < TINYFORMAT_ARGTYPES ( n ) > \
FormatListN ( TINYFORMAT_VARARGS ( n ) ) \
: FormatList ( & m_formatterStore [ 0 ] , n ) \
{ TINYFORMAT_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
FormatListN ( const FormatListN & other )
: FormatList ( & m_formatterStore [ 0 ] , N )
{ std : : copy ( & other . m_formatterStore [ 0 ] , & other . m_formatterStore [ N ] ,
& m_formatterStore [ 0 ] ) ; }
private :
FormatArg m_formatterStore [ N ] ;
@ -956,7 +1051,7 @@ TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_MAKEFORMATLIST)
/// 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_ form atte rs, list . m_N ) ;
detail : : formatImpl ( out , fmt , list . m_ arg s, list . m_N ) ;
}
@ -993,6 +1088,7 @@ void printfln(const char* fmt, const Args&... args)
std : : cout < < ' \n ' ;
}
# else // C++98 version
inline void format ( std : : ostream & out , const char * fmt )
@ -1063,6 +1159,7 @@ std::string format(const std::string &fmt, const Args&... args)
} // namespace tinyformat
// Added for Bitcoin Core:
/** Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for details) */
# define strprintf tfm::format