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