Jim Flynn | 05c342a | 2020-07-23 11:20:59 +0100 | [diff] [blame] | 1 | // Formatting library for C++ - the core API |
| 2 | // |
| 3 | // Copyright (c) 2012 - present, Victor Zverovich |
| 4 | // All rights reserved. |
| 5 | // |
| 6 | // For the license information refer to format.h. |
| 7 | |
| 8 | #ifndef FMT_CORE_H_ |
| 9 | #define FMT_CORE_H_ |
| 10 | |
| 11 | #include <cstdio> // std::FILE |
| 12 | #include <cstring> |
| 13 | #include <functional> |
| 14 | #include <iterator> |
| 15 | #include <memory> |
| 16 | #include <string> |
| 17 | #include <type_traits> |
| 18 | #include <vector> |
| 19 | |
| 20 | // The fmt library version in the form major * 10000 + minor * 100 + patch. |
| 21 | #define FMT_VERSION 70001 |
| 22 | |
| 23 | #ifdef __clang__ |
| 24 | # define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) |
| 25 | #else |
| 26 | # define FMT_CLANG_VERSION 0 |
| 27 | #endif |
| 28 | |
| 29 | #if defined(__GNUC__) && !defined(__clang__) |
| 30 | # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) |
| 31 | #else |
| 32 | # define FMT_GCC_VERSION 0 |
| 33 | #endif |
| 34 | |
| 35 | #if defined(__INTEL_COMPILER) |
| 36 | # define FMT_ICC_VERSION __INTEL_COMPILER |
| 37 | #else |
| 38 | # define FMT_ICC_VERSION 0 |
| 39 | #endif |
| 40 | |
| 41 | #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) |
| 42 | # define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION |
| 43 | #else |
| 44 | # define FMT_HAS_GXX_CXX11 0 |
| 45 | #endif |
| 46 | |
| 47 | #ifdef __NVCC__ |
| 48 | # define FMT_NVCC __NVCC__ |
| 49 | #else |
| 50 | # define FMT_NVCC 0 |
| 51 | #endif |
| 52 | |
| 53 | #ifdef _MSC_VER |
| 54 | # define FMT_MSC_VER _MSC_VER |
| 55 | # define FMT_SUPPRESS_MSC_WARNING(n) __pragma(warning(suppress : n)) |
| 56 | #else |
| 57 | # define FMT_MSC_VER 0 |
| 58 | # define FMT_SUPPRESS_MSC_WARNING(n) |
| 59 | #endif |
| 60 | #ifdef __has_feature |
| 61 | # define FMT_HAS_FEATURE(x) __has_feature(x) |
| 62 | #else |
| 63 | # define FMT_HAS_FEATURE(x) 0 |
| 64 | #endif |
| 65 | |
| 66 | #if defined(__has_include) && !defined(__INTELLISENSE__) && \ |
| 67 | !(FMT_ICC_VERSION && FMT_ICC_VERSION < 1600) |
| 68 | # define FMT_HAS_INCLUDE(x) __has_include(x) |
| 69 | #else |
| 70 | # define FMT_HAS_INCLUDE(x) 0 |
| 71 | #endif |
| 72 | |
| 73 | #ifdef __has_cpp_attribute |
| 74 | # define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) |
| 75 | #else |
| 76 | # define FMT_HAS_CPP_ATTRIBUTE(x) 0 |
| 77 | #endif |
| 78 | |
| 79 | #define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ |
| 80 | (__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) |
| 81 | |
| 82 | #define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ |
| 83 | (__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) |
| 84 | |
| 85 | // Check if relaxed C++14 constexpr is supported. |
| 86 | // GCC doesn't allow throw in constexpr until version 6 (bug 67371). |
| 87 | #ifndef FMT_USE_CONSTEXPR |
| 88 | # define FMT_USE_CONSTEXPR \ |
| 89 | (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \ |
| 90 | (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \ |
| 91 | !FMT_NVCC && !FMT_ICC_VERSION |
| 92 | #endif |
| 93 | #if FMT_USE_CONSTEXPR |
| 94 | # define FMT_CONSTEXPR constexpr |
| 95 | # define FMT_CONSTEXPR_DECL constexpr |
| 96 | #else |
| 97 | # define FMT_CONSTEXPR inline |
| 98 | # define FMT_CONSTEXPR_DECL |
| 99 | #endif |
| 100 | |
| 101 | #ifndef FMT_OVERRIDE |
| 102 | # if FMT_HAS_FEATURE(cxx_override) || \ |
| 103 | (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 |
| 104 | # define FMT_OVERRIDE override |
| 105 | # else |
| 106 | # define FMT_OVERRIDE |
| 107 | # endif |
| 108 | #endif |
| 109 | |
| 110 | // Check if exceptions are disabled. |
| 111 | #ifndef FMT_EXCEPTIONS |
| 112 | # if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ |
| 113 | FMT_MSC_VER && !_HAS_EXCEPTIONS |
| 114 | # define FMT_EXCEPTIONS 0 |
| 115 | # else |
| 116 | # define FMT_EXCEPTIONS 1 |
| 117 | # endif |
| 118 | #endif |
| 119 | |
| 120 | // Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). |
| 121 | #ifndef FMT_USE_NOEXCEPT |
| 122 | # define FMT_USE_NOEXCEPT 0 |
| 123 | #endif |
| 124 | |
| 125 | #if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ |
| 126 | (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 |
| 127 | # define FMT_DETECTED_NOEXCEPT noexcept |
| 128 | # define FMT_HAS_CXX11_NOEXCEPT 1 |
| 129 | #else |
| 130 | # define FMT_DETECTED_NOEXCEPT throw() |
| 131 | # define FMT_HAS_CXX11_NOEXCEPT 0 |
| 132 | #endif |
| 133 | |
| 134 | #ifndef FMT_NOEXCEPT |
| 135 | # if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT |
| 136 | # define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT |
| 137 | # else |
| 138 | # define FMT_NOEXCEPT |
| 139 | # endif |
| 140 | #endif |
| 141 | |
| 142 | // [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code |
| 143 | // warnings. |
| 144 | #if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \ |
| 145 | !FMT_NVCC |
| 146 | # define FMT_NORETURN [[noreturn]] |
| 147 | #else |
| 148 | # define FMT_NORETURN |
| 149 | #endif |
| 150 | |
| 151 | #ifndef FMT_DEPRECATED |
| 152 | # if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900 |
| 153 | # define FMT_DEPRECATED [[deprecated]] |
| 154 | # else |
| 155 | # if defined(__GNUC__) || defined(__clang__) |
| 156 | # define FMT_DEPRECATED __attribute__((deprecated)) |
| 157 | # elif FMT_MSC_VER |
| 158 | # define FMT_DEPRECATED __declspec(deprecated) |
| 159 | # else |
| 160 | # define FMT_DEPRECATED /* deprecated */ |
| 161 | # endif |
| 162 | # endif |
| 163 | #endif |
| 164 | |
| 165 | // Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers. |
| 166 | #if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC |
| 167 | # define FMT_DEPRECATED_ALIAS |
| 168 | #else |
| 169 | # define FMT_DEPRECATED_ALIAS FMT_DEPRECATED |
| 170 | #endif |
| 171 | |
| 172 | #ifndef FMT_INLINE |
| 173 | # if FMT_GCC_VERSION || FMT_CLANG_VERSION |
| 174 | # define FMT_INLINE inline __attribute__((always_inline)) |
| 175 | # else |
| 176 | # define FMT_INLINE inline |
| 177 | # endif |
| 178 | #endif |
| 179 | |
| 180 | #ifndef FMT_BEGIN_NAMESPACE |
| 181 | # if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \ |
| 182 | FMT_MSC_VER >= 1900 |
| 183 | # define FMT_INLINE_NAMESPACE inline namespace |
| 184 | # define FMT_END_NAMESPACE \ |
| 185 | } \ |
| 186 | } |
| 187 | # else |
| 188 | # define FMT_INLINE_NAMESPACE namespace |
| 189 | # define FMT_END_NAMESPACE \ |
| 190 | } \ |
| 191 | using namespace v7; \ |
| 192 | } |
| 193 | # endif |
| 194 | # define FMT_BEGIN_NAMESPACE \ |
| 195 | namespace fmt { \ |
| 196 | FMT_INLINE_NAMESPACE v7 { |
| 197 | #endif |
| 198 | |
| 199 | #if !defined(FMT_HEADER_ONLY) && defined(_WIN32) |
| 200 | # define FMT_CLASS_API FMT_SUPPRESS_MSC_WARNING(4275) |
| 201 | # ifdef FMT_EXPORT |
| 202 | # define FMT_API __declspec(dllexport) |
| 203 | # define FMT_EXTERN_TEMPLATE_API FMT_API |
| 204 | # define FMT_EXPORTED |
| 205 | # elif defined(FMT_SHARED) |
| 206 | # define FMT_API __declspec(dllimport) |
| 207 | # define FMT_EXTERN_TEMPLATE_API FMT_API |
| 208 | # endif |
| 209 | #else |
| 210 | # define FMT_CLASS_API |
| 211 | #endif |
| 212 | #ifndef FMT_API |
| 213 | # define FMT_API |
| 214 | #endif |
| 215 | #ifndef FMT_EXTERN_TEMPLATE_API |
| 216 | # define FMT_EXTERN_TEMPLATE_API |
| 217 | #endif |
| 218 | #ifndef FMT_INSTANTIATION_DEF_API |
| 219 | # define FMT_INSTANTIATION_DEF_API FMT_API |
| 220 | #endif |
| 221 | |
| 222 | #ifndef FMT_HEADER_ONLY |
| 223 | # define FMT_EXTERN extern |
| 224 | #else |
| 225 | # define FMT_EXTERN |
| 226 | #endif |
| 227 | |
| 228 | // libc++ supports string_view in pre-c++17. |
| 229 | #if (FMT_HAS_INCLUDE(<string_view>) && \ |
| 230 | (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ |
| 231 | (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) |
| 232 | # include <string_view> |
| 233 | # define FMT_USE_STRING_VIEW |
| 234 | #elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L |
| 235 | # include <experimental/string_view> |
| 236 | # define FMT_USE_EXPERIMENTAL_STRING_VIEW |
| 237 | #endif |
| 238 | |
| 239 | #ifndef FMT_UNICODE |
| 240 | # define FMT_UNICODE !FMT_MSC_VER |
| 241 | #endif |
| 242 | #if FMT_UNICODE && FMT_MSC_VER |
| 243 | # pragma execution_character_set("utf-8") |
| 244 | #endif |
| 245 | |
| 246 | FMT_BEGIN_NAMESPACE |
| 247 | |
| 248 | // Implementations of enable_if_t and other metafunctions for older systems. |
| 249 | template <bool B, class T = void> |
| 250 | using enable_if_t = typename std::enable_if<B, T>::type; |
| 251 | template <bool B, class T, class F> |
| 252 | using conditional_t = typename std::conditional<B, T, F>::type; |
| 253 | template <bool B> using bool_constant = std::integral_constant<bool, B>; |
| 254 | template <typename T> |
| 255 | using remove_reference_t = typename std::remove_reference<T>::type; |
| 256 | template <typename T> |
| 257 | using remove_const_t = typename std::remove_const<T>::type; |
| 258 | template <typename T> |
| 259 | using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type; |
| 260 | template <typename T> struct type_identity { using type = T; }; |
| 261 | template <typename T> using type_identity_t = typename type_identity<T>::type; |
| 262 | |
| 263 | struct monostate {}; |
| 264 | |
| 265 | // An enable_if helper to be used in template parameters which results in much |
| 266 | // shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed |
| 267 | // to workaround a bug in MSVC 2019 (see #1140 and #1186). |
| 268 | #define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0 |
| 269 | |
| 270 | namespace detail { |
| 271 | |
| 272 | // A helper function to suppress bogus "conditional expression is constant" |
| 273 | // warnings. |
| 274 | template <typename T> constexpr T const_check(T value) { return value; } |
| 275 | |
| 276 | FMT_NORETURN FMT_API void assert_fail(const char* file, int line, |
| 277 | const char* message); |
| 278 | |
| 279 | #ifndef FMT_ASSERT |
| 280 | # ifdef NDEBUG |
| 281 | // FMT_ASSERT is not empty to avoid -Werror=empty-body. |
| 282 | # define FMT_ASSERT(condition, message) ((void)0) |
| 283 | # else |
| 284 | # define FMT_ASSERT(condition, message) \ |
| 285 | ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \ |
| 286 | ? (void)0 \ |
| 287 | : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message))) |
| 288 | # endif |
| 289 | #endif |
| 290 | |
| 291 | #if defined(FMT_USE_STRING_VIEW) |
| 292 | template <typename Char> using std_string_view = std::basic_string_view<Char>; |
| 293 | #elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) |
| 294 | template <typename Char> |
| 295 | using std_string_view = std::experimental::basic_string_view<Char>; |
| 296 | #else |
| 297 | template <typename T> struct std_string_view {}; |
| 298 | #endif |
| 299 | |
| 300 | #ifdef FMT_USE_INT128 |
| 301 | // Do nothing. |
| 302 | #elif defined(__SIZEOF_INT128__) && !FMT_NVCC |
| 303 | # define FMT_USE_INT128 1 |
| 304 | using int128_t = __int128_t; |
| 305 | using uint128_t = __uint128_t; |
| 306 | #else |
| 307 | # define FMT_USE_INT128 0 |
| 308 | #endif |
| 309 | #if !FMT_USE_INT128 |
| 310 | struct int128_t {}; |
| 311 | struct uint128_t {}; |
| 312 | #endif |
| 313 | |
| 314 | // Casts a nonnegative integer to unsigned. |
| 315 | template <typename Int> |
| 316 | FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) { |
| 317 | FMT_ASSERT(value >= 0, "negative value"); |
| 318 | return static_cast<typename std::make_unsigned<Int>::type>(value); |
| 319 | } |
| 320 | |
| 321 | FMT_SUPPRESS_MSC_WARNING(4566) constexpr unsigned char micro[] = "\u00B5"; |
| 322 | |
| 323 | template <typename Char> constexpr bool is_unicode() { |
| 324 | return FMT_UNICODE || sizeof(Char) != 1 || |
| 325 | (sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5); |
| 326 | } |
| 327 | |
| 328 | #ifdef __cpp_char8_t |
| 329 | using char8_type = char8_t; |
| 330 | #else |
| 331 | enum char8_type : unsigned char {}; |
| 332 | #endif |
| 333 | } // namespace detail |
| 334 | |
| 335 | #ifdef FMT_USE_INTERNAL |
| 336 | namespace internal = detail; // DEPRECATED |
| 337 | #endif |
| 338 | |
| 339 | /** |
| 340 | An implementation of ``std::basic_string_view`` for pre-C++17. It provides a |
| 341 | subset of the API. ``fmt::basic_string_view`` is used for format strings even |
| 342 | if ``std::string_view`` is available to prevent issues when a library is |
| 343 | compiled with a different ``-std`` option than the client code (which is not |
| 344 | recommended). |
| 345 | */ |
| 346 | template <typename Char> class basic_string_view { |
| 347 | private: |
| 348 | const Char* data_; |
| 349 | size_t size_; |
| 350 | |
| 351 | public: |
| 352 | using value_type = Char; |
| 353 | using iterator = const Char*; |
| 354 | |
| 355 | constexpr basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {} |
| 356 | |
| 357 | /** Constructs a string reference object from a C string and a size. */ |
| 358 | constexpr basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT |
| 359 | : data_(s), |
| 360 | size_(count) {} |
| 361 | |
| 362 | /** |
| 363 | \rst |
| 364 | Constructs a string reference object from a C string computing |
| 365 | the size with ``std::char_traits<Char>::length``. |
| 366 | \endrst |
| 367 | */ |
| 368 | #if __cplusplus >= 201703L // C++17's char_traits::length() is constexpr. |
| 369 | FMT_CONSTEXPR |
| 370 | #endif |
| 371 | basic_string_view(const Char* s) |
| 372 | : data_(s), size_(std::char_traits<Char>::length(s)) {} |
| 373 | |
| 374 | /** Constructs a string reference from a ``std::basic_string`` object. */ |
| 375 | template <typename Traits, typename Alloc> |
| 376 | FMT_CONSTEXPR basic_string_view( |
| 377 | const std::basic_string<Char, Traits, Alloc>& s) FMT_NOEXCEPT |
| 378 | : data_(s.data()), |
| 379 | size_(s.size()) {} |
| 380 | |
| 381 | template <typename S, FMT_ENABLE_IF(std::is_same< |
| 382 | S, detail::std_string_view<Char>>::value)> |
| 383 | FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()), |
| 384 | size_(s.size()) {} |
| 385 | |
| 386 | /** Returns a pointer to the string data. */ |
| 387 | constexpr const Char* data() const { return data_; } |
| 388 | |
| 389 | /** Returns the string size. */ |
| 390 | constexpr size_t size() const { return size_; } |
| 391 | |
| 392 | constexpr iterator begin() const { return data_; } |
| 393 | constexpr iterator end() const { return data_ + size_; } |
| 394 | |
| 395 | constexpr const Char& operator[](size_t pos) const { return data_[pos]; } |
| 396 | |
| 397 | FMT_CONSTEXPR void remove_prefix(size_t n) { |
| 398 | data_ += n; |
| 399 | size_ -= n; |
| 400 | } |
| 401 | |
| 402 | // Lexicographically compare this string reference to other. |
| 403 | int compare(basic_string_view other) const { |
| 404 | size_t str_size = size_ < other.size_ ? size_ : other.size_; |
| 405 | int result = std::char_traits<Char>::compare(data_, other.data_, str_size); |
| 406 | if (result == 0) |
| 407 | result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); |
| 408 | return result; |
| 409 | } |
| 410 | |
| 411 | friend bool operator==(basic_string_view lhs, basic_string_view rhs) { |
| 412 | return lhs.compare(rhs) == 0; |
| 413 | } |
| 414 | friend bool operator!=(basic_string_view lhs, basic_string_view rhs) { |
| 415 | return lhs.compare(rhs) != 0; |
| 416 | } |
| 417 | friend bool operator<(basic_string_view lhs, basic_string_view rhs) { |
| 418 | return lhs.compare(rhs) < 0; |
| 419 | } |
| 420 | friend bool operator<=(basic_string_view lhs, basic_string_view rhs) { |
| 421 | return lhs.compare(rhs) <= 0; |
| 422 | } |
| 423 | friend bool operator>(basic_string_view lhs, basic_string_view rhs) { |
| 424 | return lhs.compare(rhs) > 0; |
| 425 | } |
| 426 | friend bool operator>=(basic_string_view lhs, basic_string_view rhs) { |
| 427 | return lhs.compare(rhs) >= 0; |
| 428 | } |
| 429 | }; |
| 430 | |
| 431 | using string_view = basic_string_view<char>; |
| 432 | using wstring_view = basic_string_view<wchar_t>; |
| 433 | |
| 434 | /** Specifies if ``T`` is a character type. Can be specialized by users. */ |
| 435 | template <typename T> struct is_char : std::false_type {}; |
| 436 | template <> struct is_char<char> : std::true_type {}; |
| 437 | template <> struct is_char<wchar_t> : std::true_type {}; |
| 438 | template <> struct is_char<detail::char8_type> : std::true_type {}; |
| 439 | template <> struct is_char<char16_t> : std::true_type {}; |
| 440 | template <> struct is_char<char32_t> : std::true_type {}; |
| 441 | |
| 442 | /** |
| 443 | \rst |
| 444 | Returns a string view of `s`. In order to add custom string type support to |
| 445 | {fmt} provide an overload of `to_string_view` for it in the same namespace as |
| 446 | the type for the argument-dependent lookup to work. |
| 447 | |
| 448 | **Example**:: |
| 449 | |
| 450 | namespace my_ns { |
| 451 | inline string_view to_string_view(const my_string& s) { |
| 452 | return {s.data(), s.length()}; |
| 453 | } |
| 454 | } |
| 455 | std::string message = fmt::format(my_string("The answer is {}"), 42); |
| 456 | \endrst |
| 457 | */ |
| 458 | template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)> |
| 459 | inline basic_string_view<Char> to_string_view(const Char* s) { |
| 460 | return s; |
| 461 | } |
| 462 | |
| 463 | template <typename Char, typename Traits, typename Alloc> |
| 464 | inline basic_string_view<Char> to_string_view( |
| 465 | const std::basic_string<Char, Traits, Alloc>& s) { |
| 466 | return s; |
| 467 | } |
| 468 | |
| 469 | template <typename Char> |
| 470 | inline basic_string_view<Char> to_string_view(basic_string_view<Char> s) { |
| 471 | return s; |
| 472 | } |
| 473 | |
| 474 | template <typename Char, |
| 475 | FMT_ENABLE_IF(!std::is_empty<detail::std_string_view<Char>>::value)> |
| 476 | inline basic_string_view<Char> to_string_view(detail::std_string_view<Char> s) { |
| 477 | return s; |
| 478 | } |
| 479 | |
| 480 | // A base class for compile-time strings. It is defined in the fmt namespace to |
| 481 | // make formatting functions visible via ADL, e.g. format(FMT_STRING("{}"), 42). |
| 482 | struct compile_string {}; |
| 483 | |
| 484 | template <typename S> |
| 485 | struct is_compile_string : std::is_base_of<compile_string, S> {}; |
| 486 | |
| 487 | template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)> |
| 488 | constexpr basic_string_view<typename S::char_type> to_string_view(const S& s) { |
| 489 | return s; |
| 490 | } |
| 491 | |
| 492 | namespace detail { |
| 493 | void to_string_view(...); |
| 494 | using fmt::v7::to_string_view; |
| 495 | |
| 496 | // Specifies whether S is a string type convertible to fmt::basic_string_view. |
| 497 | // It should be a constexpr function but MSVC 2017 fails to compile it in |
| 498 | // enable_if and MSVC 2015 fails to compile it as an alias template. |
| 499 | template <typename S> |
| 500 | struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> { |
| 501 | }; |
| 502 | |
| 503 | template <typename S, typename = void> struct char_t_impl {}; |
| 504 | template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> { |
| 505 | using result = decltype(to_string_view(std::declval<S>())); |
| 506 | using type = typename result::value_type; |
| 507 | }; |
| 508 | |
| 509 | // Reports a compile-time error if S is not a valid format string. |
| 510 | template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)> |
| 511 | FMT_INLINE void check_format_string(const S&) { |
| 512 | #ifdef FMT_ENFORCE_COMPILE_STRING |
| 513 | static_assert(is_compile_string<S>::value, |
| 514 | "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " |
| 515 | "FMT_STRING."); |
| 516 | #endif |
| 517 | } |
| 518 | template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)> |
| 519 | void check_format_string(S); |
| 520 | |
| 521 | struct error_handler { |
| 522 | constexpr error_handler() = default; |
| 523 | constexpr error_handler(const error_handler&) = default; |
| 524 | |
| 525 | // This function is intentionally not constexpr to give a compile-time error. |
| 526 | FMT_NORETURN FMT_API void on_error(const char* message); |
| 527 | }; |
| 528 | } // namespace detail |
| 529 | |
| 530 | /** String's character type. */ |
| 531 | template <typename S> using char_t = typename detail::char_t_impl<S>::type; |
| 532 | |
| 533 | /** |
| 534 | \rst |
| 535 | Parsing context consisting of a format string range being parsed and an |
| 536 | argument counter for automatic indexing. |
| 537 | |
| 538 | You can use one of the following type aliases for common character types: |
| 539 | |
| 540 | +-----------------------+-------------------------------------+ |
| 541 | | Type | Definition | |
| 542 | +=======================+=====================================+ |
| 543 | | format_parse_context | basic_format_parse_context<char> | |
| 544 | +-----------------------+-------------------------------------+ |
| 545 | | wformat_parse_context | basic_format_parse_context<wchar_t> | |
| 546 | +-----------------------+-------------------------------------+ |
| 547 | \endrst |
| 548 | */ |
| 549 | template <typename Char, typename ErrorHandler = detail::error_handler> |
| 550 | class basic_format_parse_context : private ErrorHandler { |
| 551 | private: |
| 552 | basic_string_view<Char> format_str_; |
| 553 | int next_arg_id_; |
| 554 | |
| 555 | public: |
| 556 | using char_type = Char; |
| 557 | using iterator = typename basic_string_view<Char>::iterator; |
| 558 | |
| 559 | explicit constexpr basic_format_parse_context( |
| 560 | basic_string_view<Char> format_str, ErrorHandler eh = {}) |
| 561 | : ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {} |
| 562 | |
| 563 | /** |
| 564 | Returns an iterator to the beginning of the format string range being |
| 565 | parsed. |
| 566 | */ |
| 567 | constexpr iterator begin() const FMT_NOEXCEPT { return format_str_.begin(); } |
| 568 | |
| 569 | /** |
| 570 | Returns an iterator past the end of the format string range being parsed. |
| 571 | */ |
| 572 | constexpr iterator end() const FMT_NOEXCEPT { return format_str_.end(); } |
| 573 | |
| 574 | /** Advances the begin iterator to ``it``. */ |
| 575 | FMT_CONSTEXPR void advance_to(iterator it) { |
| 576 | format_str_.remove_prefix(detail::to_unsigned(it - begin())); |
| 577 | } |
| 578 | |
| 579 | /** |
| 580 | Reports an error if using the manual argument indexing; otherwise returns |
| 581 | the next argument index and switches to the automatic indexing. |
| 582 | */ |
| 583 | FMT_CONSTEXPR int next_arg_id() { |
| 584 | // Don't check if the argument id is valid to avoid overhead and because it |
| 585 | // will be checked during formatting anyway. |
| 586 | if (next_arg_id_ >= 0) return next_arg_id_++; |
| 587 | on_error("cannot switch from manual to automatic argument indexing"); |
| 588 | return 0; |
| 589 | } |
| 590 | |
| 591 | /** |
| 592 | Reports an error if using the automatic argument indexing; otherwise |
| 593 | switches to the manual indexing. |
| 594 | */ |
| 595 | FMT_CONSTEXPR void check_arg_id(int) { |
| 596 | if (next_arg_id_ > 0) |
| 597 | on_error("cannot switch from automatic to manual argument indexing"); |
| 598 | else |
| 599 | next_arg_id_ = -1; |
| 600 | } |
| 601 | |
| 602 | FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {} |
| 603 | |
| 604 | FMT_CONSTEXPR void on_error(const char* message) { |
| 605 | ErrorHandler::on_error(message); |
| 606 | } |
| 607 | |
| 608 | constexpr ErrorHandler error_handler() const { return *this; } |
| 609 | }; |
| 610 | |
| 611 | using format_parse_context = basic_format_parse_context<char>; |
| 612 | using wformat_parse_context = basic_format_parse_context<wchar_t>; |
| 613 | |
| 614 | template <typename Context> class basic_format_arg; |
| 615 | template <typename Context> class basic_format_args; |
| 616 | template <typename Context> class dynamic_format_arg_store; |
| 617 | |
| 618 | // A formatter for objects of type T. |
| 619 | template <typename T, typename Char = char, typename Enable = void> |
| 620 | struct formatter { |
| 621 | // A deleted default constructor indicates a disabled formatter. |
| 622 | formatter() = delete; |
| 623 | }; |
| 624 | |
| 625 | // Specifies if T has an enabled formatter specialization. A type can be |
| 626 | // formattable even if it doesn't have a formatter e.g. via a conversion. |
| 627 | template <typename T, typename Context> |
| 628 | using has_formatter = |
| 629 | std::is_constructible<typename Context::template formatter_type<T>>; |
| 630 | |
| 631 | // Checks whether T is a container with contiguous storage. |
| 632 | template <typename T> struct is_contiguous : std::false_type {}; |
| 633 | template <typename Char> |
| 634 | struct is_contiguous<std::basic_string<Char>> : std::true_type {}; |
| 635 | |
| 636 | namespace detail { |
| 637 | |
| 638 | // Extracts a reference to the container from back_insert_iterator. |
| 639 | template <typename Container> |
| 640 | inline Container& get_container(std::back_insert_iterator<Container> it) { |
| 641 | using bi_iterator = std::back_insert_iterator<Container>; |
| 642 | struct accessor : bi_iterator { |
| 643 | accessor(bi_iterator iter) : bi_iterator(iter) {} |
| 644 | using bi_iterator::container; |
| 645 | }; |
| 646 | return *accessor(it).container; |
| 647 | } |
| 648 | |
| 649 | /** |
| 650 | \rst |
| 651 | A contiguous memory buffer with an optional growing ability. It is an internal |
| 652 | class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`. |
| 653 | \endrst |
| 654 | */ |
| 655 | template <typename T> class buffer { |
| 656 | private: |
| 657 | T* ptr_; |
| 658 | size_t size_; |
| 659 | size_t capacity_; |
| 660 | |
| 661 | protected: |
| 662 | // Don't initialize ptr_ since it is not accessed to save a few cycles. |
| 663 | FMT_SUPPRESS_MSC_WARNING(26495) |
| 664 | buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} |
| 665 | |
| 666 | buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT |
| 667 | : ptr_(p), |
| 668 | size_(sz), |
| 669 | capacity_(cap) {} |
| 670 | |
Jan Eilers | ba3ef18 | 2020-09-25 08:36:44 +0100 | [diff] [blame] | 671 | virtual ~buffer() = default; |
Jim Flynn | 05c342a | 2020-07-23 11:20:59 +0100 | [diff] [blame] | 672 | |
| 673 | /** Sets the buffer data and capacity. */ |
| 674 | void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT { |
| 675 | ptr_ = buf_data; |
| 676 | capacity_ = buf_capacity; |
| 677 | } |
| 678 | |
| 679 | /** Increases the buffer capacity to hold at least *capacity* elements. */ |
| 680 | virtual void grow(size_t capacity) = 0; |
| 681 | |
| 682 | public: |
| 683 | using value_type = T; |
| 684 | using const_reference = const T&; |
| 685 | |
| 686 | buffer(const buffer&) = delete; |
| 687 | void operator=(const buffer&) = delete; |
| 688 | |
| 689 | T* begin() FMT_NOEXCEPT { return ptr_; } |
| 690 | T* end() FMT_NOEXCEPT { return ptr_ + size_; } |
| 691 | |
| 692 | const T* begin() const FMT_NOEXCEPT { return ptr_; } |
| 693 | const T* end() const FMT_NOEXCEPT { return ptr_ + size_; } |
| 694 | |
| 695 | /** Returns the size of this buffer. */ |
| 696 | size_t size() const FMT_NOEXCEPT { return size_; } |
| 697 | |
| 698 | /** Returns the capacity of this buffer. */ |
| 699 | size_t capacity() const FMT_NOEXCEPT { return capacity_; } |
| 700 | |
| 701 | /** Returns a pointer to the buffer data. */ |
| 702 | T* data() FMT_NOEXCEPT { return ptr_; } |
| 703 | |
| 704 | /** Returns a pointer to the buffer data. */ |
| 705 | const T* data() const FMT_NOEXCEPT { return ptr_; } |
| 706 | |
| 707 | /** Clears this buffer. */ |
| 708 | void clear() { size_ = 0; } |
| 709 | |
| 710 | // Tries resizing the buffer to contain *count* elements. If T is a POD type |
| 711 | // the new elements may not be initialized. |
| 712 | void try_resize(size_t count) { |
| 713 | try_reserve(count); |
| 714 | size_ = count <= capacity_ ? count : capacity_; |
| 715 | } |
| 716 | |
| 717 | // Tries increasing the buffer capacity to *new_capacity*. It can increase the |
| 718 | // capacity by a smaller amount than requested but guarantees there is space |
| 719 | // for at least one additional element either by increasing the capacity or by |
| 720 | // flushing the buffer if it is full. |
| 721 | void try_reserve(size_t new_capacity) { |
| 722 | if (new_capacity > capacity_) grow(new_capacity); |
| 723 | } |
| 724 | |
| 725 | void push_back(const T& value) { |
| 726 | try_reserve(size_ + 1); |
| 727 | ptr_[size_++] = value; |
| 728 | } |
| 729 | |
| 730 | /** Appends data to the end of the buffer. */ |
| 731 | template <typename U> void append(const U* begin, const U* end); |
| 732 | |
| 733 | template <typename I> T& operator[](I index) { return ptr_[index]; } |
| 734 | template <typename I> const T& operator[](I index) const { |
| 735 | return ptr_[index]; |
| 736 | } |
| 737 | }; |
| 738 | |
| 739 | // A buffer that writes to an output iterator when flushed. |
| 740 | template <typename OutputIt, typename T> |
| 741 | class iterator_buffer : public buffer<T> { |
| 742 | private: |
| 743 | enum { buffer_size = 256 }; |
| 744 | |
| 745 | OutputIt out_; |
| 746 | T data_[buffer_size]; |
| 747 | |
| 748 | protected: |
| 749 | void grow(size_t) final { |
| 750 | if (this->size() == buffer_size) flush(); |
| 751 | } |
| 752 | void flush(); |
| 753 | |
| 754 | public: |
| 755 | explicit iterator_buffer(OutputIt out) |
| 756 | : buffer<T>(data_, 0, buffer_size), out_(out) {} |
| 757 | ~iterator_buffer() { flush(); } |
| 758 | |
| 759 | OutputIt out() { |
| 760 | flush(); |
| 761 | return out_; |
| 762 | } |
| 763 | }; |
| 764 | |
| 765 | template <typename T> class iterator_buffer<T*, T> : public buffer<T> { |
| 766 | protected: |
| 767 | void grow(size_t) final {} |
| 768 | |
| 769 | public: |
| 770 | explicit iterator_buffer(T* out) : buffer<T>(out, 0, ~size_t()) {} |
| 771 | |
| 772 | T* out() { return &*this->end(); } |
| 773 | }; |
| 774 | |
| 775 | // A buffer that writes to a container with the contiguous storage. |
| 776 | template <typename Container> |
| 777 | class iterator_buffer<std::back_insert_iterator<Container>, |
| 778 | enable_if_t<is_contiguous<Container>::value, |
| 779 | typename Container::value_type>> |
| 780 | : public buffer<typename Container::value_type> { |
| 781 | private: |
| 782 | Container& container_; |
| 783 | |
| 784 | protected: |
| 785 | void grow(size_t capacity) FMT_OVERRIDE { |
| 786 | container_.resize(capacity); |
| 787 | this->set(&container_[0], capacity); |
| 788 | } |
| 789 | |
| 790 | public: |
| 791 | explicit iterator_buffer(Container& c) |
| 792 | : buffer<typename Container::value_type>(c.size()), container_(c) {} |
| 793 | explicit iterator_buffer(std::back_insert_iterator<Container> out) |
| 794 | : iterator_buffer(get_container(out)) {} |
| 795 | std::back_insert_iterator<Container> out() { |
| 796 | return std::back_inserter(container_); |
| 797 | } |
| 798 | }; |
| 799 | |
| 800 | template <typename Container> |
| 801 | using container_buffer = iterator_buffer<std::back_insert_iterator<Container>, |
| 802 | typename Container::value_type>; |
| 803 | |
| 804 | // An output iterator that appends to the buffer. |
| 805 | // It is used to reduce symbol sizes for the common case. |
| 806 | template <typename T> |
| 807 | class buffer_appender : public std::back_insert_iterator<buffer<T>> { |
| 808 | public: |
| 809 | explicit buffer_appender(buffer<T>& buf) |
| 810 | : std::back_insert_iterator<buffer<T>>(buf) {} |
| 811 | buffer_appender(std::back_insert_iterator<buffer<T>> it) |
| 812 | : std::back_insert_iterator<buffer<T>>(it) {} |
| 813 | }; |
| 814 | |
| 815 | // Maps an output iterator into a buffer. |
| 816 | template <typename T, typename OutputIt> |
| 817 | iterator_buffer<OutputIt, T> get_buffer(OutputIt); |
| 818 | template <typename T> buffer<T>& get_buffer(buffer_appender<T>); |
| 819 | |
| 820 | template <typename OutputIt> OutputIt get_buffer_init(OutputIt out) { |
| 821 | return out; |
| 822 | } |
| 823 | template <typename T> buffer<T>& get_buffer_init(buffer_appender<T> out) { |
| 824 | return get_container(out); |
| 825 | } |
| 826 | |
| 827 | template <typename Buffer> |
| 828 | auto get_iterator(Buffer& buf) -> decltype(buf.out()) { |
| 829 | return buf.out(); |
| 830 | } |
| 831 | template <typename T> buffer_appender<T> get_iterator(buffer<T>& buf) { |
| 832 | return buffer_appender<T>(buf); |
| 833 | } |
| 834 | |
| 835 | template <typename T, typename Char = char, typename Enable = void> |
| 836 | struct fallback_formatter { |
| 837 | fallback_formatter() = delete; |
| 838 | }; |
| 839 | |
| 840 | // Specifies if T has an enabled fallback_formatter specialization. |
| 841 | template <typename T, typename Context> |
| 842 | using has_fallback_formatter = |
| 843 | std::is_constructible<fallback_formatter<T, typename Context::char_type>>; |
| 844 | |
| 845 | struct view {}; |
| 846 | |
| 847 | template <typename Char, typename T> struct named_arg : view { |
| 848 | const Char* name; |
| 849 | const T& value; |
| 850 | named_arg(const Char* n, const T& v) : name(n), value(v) {} |
| 851 | }; |
| 852 | |
| 853 | template <typename Char> struct named_arg_info { |
| 854 | const Char* name; |
| 855 | int id; |
| 856 | }; |
| 857 | |
| 858 | template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS> |
| 859 | struct arg_data { |
| 860 | // args_[0].named_args points to named_args_ to avoid bloating format_args. |
| 861 | T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : 1)]; |
| 862 | named_arg_info<Char> named_args_[NUM_NAMED_ARGS]; |
| 863 | |
| 864 | template <typename... U> |
| 865 | arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {} |
| 866 | arg_data(const arg_data& other) = delete; |
| 867 | const T* args() const { return args_ + 1; } |
| 868 | named_arg_info<Char>* named_args() { return named_args_; } |
| 869 | }; |
| 870 | |
| 871 | template <typename T, typename Char, size_t NUM_ARGS> |
| 872 | struct arg_data<T, Char, NUM_ARGS, 0> { |
| 873 | T args_[NUM_ARGS != 0 ? NUM_ARGS : 1]; |
| 874 | |
| 875 | template <typename... U> |
| 876 | FMT_INLINE arg_data(const U&... init) : args_{init...} {} |
| 877 | FMT_INLINE const T* args() const { return args_; } |
| 878 | FMT_INLINE std::nullptr_t named_args() { return nullptr; } |
| 879 | }; |
| 880 | |
| 881 | template <typename Char> |
| 882 | inline void init_named_args(named_arg_info<Char>*, int, int) {} |
| 883 | |
| 884 | template <typename Char, typename T, typename... Tail> |
| 885 | void init_named_args(named_arg_info<Char>* named_args, int arg_count, |
| 886 | int named_arg_count, const T&, const Tail&... args) { |
| 887 | init_named_args(named_args, arg_count + 1, named_arg_count, args...); |
| 888 | } |
| 889 | |
| 890 | template <typename Char, typename T, typename... Tail> |
| 891 | void init_named_args(named_arg_info<Char>* named_args, int arg_count, |
| 892 | int named_arg_count, const named_arg<Char, T>& arg, |
| 893 | const Tail&... args) { |
| 894 | named_args[named_arg_count++] = {arg.name, arg_count}; |
| 895 | init_named_args(named_args, arg_count + 1, named_arg_count, args...); |
| 896 | } |
| 897 | |
| 898 | template <typename... Args> |
| 899 | FMT_INLINE void init_named_args(std::nullptr_t, int, int, const Args&...) {} |
| 900 | |
| 901 | template <typename T> struct is_named_arg : std::false_type {}; |
| 902 | |
| 903 | template <typename T, typename Char> |
| 904 | struct is_named_arg<named_arg<Char, T>> : std::true_type {}; |
| 905 | |
| 906 | template <bool B = false> constexpr size_t count() { return B ? 1 : 0; } |
| 907 | template <bool B1, bool B2, bool... Tail> constexpr size_t count() { |
| 908 | return (B1 ? 1 : 0) + count<B2, Tail...>(); |
| 909 | } |
| 910 | |
| 911 | template <typename... Args> constexpr size_t count_named_args() { |
| 912 | return count<is_named_arg<Args>::value...>(); |
| 913 | } |
| 914 | |
| 915 | enum class type { |
| 916 | none_type, |
| 917 | // Integer types should go first, |
| 918 | int_type, |
| 919 | uint_type, |
| 920 | long_long_type, |
| 921 | ulong_long_type, |
| 922 | int128_type, |
| 923 | uint128_type, |
| 924 | bool_type, |
| 925 | char_type, |
| 926 | last_integer_type = char_type, |
| 927 | // followed by floating-point types. |
| 928 | float_type, |
| 929 | double_type, |
| 930 | long_double_type, |
| 931 | last_numeric_type = long_double_type, |
| 932 | cstring_type, |
| 933 | string_type, |
| 934 | pointer_type, |
| 935 | custom_type |
| 936 | }; |
| 937 | |
| 938 | // Maps core type T to the corresponding type enum constant. |
| 939 | template <typename T, typename Char> |
| 940 | struct type_constant : std::integral_constant<type, type::custom_type> {}; |
| 941 | |
| 942 | #define FMT_TYPE_CONSTANT(Type, constant) \ |
| 943 | template <typename Char> \ |
| 944 | struct type_constant<Type, Char> \ |
| 945 | : std::integral_constant<type, type::constant> {} |
| 946 | |
| 947 | FMT_TYPE_CONSTANT(int, int_type); |
| 948 | FMT_TYPE_CONSTANT(unsigned, uint_type); |
| 949 | FMT_TYPE_CONSTANT(long long, long_long_type); |
| 950 | FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); |
| 951 | FMT_TYPE_CONSTANT(int128_t, int128_type); |
| 952 | FMT_TYPE_CONSTANT(uint128_t, uint128_type); |
| 953 | FMT_TYPE_CONSTANT(bool, bool_type); |
| 954 | FMT_TYPE_CONSTANT(Char, char_type); |
| 955 | FMT_TYPE_CONSTANT(float, float_type); |
| 956 | FMT_TYPE_CONSTANT(double, double_type); |
| 957 | FMT_TYPE_CONSTANT(long double, long_double_type); |
| 958 | FMT_TYPE_CONSTANT(const Char*, cstring_type); |
| 959 | FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type); |
| 960 | FMT_TYPE_CONSTANT(const void*, pointer_type); |
| 961 | |
| 962 | constexpr bool is_integral_type(type t) { |
| 963 | return t > type::none_type && t <= type::last_integer_type; |
| 964 | } |
| 965 | |
| 966 | constexpr bool is_arithmetic_type(type t) { |
| 967 | return t > type::none_type && t <= type::last_numeric_type; |
| 968 | } |
| 969 | |
| 970 | template <typename Char> struct string_value { |
| 971 | const Char* data; |
| 972 | size_t size; |
| 973 | }; |
| 974 | |
| 975 | template <typename Char> struct named_arg_value { |
| 976 | const named_arg_info<Char>* data; |
| 977 | size_t size; |
| 978 | }; |
| 979 | |
| 980 | template <typename Context> struct custom_value { |
| 981 | using parse_context = typename Context::parse_context_type; |
| 982 | const void* value; |
| 983 | void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx); |
| 984 | }; |
| 985 | |
| 986 | // A formatting argument value. |
| 987 | template <typename Context> class value { |
| 988 | public: |
| 989 | using char_type = typename Context::char_type; |
| 990 | |
| 991 | union { |
| 992 | int int_value; |
| 993 | unsigned uint_value; |
| 994 | long long long_long_value; |
| 995 | unsigned long long ulong_long_value; |
| 996 | int128_t int128_value; |
| 997 | uint128_t uint128_value; |
| 998 | bool bool_value; |
| 999 | char_type char_value; |
| 1000 | float float_value; |
| 1001 | double double_value; |
| 1002 | long double long_double_value; |
| 1003 | const void* pointer; |
| 1004 | string_value<char_type> string; |
| 1005 | custom_value<Context> custom; |
| 1006 | named_arg_value<char_type> named_args; |
| 1007 | }; |
| 1008 | |
| 1009 | constexpr FMT_INLINE value(int val = 0) : int_value(val) {} |
| 1010 | constexpr FMT_INLINE value(unsigned val) : uint_value(val) {} |
| 1011 | FMT_INLINE value(long long val) : long_long_value(val) {} |
| 1012 | FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} |
| 1013 | FMT_INLINE value(int128_t val) : int128_value(val) {} |
| 1014 | FMT_INLINE value(uint128_t val) : uint128_value(val) {} |
| 1015 | FMT_INLINE value(float val) : float_value(val) {} |
| 1016 | FMT_INLINE value(double val) : double_value(val) {} |
| 1017 | FMT_INLINE value(long double val) : long_double_value(val) {} |
| 1018 | FMT_INLINE value(bool val) : bool_value(val) {} |
| 1019 | FMT_INLINE value(char_type val) : char_value(val) {} |
| 1020 | FMT_INLINE value(const char_type* val) { string.data = val; } |
| 1021 | FMT_INLINE value(basic_string_view<char_type> val) { |
| 1022 | string.data = val.data(); |
| 1023 | string.size = val.size(); |
| 1024 | } |
| 1025 | FMT_INLINE value(const void* val) : pointer(val) {} |
| 1026 | FMT_INLINE value(const named_arg_info<char_type>* args, size_t size) |
| 1027 | : named_args{args, size} {} |
| 1028 | |
| 1029 | template <typename T> FMT_INLINE value(const T& val) { |
| 1030 | custom.value = &val; |
| 1031 | // Get the formatter type through the context to allow different contexts |
| 1032 | // have different extension points, e.g. `formatter<T>` for `format` and |
| 1033 | // `printf_formatter<T>` for `printf`. |
| 1034 | custom.format = format_custom_arg< |
| 1035 | T, conditional_t<has_formatter<T, Context>::value, |
| 1036 | typename Context::template formatter_type<T>, |
| 1037 | fallback_formatter<T, char_type>>>; |
| 1038 | } |
| 1039 | |
| 1040 | private: |
| 1041 | // Formats an argument of a custom type, such as a user-defined class. |
| 1042 | template <typename T, typename Formatter> |
| 1043 | static void format_custom_arg(const void* arg, |
| 1044 | typename Context::parse_context_type& parse_ctx, |
| 1045 | Context& ctx) { |
| 1046 | Formatter f; |
| 1047 | parse_ctx.advance_to(f.parse(parse_ctx)); |
| 1048 | ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx)); |
| 1049 | } |
| 1050 | }; |
| 1051 | |
| 1052 | template <typename Context, typename T> |
| 1053 | FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value); |
| 1054 | |
| 1055 | // To minimize the number of types we need to deal with, long is translated |
| 1056 | // either to int or to long long depending on its size. |
| 1057 | enum { long_short = sizeof(long) == sizeof(int) }; |
| 1058 | using long_type = conditional_t<long_short, int, long long>; |
| 1059 | using ulong_type = conditional_t<long_short, unsigned, unsigned long long>; |
| 1060 | |
| 1061 | struct unformattable {}; |
| 1062 | |
| 1063 | // Maps formatting arguments to core types. |
| 1064 | template <typename Context> struct arg_mapper { |
| 1065 | using char_type = typename Context::char_type; |
| 1066 | |
| 1067 | FMT_CONSTEXPR int map(signed char val) { return val; } |
| 1068 | FMT_CONSTEXPR unsigned map(unsigned char val) { return val; } |
| 1069 | FMT_CONSTEXPR int map(short val) { return val; } |
| 1070 | FMT_CONSTEXPR unsigned map(unsigned short val) { return val; } |
| 1071 | FMT_CONSTEXPR int map(int val) { return val; } |
| 1072 | FMT_CONSTEXPR unsigned map(unsigned val) { return val; } |
| 1073 | FMT_CONSTEXPR long_type map(long val) { return val; } |
| 1074 | FMT_CONSTEXPR ulong_type map(unsigned long val) { return val; } |
| 1075 | FMT_CONSTEXPR long long map(long long val) { return val; } |
| 1076 | FMT_CONSTEXPR unsigned long long map(unsigned long long val) { return val; } |
| 1077 | FMT_CONSTEXPR int128_t map(int128_t val) { return val; } |
| 1078 | FMT_CONSTEXPR uint128_t map(uint128_t val) { return val; } |
| 1079 | FMT_CONSTEXPR bool map(bool val) { return val; } |
| 1080 | |
| 1081 | template <typename T, FMT_ENABLE_IF(is_char<T>::value)> |
| 1082 | FMT_CONSTEXPR char_type map(T val) { |
| 1083 | static_assert( |
| 1084 | std::is_same<T, char>::value || std::is_same<T, char_type>::value, |
| 1085 | "mixing character types is disallowed"); |
| 1086 | return val; |
| 1087 | } |
| 1088 | |
| 1089 | FMT_CONSTEXPR float map(float val) { return val; } |
| 1090 | FMT_CONSTEXPR double map(double val) { return val; } |
| 1091 | FMT_CONSTEXPR long double map(long double val) { return val; } |
| 1092 | |
| 1093 | FMT_CONSTEXPR const char_type* map(char_type* val) { return val; } |
| 1094 | FMT_CONSTEXPR const char_type* map(const char_type* val) { return val; } |
| 1095 | template <typename T, FMT_ENABLE_IF(is_string<T>::value)> |
| 1096 | FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) { |
| 1097 | static_assert(std::is_same<char_type, char_t<T>>::value, |
| 1098 | "mixing character types is disallowed"); |
| 1099 | return to_string_view(val); |
| 1100 | } |
| 1101 | template <typename T, |
| 1102 | FMT_ENABLE_IF( |
| 1103 | std::is_constructible<basic_string_view<char_type>, T>::value && |
| 1104 | !is_string<T>::value && !has_formatter<T, Context>::value && |
| 1105 | !has_fallback_formatter<T, Context>::value)> |
| 1106 | FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) { |
| 1107 | return basic_string_view<char_type>(val); |
| 1108 | } |
| 1109 | template < |
| 1110 | typename T, |
| 1111 | FMT_ENABLE_IF( |
| 1112 | std::is_constructible<std_string_view<char_type>, T>::value && |
| 1113 | !std::is_constructible<basic_string_view<char_type>, T>::value && |
| 1114 | !is_string<T>::value && !has_formatter<T, Context>::value && |
| 1115 | !has_fallback_formatter<T, Context>::value)> |
| 1116 | FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) { |
| 1117 | return std_string_view<char_type>(val); |
| 1118 | } |
| 1119 | FMT_CONSTEXPR const char* map(const signed char* val) { |
| 1120 | static_assert(std::is_same<char_type, char>::value, "invalid string type"); |
| 1121 | return reinterpret_cast<const char*>(val); |
| 1122 | } |
| 1123 | FMT_CONSTEXPR const char* map(const unsigned char* val) { |
| 1124 | static_assert(std::is_same<char_type, char>::value, "invalid string type"); |
| 1125 | return reinterpret_cast<const char*>(val); |
| 1126 | } |
| 1127 | FMT_CONSTEXPR const char* map(signed char* val) { |
| 1128 | const auto* const_val = val; |
| 1129 | return map(const_val); |
| 1130 | } |
| 1131 | FMT_CONSTEXPR const char* map(unsigned char* val) { |
| 1132 | const auto* const_val = val; |
| 1133 | return map(const_val); |
| 1134 | } |
| 1135 | |
| 1136 | FMT_CONSTEXPR const void* map(void* val) { return val; } |
| 1137 | FMT_CONSTEXPR const void* map(const void* val) { return val; } |
| 1138 | FMT_CONSTEXPR const void* map(std::nullptr_t val) { return val; } |
| 1139 | template <typename T> FMT_CONSTEXPR int map(const T*) { |
| 1140 | // Formatting of arbitrary pointers is disallowed. If you want to output |
| 1141 | // a pointer cast it to "void *" or "const void *". In particular, this |
| 1142 | // forbids formatting of "[const] volatile char *" which is printed as bool |
| 1143 | // by iostreams. |
| 1144 | static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); |
| 1145 | return 0; |
| 1146 | } |
| 1147 | |
| 1148 | template <typename T, |
| 1149 | FMT_ENABLE_IF(std::is_enum<T>::value && |
| 1150 | !has_formatter<T, Context>::value && |
| 1151 | !has_fallback_formatter<T, Context>::value)> |
| 1152 | FMT_CONSTEXPR auto map(const T& val) |
| 1153 | -> decltype(std::declval<arg_mapper>().map( |
| 1154 | static_cast<typename std::underlying_type<T>::type>(val))) { |
| 1155 | return map(static_cast<typename std::underlying_type<T>::type>(val)); |
| 1156 | } |
| 1157 | template <typename T, |
| 1158 | FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value && |
| 1159 | (has_formatter<T, Context>::value || |
| 1160 | has_fallback_formatter<T, Context>::value))> |
| 1161 | FMT_CONSTEXPR const T& map(const T& val) { |
| 1162 | return val; |
| 1163 | } |
| 1164 | |
| 1165 | template <typename T> |
| 1166 | FMT_CONSTEXPR auto map(const named_arg<char_type, T>& val) |
| 1167 | -> decltype(std::declval<arg_mapper>().map(val.value)) { |
| 1168 | return map(val.value); |
| 1169 | } |
| 1170 | |
| 1171 | unformattable map(...) { return {}; } |
| 1172 | }; |
| 1173 | |
| 1174 | // A type constant after applying arg_mapper<Context>. |
| 1175 | template <typename T, typename Context> |
| 1176 | using mapped_type_constant = |
| 1177 | type_constant<decltype(arg_mapper<Context>().map(std::declval<const T&>())), |
| 1178 | typename Context::char_type>; |
| 1179 | |
| 1180 | enum { packed_arg_bits = 4 }; |
| 1181 | // Maximum number of arguments with packed types. |
| 1182 | enum { max_packed_args = 62 / packed_arg_bits }; |
| 1183 | enum : unsigned long long { is_unpacked_bit = 1ULL << 63 }; |
| 1184 | enum : unsigned long long { has_named_args_bit = 1ULL << 62 }; |
| 1185 | } // namespace detail |
| 1186 | |
| 1187 | // A formatting argument. It is a trivially copyable/constructible type to |
| 1188 | // allow storage in basic_memory_buffer. |
| 1189 | template <typename Context> class basic_format_arg { |
| 1190 | private: |
| 1191 | detail::value<Context> value_; |
| 1192 | detail::type type_; |
| 1193 | |
| 1194 | template <typename ContextType, typename T> |
| 1195 | friend FMT_CONSTEXPR basic_format_arg<ContextType> detail::make_arg( |
| 1196 | const T& value); |
| 1197 | |
| 1198 | template <typename Visitor, typename Ctx> |
| 1199 | friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis, |
| 1200 | const basic_format_arg<Ctx>& arg) |
| 1201 | -> decltype(vis(0)); |
| 1202 | |
| 1203 | friend class basic_format_args<Context>; |
| 1204 | friend class dynamic_format_arg_store<Context>; |
| 1205 | |
| 1206 | using char_type = typename Context::char_type; |
| 1207 | |
| 1208 | template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS> |
| 1209 | friend struct detail::arg_data; |
| 1210 | |
| 1211 | basic_format_arg(const detail::named_arg_info<char_type>* args, size_t size) |
| 1212 | : value_(args, size) {} |
| 1213 | |
| 1214 | public: |
| 1215 | class handle { |
| 1216 | public: |
| 1217 | explicit handle(detail::custom_value<Context> custom) : custom_(custom) {} |
| 1218 | |
| 1219 | void format(typename Context::parse_context_type& parse_ctx, |
| 1220 | Context& ctx) const { |
| 1221 | custom_.format(custom_.value, parse_ctx, ctx); |
| 1222 | } |
| 1223 | |
| 1224 | private: |
| 1225 | detail::custom_value<Context> custom_; |
| 1226 | }; |
| 1227 | |
| 1228 | constexpr basic_format_arg() : type_(detail::type::none_type) {} |
| 1229 | |
| 1230 | constexpr explicit operator bool() const FMT_NOEXCEPT { |
| 1231 | return type_ != detail::type::none_type; |
| 1232 | } |
| 1233 | |
| 1234 | detail::type type() const { return type_; } |
| 1235 | |
| 1236 | bool is_integral() const { return detail::is_integral_type(type_); } |
| 1237 | bool is_arithmetic() const { return detail::is_arithmetic_type(type_); } |
| 1238 | }; |
| 1239 | |
| 1240 | /** |
| 1241 | \rst |
| 1242 | Visits an argument dispatching to the appropriate visit method based on |
| 1243 | the argument type. For example, if the argument type is ``double`` then |
| 1244 | ``vis(value)`` will be called with the value of type ``double``. |
| 1245 | \endrst |
| 1246 | */ |
| 1247 | template <typename Visitor, typename Context> |
| 1248 | FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg( |
| 1249 | Visitor&& vis, const basic_format_arg<Context>& arg) -> decltype(vis(0)) { |
| 1250 | using char_type = typename Context::char_type; |
| 1251 | switch (arg.type_) { |
| 1252 | case detail::type::none_type: |
| 1253 | break; |
| 1254 | case detail::type::int_type: |
| 1255 | return vis(arg.value_.int_value); |
| 1256 | case detail::type::uint_type: |
| 1257 | return vis(arg.value_.uint_value); |
| 1258 | case detail::type::long_long_type: |
| 1259 | return vis(arg.value_.long_long_value); |
| 1260 | case detail::type::ulong_long_type: |
| 1261 | return vis(arg.value_.ulong_long_value); |
| 1262 | #if FMT_USE_INT128 |
| 1263 | case detail::type::int128_type: |
| 1264 | return vis(arg.value_.int128_value); |
| 1265 | case detail::type::uint128_type: |
| 1266 | return vis(arg.value_.uint128_value); |
| 1267 | #else |
| 1268 | case detail::type::int128_type: |
| 1269 | case detail::type::uint128_type: |
| 1270 | break; |
| 1271 | #endif |
| 1272 | case detail::type::bool_type: |
| 1273 | return vis(arg.value_.bool_value); |
| 1274 | case detail::type::char_type: |
| 1275 | return vis(arg.value_.char_value); |
| 1276 | case detail::type::float_type: |
| 1277 | return vis(arg.value_.float_value); |
| 1278 | case detail::type::double_type: |
| 1279 | return vis(arg.value_.double_value); |
| 1280 | case detail::type::long_double_type: |
| 1281 | return vis(arg.value_.long_double_value); |
| 1282 | case detail::type::cstring_type: |
| 1283 | return vis(arg.value_.string.data); |
| 1284 | case detail::type::string_type: |
| 1285 | return vis(basic_string_view<char_type>(arg.value_.string.data, |
| 1286 | arg.value_.string.size)); |
| 1287 | case detail::type::pointer_type: |
| 1288 | return vis(arg.value_.pointer); |
| 1289 | case detail::type::custom_type: |
| 1290 | return vis(typename basic_format_arg<Context>::handle(arg.value_.custom)); |
| 1291 | } |
| 1292 | return vis(monostate()); |
| 1293 | } |
| 1294 | |
| 1295 | template <typename T> struct formattable : std::false_type {}; |
| 1296 | |
| 1297 | namespace detail { |
| 1298 | |
| 1299 | // A workaround for gcc 4.8 to make void_t work in a SFINAE context. |
| 1300 | template <typename... Ts> struct void_t_impl { using type = void; }; |
| 1301 | |
| 1302 | template <typename... Ts> |
| 1303 | using void_t = typename detail::void_t_impl<Ts...>::type; |
| 1304 | |
| 1305 | // Detect the iterator category of *any* given type in a SFINAE-friendly way. |
| 1306 | // Unfortunately, older implementations of std::iterator_traits are not safe |
| 1307 | // for use in a SFINAE-context. |
| 1308 | template <typename It, typename Enable = void> |
| 1309 | struct iterator_category : std::false_type {}; |
| 1310 | |
| 1311 | template <typename T> struct iterator_category<T*> { |
| 1312 | using type = std::random_access_iterator_tag; |
| 1313 | }; |
| 1314 | |
| 1315 | template <typename It> |
| 1316 | struct iterator_category<It, void_t<typename It::iterator_category>> { |
| 1317 | using type = typename It::iterator_category; |
| 1318 | }; |
| 1319 | |
| 1320 | // Detect if *any* given type models the OutputIterator concept. |
| 1321 | template <typename It> class is_output_iterator { |
| 1322 | // Check for mutability because all iterator categories derived from |
| 1323 | // std::input_iterator_tag *may* also meet the requirements of an |
| 1324 | // OutputIterator, thereby falling into the category of 'mutable iterators' |
| 1325 | // [iterator.requirements.general] clause 4. The compiler reveals this |
| 1326 | // property only at the point of *actually dereferencing* the iterator! |
| 1327 | template <typename U> |
| 1328 | static decltype(*(std::declval<U>())) test(std::input_iterator_tag); |
| 1329 | template <typename U> static char& test(std::output_iterator_tag); |
| 1330 | template <typename U> static const char& test(...); |
| 1331 | |
| 1332 | using type = decltype(test<It>(typename iterator_category<It>::type{})); |
| 1333 | |
| 1334 | public: |
| 1335 | enum { value = !std::is_const<remove_reference_t<type>>::value }; |
| 1336 | }; |
| 1337 | |
| 1338 | template <typename OutputIt> |
| 1339 | struct is_back_insert_iterator : std::false_type {}; |
| 1340 | template <typename Container> |
| 1341 | struct is_back_insert_iterator<std::back_insert_iterator<Container>> |
| 1342 | : std::true_type {}; |
| 1343 | |
| 1344 | template <typename OutputIt> |
| 1345 | struct is_contiguous_back_insert_iterator : std::false_type {}; |
| 1346 | template <typename Container> |
| 1347 | struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>> |
| 1348 | : is_contiguous<Container> {}; |
| 1349 | template <typename Char> |
| 1350 | struct is_contiguous_back_insert_iterator<buffer_appender<Char>> |
| 1351 | : std::true_type {}; |
| 1352 | |
| 1353 | // A type-erased reference to an std::locale to avoid heavy <locale> include. |
| 1354 | class locale_ref { |
| 1355 | private: |
| 1356 | const void* locale_; // A type-erased pointer to std::locale. |
| 1357 | |
| 1358 | public: |
| 1359 | locale_ref() : locale_(nullptr) {} |
| 1360 | template <typename Locale> explicit locale_ref(const Locale& loc); |
| 1361 | |
| 1362 | explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; } |
| 1363 | |
| 1364 | template <typename Locale> Locale get() const; |
| 1365 | }; |
| 1366 | |
| 1367 | template <typename> constexpr unsigned long long encode_types() { return 0; } |
| 1368 | |
| 1369 | template <typename Context, typename Arg, typename... Args> |
| 1370 | constexpr unsigned long long encode_types() { |
| 1371 | return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) | |
| 1372 | (encode_types<Context, Args...>() << packed_arg_bits); |
| 1373 | } |
| 1374 | |
| 1375 | template <typename Context, typename T> |
| 1376 | FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value) { |
| 1377 | basic_format_arg<Context> arg; |
| 1378 | arg.type_ = mapped_type_constant<T, Context>::value; |
| 1379 | arg.value_ = arg_mapper<Context>().map(value); |
| 1380 | return arg; |
| 1381 | } |
| 1382 | |
| 1383 | template <typename T> int check(unformattable) { |
| 1384 | static_assert( |
| 1385 | formattable<T>(), |
| 1386 | "Cannot format an argument. To make type T formattable provide a " |
| 1387 | "formatter<T> specialization: https://fmt.dev/dev/api.html#udt"); |
| 1388 | return 0; |
| 1389 | } |
| 1390 | template <typename T, typename U> inline const U& check(const U& val) { |
| 1391 | return val; |
| 1392 | } |
| 1393 | |
| 1394 | // The type template parameter is there to avoid an ODR violation when using |
| 1395 | // a fallback formatter in one translation unit and an implicit conversion in |
| 1396 | // another (not recommended). |
| 1397 | template <bool IS_PACKED, typename Context, type, typename T, |
| 1398 | FMT_ENABLE_IF(IS_PACKED)> |
| 1399 | inline value<Context> make_arg(const T& val) { |
| 1400 | return check<T>(arg_mapper<Context>().map(val)); |
| 1401 | } |
| 1402 | |
| 1403 | template <bool IS_PACKED, typename Context, type, typename T, |
| 1404 | FMT_ENABLE_IF(!IS_PACKED)> |
| 1405 | inline basic_format_arg<Context> make_arg(const T& value) { |
| 1406 | return make_arg<Context>(value); |
| 1407 | } |
| 1408 | |
| 1409 | template <typename T> struct is_reference_wrapper : std::false_type {}; |
| 1410 | template <typename T> |
| 1411 | struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; |
| 1412 | |
| 1413 | template <typename T> const T& unwrap(const T& v) { return v; } |
| 1414 | template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) { |
| 1415 | return static_cast<const T&>(v); |
| 1416 | } |
| 1417 | |
| 1418 | class dynamic_arg_list { |
| 1419 | // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for |
| 1420 | // templates it doesn't complain about inability to deduce single translation |
| 1421 | // unit for placing vtable. So storage_node_base is made a fake template. |
| 1422 | template <typename = void> struct node { |
| 1423 | virtual ~node() = default; |
| 1424 | std::unique_ptr<node<>> next; |
| 1425 | }; |
| 1426 | |
| 1427 | template <typename T> struct typed_node : node<> { |
| 1428 | T value; |
| 1429 | |
| 1430 | template <typename Arg> |
| 1431 | FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} |
| 1432 | |
| 1433 | template <typename Char> |
| 1434 | FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg) |
| 1435 | : value(arg.data(), arg.size()) {} |
| 1436 | }; |
| 1437 | |
| 1438 | std::unique_ptr<node<>> head_; |
| 1439 | |
| 1440 | public: |
| 1441 | template <typename T, typename Arg> const T& push(const Arg& arg) { |
| 1442 | auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg)); |
| 1443 | auto& value = new_node->value; |
| 1444 | new_node->next = std::move(head_); |
| 1445 | head_ = std::move(new_node); |
| 1446 | return value; |
| 1447 | } |
| 1448 | }; |
| 1449 | } // namespace detail |
| 1450 | |
| 1451 | // Formatting context. |
| 1452 | template <typename OutputIt, typename Char> class basic_format_context { |
| 1453 | public: |
| 1454 | /** The character type for the output. */ |
| 1455 | using char_type = Char; |
| 1456 | |
| 1457 | private: |
| 1458 | OutputIt out_; |
| 1459 | basic_format_args<basic_format_context> args_; |
| 1460 | detail::locale_ref loc_; |
| 1461 | |
| 1462 | public: |
| 1463 | using iterator = OutputIt; |
| 1464 | using format_arg = basic_format_arg<basic_format_context>; |
| 1465 | using parse_context_type = basic_format_parse_context<Char>; |
| 1466 | template <typename T> using formatter_type = formatter<T, char_type>; |
| 1467 | |
| 1468 | basic_format_context(const basic_format_context&) = delete; |
| 1469 | void operator=(const basic_format_context&) = delete; |
| 1470 | /** |
| 1471 | Constructs a ``basic_format_context`` object. References to the arguments are |
| 1472 | stored in the object so make sure they have appropriate lifetimes. |
| 1473 | */ |
| 1474 | basic_format_context(OutputIt out, |
| 1475 | basic_format_args<basic_format_context> ctx_args, |
| 1476 | detail::locale_ref loc = detail::locale_ref()) |
| 1477 | : out_(out), args_(ctx_args), loc_(loc) {} |
| 1478 | |
| 1479 | format_arg arg(int id) const { return args_.get(id); } |
| 1480 | format_arg arg(basic_string_view<char_type> name) { return args_.get(name); } |
| 1481 | int arg_id(basic_string_view<char_type> name) { return args_.get_id(name); } |
| 1482 | const basic_format_args<basic_format_context>& args() const { return args_; } |
| 1483 | |
| 1484 | detail::error_handler error_handler() { return {}; } |
| 1485 | void on_error(const char* message) { error_handler().on_error(message); } |
| 1486 | |
| 1487 | // Returns an iterator to the beginning of the output range. |
| 1488 | iterator out() { return out_; } |
| 1489 | |
| 1490 | // Advances the begin iterator to ``it``. |
| 1491 | void advance_to(iterator it) { |
| 1492 | if (!detail::is_back_insert_iterator<iterator>()) out_ = it; |
| 1493 | } |
| 1494 | |
| 1495 | detail::locale_ref locale() { return loc_; } |
| 1496 | }; |
| 1497 | |
| 1498 | template <typename Char> |
| 1499 | using buffer_context = |
| 1500 | basic_format_context<detail::buffer_appender<Char>, Char>; |
| 1501 | using format_context = buffer_context<char>; |
| 1502 | using wformat_context = buffer_context<wchar_t>; |
| 1503 | |
| 1504 | // Workaround an alias issue: https://stackoverflow.com/q/62767544/471164. |
| 1505 | #define FMT_BUFFER_CONTEXT(Char) \ |
| 1506 | basic_format_context<detail::buffer_appender<Char>, Char> |
| 1507 | |
| 1508 | /** |
| 1509 | \rst |
| 1510 | An array of references to arguments. It can be implicitly converted into |
| 1511 | `~fmt::basic_format_args` for passing into type-erased formatting functions |
| 1512 | such as `~fmt::vformat`. |
| 1513 | \endrst |
| 1514 | */ |
| 1515 | template <typename Context, typename... Args> |
| 1516 | class format_arg_store |
| 1517 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 |
| 1518 | // Workaround a GCC template argument substitution bug. |
| 1519 | : public basic_format_args<Context> |
| 1520 | #endif |
| 1521 | { |
| 1522 | private: |
| 1523 | static const size_t num_args = sizeof...(Args); |
| 1524 | static const size_t num_named_args = detail::count_named_args<Args...>(); |
| 1525 | static const bool is_packed = num_args <= detail::max_packed_args; |
| 1526 | |
| 1527 | using value_type = conditional_t<is_packed, detail::value<Context>, |
| 1528 | basic_format_arg<Context>>; |
| 1529 | |
| 1530 | detail::arg_data<value_type, typename Context::char_type, num_args, |
| 1531 | num_named_args> |
| 1532 | data_; |
| 1533 | |
| 1534 | friend class basic_format_args<Context>; |
| 1535 | |
| 1536 | static constexpr unsigned long long desc = |
| 1537 | (is_packed ? detail::encode_types<Context, Args...>() |
| 1538 | : detail::is_unpacked_bit | num_args) | |
| 1539 | (num_named_args != 0 |
| 1540 | ? static_cast<unsigned long long>(detail::has_named_args_bit) |
| 1541 | : 0); |
| 1542 | |
| 1543 | public: |
| 1544 | format_arg_store(const Args&... args) |
| 1545 | : |
| 1546 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 |
| 1547 | basic_format_args<Context>(*this), |
| 1548 | #endif |
| 1549 | data_{detail::make_arg< |
| 1550 | is_packed, Context, |
| 1551 | detail::mapped_type_constant<Args, Context>::value>(args)...} { |
| 1552 | detail::init_named_args(data_.named_args(), 0, 0, args...); |
| 1553 | } |
| 1554 | }; |
| 1555 | |
| 1556 | /** |
| 1557 | \rst |
| 1558 | Constructs a `~fmt::format_arg_store` object that contains references to |
| 1559 | arguments and can be implicitly converted to `~fmt::format_args`. `Context` |
| 1560 | can be omitted in which case it defaults to `~fmt::context`. |
| 1561 | See `~fmt::arg` for lifetime considerations. |
| 1562 | \endrst |
| 1563 | */ |
| 1564 | template <typename Context = format_context, typename... Args> |
| 1565 | inline format_arg_store<Context, Args...> make_format_args( |
| 1566 | const Args&... args) { |
| 1567 | return {args...}; |
| 1568 | } |
| 1569 | |
| 1570 | /** |
| 1571 | \rst |
| 1572 | Constructs a `~fmt::format_arg_store` object that contains references |
| 1573 | to arguments and can be implicitly converted to `~fmt::format_args`. |
| 1574 | If ``format_str`` is a compile-time string then `make_args_checked` checks |
| 1575 | its validity at compile time. |
| 1576 | \endrst |
| 1577 | */ |
| 1578 | template <typename... Args, typename S, typename Char = char_t<S>> |
| 1579 | inline auto make_args_checked(const S& format_str, |
| 1580 | const remove_reference_t<Args>&... args) |
| 1581 | -> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> { |
| 1582 | static_assert( |
| 1583 | detail::count<( |
| 1584 | std::is_base_of<detail::view, remove_reference_t<Args>>::value && |
| 1585 | std::is_reference<Args>::value)...>() == 0, |
| 1586 | "passing views as lvalues is disallowed"); |
| 1587 | detail::check_format_string<Args...>(format_str); |
| 1588 | return {args...}; |
| 1589 | } |
| 1590 | |
| 1591 | /** |
| 1592 | \rst |
| 1593 | Returns a named argument to be used in a formatting function. It should only |
| 1594 | be used in a call to a formatting function. |
| 1595 | |
| 1596 | **Example**:: |
| 1597 | |
| 1598 | fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); |
| 1599 | \endrst |
| 1600 | */ |
| 1601 | template <typename Char, typename T> |
| 1602 | inline detail::named_arg<Char, T> arg(const Char* name, const T& arg) { |
| 1603 | static_assert(!detail::is_named_arg<T>(), "nested named arguments"); |
| 1604 | return {name, arg}; |
| 1605 | } |
| 1606 | |
| 1607 | /** |
| 1608 | \rst |
| 1609 | A dynamic version of `fmt::format_arg_store`. |
| 1610 | It's equipped with a storage to potentially temporary objects which lifetimes |
| 1611 | could be shorter than the format arguments object. |
| 1612 | |
| 1613 | It can be implicitly converted into `~fmt::basic_format_args` for passing |
| 1614 | into type-erased formatting functions such as `~fmt::vformat`. |
| 1615 | \endrst |
| 1616 | */ |
| 1617 | template <typename Context> |
| 1618 | class dynamic_format_arg_store |
| 1619 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 |
| 1620 | // Workaround a GCC template argument substitution bug. |
| 1621 | : public basic_format_args<Context> |
| 1622 | #endif |
| 1623 | { |
| 1624 | private: |
| 1625 | using char_type = typename Context::char_type; |
| 1626 | |
| 1627 | template <typename T> struct need_copy { |
| 1628 | static constexpr detail::type mapped_type = |
| 1629 | detail::mapped_type_constant<T, Context>::value; |
| 1630 | |
| 1631 | enum { |
| 1632 | value = !(detail::is_reference_wrapper<T>::value || |
| 1633 | std::is_same<T, basic_string_view<char_type>>::value || |
| 1634 | std::is_same<T, detail::std_string_view<char_type>>::value || |
| 1635 | (mapped_type != detail::type::cstring_type && |
| 1636 | mapped_type != detail::type::string_type && |
| 1637 | mapped_type != detail::type::custom_type)) |
| 1638 | }; |
| 1639 | }; |
| 1640 | |
| 1641 | template <typename T> |
| 1642 | using stored_type = conditional_t<detail::is_string<T>::value, |
| 1643 | std::basic_string<char_type>, T>; |
| 1644 | |
| 1645 | // Storage of basic_format_arg must be contiguous. |
| 1646 | std::vector<basic_format_arg<Context>> data_; |
| 1647 | std::vector<detail::named_arg_info<char_type>> named_info_; |
| 1648 | |
| 1649 | // Storage of arguments not fitting into basic_format_arg must grow |
| 1650 | // without relocation because items in data_ refer to it. |
| 1651 | detail::dynamic_arg_list dynamic_args_; |
| 1652 | |
| 1653 | friend class basic_format_args<Context>; |
| 1654 | |
| 1655 | unsigned long long get_types() const { |
| 1656 | return detail::is_unpacked_bit | data_.size() | |
| 1657 | (named_info_.empty() |
| 1658 | ? 0ULL |
| 1659 | : static_cast<unsigned long long>(detail::has_named_args_bit)); |
| 1660 | } |
| 1661 | |
| 1662 | const basic_format_arg<Context>* data() const { |
| 1663 | return named_info_.empty() ? data_.data() : data_.data() + 1; |
| 1664 | } |
| 1665 | |
| 1666 | template <typename T> void emplace_arg(const T& arg) { |
| 1667 | data_.emplace_back(detail::make_arg<Context>(arg)); |
| 1668 | } |
| 1669 | |
| 1670 | template <typename T> |
| 1671 | void emplace_arg(const detail::named_arg<char_type, T>& arg) { |
| 1672 | if (named_info_.empty()) { |
| 1673 | constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr}; |
| 1674 | data_.insert(data_.begin(), {zero_ptr, 0}); |
| 1675 | } |
| 1676 | data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value))); |
| 1677 | auto pop_one = [](std::vector<basic_format_arg<Context>>* data) { |
| 1678 | data->pop_back(); |
| 1679 | }; |
| 1680 | std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)> |
| 1681 | guard{&data_, pop_one}; |
| 1682 | named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)}); |
| 1683 | data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; |
| 1684 | guard.release(); |
| 1685 | } |
| 1686 | |
| 1687 | public: |
| 1688 | /** |
| 1689 | \rst |
| 1690 | Adds an argument into the dynamic store for later passing to a formatting |
| 1691 | function. |
| 1692 | |
| 1693 | Note that custom types and string types (but not string views) are copied |
| 1694 | into the store dynamically allocating memory if necessary. |
| 1695 | |
| 1696 | **Example**:: |
| 1697 | |
| 1698 | fmt::dynamic_format_arg_store<fmt::format_context> store; |
| 1699 | store.push_back(42); |
| 1700 | store.push_back("abc"); |
| 1701 | store.push_back(1.5f); |
| 1702 | std::string result = fmt::vformat("{} and {} and {}", store); |
| 1703 | \endrst |
| 1704 | */ |
| 1705 | template <typename T> void push_back(const T& arg) { |
| 1706 | if (detail::const_check(need_copy<T>::value)) |
| 1707 | emplace_arg(dynamic_args_.push<stored_type<T>>(arg)); |
| 1708 | else |
| 1709 | emplace_arg(detail::unwrap(arg)); |
| 1710 | } |
| 1711 | |
| 1712 | /** |
| 1713 | \rst |
| 1714 | Adds a reference to the argument into the dynamic store for later passing to |
| 1715 | a formatting function. Supports named arguments wrapped in |
| 1716 | ``std::reference_wrapper`` via ``std::ref()``/``std::cref()``. |
| 1717 | |
| 1718 | **Example**:: |
| 1719 | |
| 1720 | fmt::dynamic_format_arg_store<fmt::format_context> store; |
| 1721 | char str[] = "1234567890"; |
| 1722 | store.push_back(std::cref(str)); |
| 1723 | int a1_val{42}; |
| 1724 | auto a1 = fmt::arg("a1_", a1_val); |
| 1725 | store.push_back(std::cref(a1)); |
| 1726 | |
| 1727 | // Changing str affects the output but only for string and custom types. |
| 1728 | str[0] = 'X'; |
| 1729 | |
| 1730 | std::string result = fmt::vformat("{} and {a1_}"); |
| 1731 | assert(result == "X234567890 and 42"); |
| 1732 | \endrst |
| 1733 | */ |
| 1734 | template <typename T> void push_back(std::reference_wrapper<T> arg) { |
| 1735 | static_assert( |
| 1736 | detail::is_named_arg<typename std::remove_cv<T>::type>::value || |
| 1737 | need_copy<T>::value, |
| 1738 | "objects of built-in types and string views are always copied"); |
| 1739 | emplace_arg(arg.get()); |
| 1740 | } |
| 1741 | |
| 1742 | /** |
| 1743 | Adds named argument into the dynamic store for later passing to a formatting |
| 1744 | function. ``std::reference_wrapper`` is supported to avoid copying of the |
| 1745 | argument. |
| 1746 | */ |
| 1747 | template <typename T> |
| 1748 | void push_back(const detail::named_arg<char_type, T>& arg) { |
| 1749 | const char_type* arg_name = |
| 1750 | dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str(); |
| 1751 | if (detail::const_check(need_copy<T>::value)) { |
| 1752 | emplace_arg( |
| 1753 | fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value))); |
| 1754 | } else { |
| 1755 | emplace_arg(fmt::arg(arg_name, arg.value)); |
| 1756 | } |
| 1757 | } |
| 1758 | |
| 1759 | /** Erase all elements from the store */ |
| 1760 | void clear() { |
| 1761 | data_.clear(); |
| 1762 | named_info_.clear(); |
| 1763 | dynamic_args_ = detail::dynamic_arg_list(); |
| 1764 | } |
| 1765 | |
| 1766 | /** |
| 1767 | \rst |
| 1768 | Reserves space to store at least *new_cap* arguments including |
| 1769 | *new_cap_named* named arguments. |
| 1770 | \endrst |
| 1771 | */ |
| 1772 | void reserve(size_t new_cap, size_t new_cap_named) { |
| 1773 | FMT_ASSERT(new_cap >= new_cap_named, |
| 1774 | "Set of arguments includes set of named arguments"); |
| 1775 | data_.reserve(new_cap); |
| 1776 | named_info_.reserve(new_cap_named); |
| 1777 | } |
| 1778 | }; |
| 1779 | |
| 1780 | /** |
| 1781 | \rst |
| 1782 | A view of a collection of formatting arguments. To avoid lifetime issues it |
| 1783 | should only be used as a parameter type in type-erased functions such as |
| 1784 | ``vformat``:: |
| 1785 | |
| 1786 | void vlog(string_view format_str, format_args args); // OK |
| 1787 | format_args args = make_format_args(42); // Error: dangling reference |
| 1788 | \endrst |
| 1789 | */ |
| 1790 | template <typename Context> class basic_format_args { |
| 1791 | public: |
| 1792 | using size_type = int; |
| 1793 | using format_arg = basic_format_arg<Context>; |
| 1794 | |
| 1795 | private: |
| 1796 | // A descriptor that contains information about formatting arguments. |
| 1797 | // If the number of arguments is less or equal to max_packed_args then |
| 1798 | // argument types are passed in the descriptor. This reduces binary code size |
| 1799 | // per formatting function call. |
| 1800 | unsigned long long desc_; |
| 1801 | union { |
| 1802 | // If is_packed() returns true then argument values are stored in values_; |
| 1803 | // otherwise they are stored in args_. This is done to improve cache |
| 1804 | // locality and reduce compiled code size since storing larger objects |
| 1805 | // may require more code (at least on x86-64) even if the same amount of |
| 1806 | // data is actually copied to stack. It saves ~10% on the bloat test. |
| 1807 | const detail::value<Context>* values_; |
| 1808 | const format_arg* args_; |
| 1809 | }; |
| 1810 | |
| 1811 | bool is_packed() const { return (desc_ & detail::is_unpacked_bit) == 0; } |
| 1812 | bool has_named_args() const { |
| 1813 | return (desc_ & detail::has_named_args_bit) != 0; |
| 1814 | } |
| 1815 | |
| 1816 | detail::type type(int index) const { |
| 1817 | int shift = index * detail::packed_arg_bits; |
| 1818 | unsigned int mask = (1 << detail::packed_arg_bits) - 1; |
| 1819 | return static_cast<detail::type>((desc_ >> shift) & mask); |
| 1820 | } |
| 1821 | |
| 1822 | basic_format_args(unsigned long long desc, |
| 1823 | const detail::value<Context>* values) |
| 1824 | : desc_(desc), values_(values) {} |
| 1825 | basic_format_args(unsigned long long desc, const format_arg* args) |
| 1826 | : desc_(desc), args_(args) {} |
| 1827 | |
| 1828 | public: |
| 1829 | basic_format_args() : desc_(0) {} |
| 1830 | |
| 1831 | /** |
| 1832 | \rst |
| 1833 | Constructs a `basic_format_args` object from `~fmt::format_arg_store`. |
| 1834 | \endrst |
| 1835 | */ |
| 1836 | template <typename... Args> |
| 1837 | FMT_INLINE basic_format_args(const format_arg_store<Context, Args...>& store) |
| 1838 | : basic_format_args(store.desc, store.data_.args()) {} |
| 1839 | |
| 1840 | /** |
| 1841 | \rst |
| 1842 | Constructs a `basic_format_args` object from |
| 1843 | `~fmt::dynamic_format_arg_store`. |
| 1844 | \endrst |
| 1845 | */ |
| 1846 | FMT_INLINE basic_format_args(const dynamic_format_arg_store<Context>& store) |
| 1847 | : basic_format_args(store.get_types(), store.data()) {} |
| 1848 | |
| 1849 | /** |
| 1850 | \rst |
| 1851 | Constructs a `basic_format_args` object from a dynamic set of arguments. |
| 1852 | \endrst |
| 1853 | */ |
| 1854 | basic_format_args(const format_arg* args, int count) |
| 1855 | : basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count), |
| 1856 | args) {} |
| 1857 | |
| 1858 | /** Returns the argument with the specified id. */ |
| 1859 | format_arg get(int id) const { |
| 1860 | format_arg arg; |
| 1861 | if (!is_packed()) { |
| 1862 | if (id < max_size()) arg = args_[id]; |
| 1863 | return arg; |
| 1864 | } |
| 1865 | if (id >= detail::max_packed_args) return arg; |
| 1866 | arg.type_ = type(id); |
| 1867 | if (arg.type_ == detail::type::none_type) return arg; |
| 1868 | arg.value_ = values_[id]; |
| 1869 | return arg; |
| 1870 | } |
| 1871 | |
| 1872 | template <typename Char> format_arg get(basic_string_view<Char> name) const { |
| 1873 | int id = get_id(name); |
| 1874 | return id >= 0 ? get(id) : format_arg(); |
| 1875 | } |
| 1876 | |
| 1877 | template <typename Char> int get_id(basic_string_view<Char> name) const { |
| 1878 | if (!has_named_args()) return {}; |
| 1879 | const auto& named_args = |
| 1880 | (is_packed() ? values_[-1] : args_[-1].value_).named_args; |
| 1881 | for (size_t i = 0; i < named_args.size; ++i) { |
| 1882 | if (named_args.data[i].name == name) return named_args.data[i].id; |
| 1883 | } |
| 1884 | return -1; |
| 1885 | } |
| 1886 | |
| 1887 | int max_size() const { |
| 1888 | unsigned long long max_packed = detail::max_packed_args; |
| 1889 | return static_cast<int>(is_packed() ? max_packed |
| 1890 | : desc_ & ~detail::is_unpacked_bit); |
| 1891 | } |
| 1892 | }; |
| 1893 | |
| 1894 | /** An alias to ``basic_format_args<context>``. */ |
| 1895 | // It is a separate type rather than an alias to make symbols readable. |
| 1896 | struct format_args : basic_format_args<format_context> { |
| 1897 | template <typename... Args> |
| 1898 | FMT_INLINE format_args(const Args&... args) : basic_format_args(args...) {} |
| 1899 | }; |
| 1900 | struct wformat_args : basic_format_args<wformat_context> { |
| 1901 | using basic_format_args::basic_format_args; |
| 1902 | }; |
| 1903 | |
| 1904 | namespace detail { |
| 1905 | |
| 1906 | template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)> |
| 1907 | std::basic_string<Char> vformat( |
| 1908 | basic_string_view<Char> format_str, |
| 1909 | basic_format_args<buffer_context<type_identity_t<Char>>> args); |
| 1910 | |
| 1911 | FMT_API std::string vformat(string_view format_str, format_args args); |
| 1912 | |
| 1913 | template <typename Char> |
| 1914 | buffer_appender<Char> vformat_to( |
| 1915 | buffer<Char>& buf, basic_string_view<Char> format_str, |
| 1916 | basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args); |
| 1917 | |
| 1918 | template <typename Char, typename Args, |
| 1919 | FMT_ENABLE_IF(!std::is_same<Char, char>::value)> |
| 1920 | inline void vprint_mojibake(std::FILE*, basic_string_view<Char>, const Args&) {} |
| 1921 | |
| 1922 | FMT_API void vprint_mojibake(std::FILE*, string_view, format_args); |
| 1923 | #ifndef _WIN32 |
| 1924 | inline void vprint_mojibake(std::FILE*, string_view, format_args) {} |
| 1925 | #endif |
| 1926 | } // namespace detail |
| 1927 | |
| 1928 | /** Formats a string and writes the output to ``out``. */ |
| 1929 | // GCC 8 and earlier cannot handle std::back_insert_iterator<Container> with |
| 1930 | // vformat_to<ArgFormatter>(...) overload, so SFINAE on iterator type instead. |
| 1931 | template <typename OutputIt, typename S, typename Char = char_t<S>, |
| 1932 | FMT_ENABLE_IF(detail::is_output_iterator<OutputIt>::value)> |
| 1933 | OutputIt vformat_to( |
| 1934 | OutputIt out, const S& format_str, |
| 1935 | basic_format_args<buffer_context<type_identity_t<Char>>> args) { |
| 1936 | decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out)); |
| 1937 | detail::vformat_to(buf, to_string_view(format_str), args); |
| 1938 | return detail::get_iterator(buf); |
| 1939 | } |
| 1940 | |
| 1941 | /** |
| 1942 | \rst |
| 1943 | Formats arguments, writes the result to the output iterator ``out`` and returns |
| 1944 | the iterator past the end of the output range. |
| 1945 | |
| 1946 | **Example**:: |
| 1947 | |
| 1948 | std::vector<char> out; |
| 1949 | fmt::format_to(std::back_inserter(out), "{}", 42); |
| 1950 | \endrst |
| 1951 | */ |
| 1952 | template <typename OutputIt, typename S, typename... Args, |
| 1953 | FMT_ENABLE_IF(detail::is_output_iterator<OutputIt>::value&& |
| 1954 | detail::is_string<S>::value)> |
| 1955 | inline OutputIt format_to(OutputIt out, const S& format_str, Args&&... args) { |
| 1956 | const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); |
| 1957 | return vformat_to(out, to_string_view(format_str), vargs); |
| 1958 | } |
| 1959 | |
| 1960 | template <typename S, typename Char = char_t<S>> |
| 1961 | FMT_INLINE std::basic_string<Char> vformat( |
| 1962 | const S& format_str, |
| 1963 | basic_format_args<buffer_context<type_identity_t<Char>>> args) { |
| 1964 | return detail::vformat(to_string_view(format_str), args); |
| 1965 | } |
| 1966 | |
| 1967 | /** |
| 1968 | \rst |
| 1969 | Formats arguments and returns the result as a string. |
| 1970 | |
| 1971 | **Example**:: |
| 1972 | |
| 1973 | #include <fmt/core.h> |
| 1974 | std::string message = fmt::format("The answer is {}", 42); |
| 1975 | \endrst |
| 1976 | */ |
| 1977 | // Pass char_t as a default template parameter instead of using |
| 1978 | // std::basic_string<char_t<S>> to reduce the symbol size. |
| 1979 | template <typename S, typename... Args, typename Char = char_t<S>> |
| 1980 | FMT_INLINE std::basic_string<Char> format(const S& format_str, Args&&... args) { |
| 1981 | const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); |
| 1982 | return detail::vformat(to_string_view(format_str), vargs); |
| 1983 | } |
| 1984 | |
| 1985 | FMT_API void vprint(string_view, format_args); |
| 1986 | FMT_API void vprint(std::FILE*, string_view, format_args); |
| 1987 | |
| 1988 | /** |
| 1989 | \rst |
| 1990 | Formats ``args`` according to specifications in ``format_str`` and writes the |
| 1991 | output to the file ``f``. Strings are assumed to be Unicode-encoded unless the |
| 1992 | ``FMT_UNICODE`` macro is set to 0. |
| 1993 | |
| 1994 | **Example**:: |
| 1995 | |
| 1996 | fmt::print(stderr, "Don't {}!", "panic"); |
| 1997 | \endrst |
| 1998 | */ |
| 1999 | template <typename S, typename... Args, typename Char = char_t<S>> |
| 2000 | inline void print(std::FILE* f, const S& format_str, Args&&... args) { |
| 2001 | const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); |
| 2002 | return detail::is_unicode<Char>() |
| 2003 | ? vprint(f, to_string_view(format_str), vargs) |
| 2004 | : detail::vprint_mojibake(f, to_string_view(format_str), vargs); |
| 2005 | } |
| 2006 | |
| 2007 | /** |
| 2008 | \rst |
| 2009 | Formats ``args`` according to specifications in ``format_str`` and writes |
| 2010 | the output to ``stdout``. Strings are assumed to be Unicode-encoded unless |
| 2011 | the ``FMT_UNICODE`` macro is set to 0. |
| 2012 | |
| 2013 | **Example**:: |
| 2014 | |
| 2015 | fmt::print("Elapsed time: {0:.2f} seconds", 1.23); |
| 2016 | \endrst |
| 2017 | */ |
| 2018 | template <typename S, typename... Args, typename Char = char_t<S>> |
| 2019 | inline void print(const S& format_str, Args&&... args) { |
| 2020 | const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); |
| 2021 | return detail::is_unicode<Char>() |
| 2022 | ? vprint(to_string_view(format_str), vargs) |
| 2023 | : detail::vprint_mojibake(stdout, to_string_view(format_str), |
| 2024 | vargs); |
| 2025 | } |
| 2026 | FMT_END_NAMESPACE |
| 2027 | |
| 2028 | #endif // FMT_CORE_H_ |