]> git.proxmox.com Git - ceph.git/blame - ceph/src/fmt/include/fmt/core.h
import quincy beta 17.1.0
[ceph.git] / ceph / src / fmt / include / fmt / core.h
CommitLineData
20effc67 1// Formatting library for C++ - the core API for char/UTF-8
11fdf7f2
TL
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
11fdf7f2
TL
11#include <cstdio> // std::FILE
12#include <cstring>
13#include <iterator>
20effc67 14#include <limits>
11fdf7f2
TL
15#include <string>
16#include <type_traits>
17
18// The fmt library version in the form major * 10000 + minor * 100 + patch.
20effc67 19#define FMT_VERSION 70104
11fdf7f2 20
f67539c2
TL
21#ifdef __clang__
22# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
11fdf7f2 23#else
f67539c2 24# define FMT_CLANG_VERSION 0
11fdf7f2
TL
25#endif
26
27#if defined(__GNUC__) && !defined(__clang__)
9f95a23c 28# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
20effc67 29# define FMT_GCC_PRAGMA(arg) _Pragma(arg)
11fdf7f2 30#else
9f95a23c 31# define FMT_GCC_VERSION 0
20effc67 32# define FMT_GCC_PRAGMA(arg)
f67539c2
TL
33#endif
34
11fdf7f2 35#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
9f95a23c 36# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION
11fdf7f2 37#else
9f95a23c 38# define FMT_HAS_GXX_CXX11 0
11fdf7f2
TL
39#endif
40
20effc67
TL
41#if defined(__INTEL_COMPILER)
42# define FMT_ICC_VERSION __INTEL_COMPILER
43#else
44# define FMT_ICC_VERSION 0
45#endif
46
f67539c2
TL
47#ifdef __NVCC__
48# define FMT_NVCC __NVCC__
49#else
50# define FMT_NVCC 0
51#endif
52
11fdf7f2 53#ifdef _MSC_VER
9f95a23c 54# define FMT_MSC_VER _MSC_VER
20effc67 55# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__))
11fdf7f2 56#else
9f95a23c 57# define FMT_MSC_VER 0
20effc67 58# define FMT_MSC_WARNING(...)
f67539c2 59#endif
20effc67 60
f67539c2
TL
61#ifdef __has_feature
62# define FMT_HAS_FEATURE(x) __has_feature(x)
63#else
64# define FMT_HAS_FEATURE(x) 0
65#endif
66
67#if defined(__has_include) && !defined(__INTELLISENSE__) && \
20effc67 68 (!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600)
f67539c2
TL
69# define FMT_HAS_INCLUDE(x) __has_include(x)
70#else
71# define FMT_HAS_INCLUDE(x) 0
72#endif
73
74#ifdef __has_cpp_attribute
75# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
76#else
77# define FMT_HAS_CPP_ATTRIBUTE(x) 0
11fdf7f2
TL
78#endif
79
f67539c2
TL
80#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
81 (__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
82
83#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
84 (__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
85
11fdf7f2
TL
86// Check if relaxed C++14 constexpr is supported.
87// GCC doesn't allow throw in constexpr until version 6 (bug 67371).
88#ifndef FMT_USE_CONSTEXPR
9f95a23c
TL
89# define FMT_USE_CONSTEXPR \
90 (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \
f67539c2
TL
91 (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \
92 !FMT_NVCC && !FMT_ICC_VERSION
11fdf7f2
TL
93#endif
94#if FMT_USE_CONSTEXPR
9f95a23c
TL
95# define FMT_CONSTEXPR constexpr
96# define FMT_CONSTEXPR_DECL constexpr
11fdf7f2 97#else
20effc67 98# define FMT_CONSTEXPR
9f95a23c 99# define FMT_CONSTEXPR_DECL
11fdf7f2
TL
100#endif
101
20effc67
TL
102// Check if constexpr std::char_traits<>::compare,length is supported.
103#if defined(__GLIBCXX__)
104# if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \
105 _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE.
106# define FMT_CONSTEXPR_CHAR_TRAITS constexpr
107# endif
108#elif defined(_LIBCPP_VERSION) && __cplusplus >= 201703L && \
109 _LIBCPP_VERSION >= 4000
110# define FMT_CONSTEXPR_CHAR_TRAITS constexpr
111#elif FMT_MSC_VER >= 1914 && _MSVC_LANG >= 201703L
112# define FMT_CONSTEXPR_CHAR_TRAITS constexpr
113#endif
114#ifndef FMT_CONSTEXPR_CHAR_TRAITS
115# define FMT_CONSTEXPR_CHAR_TRAITS
116#endif
117
11fdf7f2 118#ifndef FMT_OVERRIDE
20effc67 119# if FMT_HAS_FEATURE(cxx_override_control) || \
9f95a23c
TL
120 (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
121# define FMT_OVERRIDE override
122# else
123# define FMT_OVERRIDE
124# endif
11fdf7f2
TL
125#endif
126
11fdf7f2 127// Check if exceptions are disabled.
11fdf7f2 128#ifndef FMT_EXCEPTIONS
9f95a23c
TL
129# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
130 FMT_MSC_VER && !_HAS_EXCEPTIONS
131# define FMT_EXCEPTIONS 0
132# else
133# define FMT_EXCEPTIONS 1
134# endif
11fdf7f2
TL
135#endif
136
137// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature).
138#ifndef FMT_USE_NOEXCEPT
9f95a23c 139# define FMT_USE_NOEXCEPT 0
11fdf7f2
TL
140#endif
141
142#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
143 (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
9f95a23c
TL
144# define FMT_DETECTED_NOEXCEPT noexcept
145# define FMT_HAS_CXX11_NOEXCEPT 1
11fdf7f2 146#else
9f95a23c
TL
147# define FMT_DETECTED_NOEXCEPT throw()
148# define FMT_HAS_CXX11_NOEXCEPT 0
11fdf7f2
TL
149#endif
150
151#ifndef FMT_NOEXCEPT
9f95a23c
TL
152# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT
153# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT
154# else
155# define FMT_NOEXCEPT
156# endif
157#endif
158
f67539c2
TL
159// [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code
160// warnings.
161#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \
162 !FMT_NVCC
163# define FMT_NORETURN [[noreturn]]
164#else
165# define FMT_NORETURN
166#endif
167
20effc67
TL
168#ifndef FMT_MAYBE_UNUSED
169# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused)
170# define FMT_MAYBE_UNUSED [[maybe_unused]]
9f95a23c 171# else
20effc67 172# define FMT_MAYBE_UNUSED
9f95a23c 173# endif
11fdf7f2
TL
174#endif
175
20effc67
TL
176#if __cplusplus == 201103L || __cplusplus == 201402L
177# if defined(__INTEL_COMPILER) || defined(__PGI)
178# define FMT_FALLTHROUGH
179# elif defined(__clang__)
180# define FMT_FALLTHROUGH [[clang::fallthrough]]
181# elif FMT_GCC_VERSION >= 700 && \
182 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
183# define FMT_FALLTHROUGH [[gnu::fallthrough]]
184# else
185# define FMT_FALLTHROUGH
186# endif
187#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) || \
188 (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
189# define FMT_FALLTHROUGH [[fallthrough]]
f67539c2 190#else
20effc67
TL
191# define FMT_FALLTHROUGH
192#endif
193
194#ifndef FMT_USE_FLOAT
195# define FMT_USE_FLOAT 1
196#endif
197#ifndef FMT_USE_DOUBLE
198# define FMT_USE_DOUBLE 1
199#endif
200#ifndef FMT_USE_LONG_DOUBLE
201# define FMT_USE_LONG_DOUBLE 1
f67539c2
TL
202#endif
203
204#ifndef FMT_INLINE
20effc67 205# if FMT_GCC_VERSION || FMT_CLANG_VERSION
f67539c2
TL
206# define FMT_INLINE inline __attribute__((always_inline))
207# else
208# define FMT_INLINE inline
209# endif
210#endif
211
20effc67 212#ifndef FMT_USE_INLINE_NAMESPACES
9f95a23c 213# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
20effc67
TL
214 (FMT_MSC_VER >= 1900 && (!defined(_MANAGED) || !_MANAGED))
215# define FMT_USE_INLINE_NAMESPACES 1
216# else
217# define FMT_USE_INLINE_NAMESPACES 0
218# endif
219#endif
220
221#ifndef FMT_BEGIN_NAMESPACE
222# if FMT_USE_INLINE_NAMESPACES
9f95a23c
TL
223# define FMT_INLINE_NAMESPACE inline namespace
224# define FMT_END_NAMESPACE \
225 } \
226 }
227# else
228# define FMT_INLINE_NAMESPACE namespace
229# define FMT_END_NAMESPACE \
230 } \
20effc67 231 using namespace v7; \
9f95a23c
TL
232 }
233# endif
234# define FMT_BEGIN_NAMESPACE \
235 namespace fmt { \
20effc67
TL
236 FMT_INLINE_NAMESPACE v7 {
237#endif
238
239#ifndef FMT_MODULE_EXPORT
240# define FMT_MODULE_EXPORT
241# define FMT_MODULE_EXPORT_BEGIN
242# define FMT_MODULE_EXPORT_END
243# define FMT_BEGIN_DETAIL_NAMESPACE namespace detail {
244# define FMT_END_DETAIL_NAMESPACE }
11fdf7f2
TL
245#endif
246
247#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
20effc67 248# define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275)
9f95a23c
TL
249# ifdef FMT_EXPORT
250# define FMT_API __declspec(dllexport)
251# elif defined(FMT_SHARED)
252# define FMT_API __declspec(dllimport)
253# endif
f67539c2
TL
254#else
255# define FMT_CLASS_API
20effc67
TL
256# if defined(FMT_EXPORT) || defined(FMT_SHARED)
257# if defined(__GNUC__) || defined(__clang__)
258# define FMT_API __attribute__((visibility("default")))
259# endif
f67539c2
TL
260# endif
261#endif
20effc67
TL
262#ifndef FMT_API
263# define FMT_API
11fdf7f2
TL
264#endif
265
20effc67
TL
266#if FMT_GCC_VERSION
267# define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden")))
f67539c2 268#else
20effc67 269# define FMT_GCC_VISIBILITY_HIDDEN
11fdf7f2
TL
270#endif
271
272// libc++ supports string_view in pre-c++17.
9f95a23c
TL
273#if (FMT_HAS_INCLUDE(<string_view>) && \
274 (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
11fdf7f2 275 (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
9f95a23c 276# include <string_view>
f67539c2
TL
277# define FMT_USE_STRING_VIEW
278#elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L
9f95a23c 279# include <experimental/string_view>
f67539c2 280# define FMT_USE_EXPERIMENTAL_STRING_VIEW
11fdf7f2
TL
281#endif
282
f67539c2
TL
283#ifndef FMT_UNICODE
284# define FMT_UNICODE !FMT_MSC_VER
285#endif
20effc67
TL
286
287#ifndef FMT_CONSTEVAL
288# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \
289 __cplusplus > 201703L) || \
290 (defined(__cpp_consteval) && \
291 !FMT_MSC_VER) // consteval is broken in MSVC.
292# define FMT_CONSTEVAL consteval
293# define FMT_HAS_CONSTEVAL
294# else
295# define FMT_CONSTEVAL
296# endif
297#endif
298
299#ifndef FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
300# if defined(__cpp_nontype_template_args) && \
301 ((FMT_GCC_VERSION >= 903 && __cplusplus >= 201709L) || \
302 __cpp_nontype_template_args >= 201911L)
303# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 1
304# else
305# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0
306# endif
307#endif
308
309// Enable minimal optimizations for more compact code in debug mode.
310FMT_GCC_PRAGMA("GCC push_options")
311#ifndef __OPTIMIZE__
312FMT_GCC_PRAGMA("GCC optimize(\"Og\")")
11fdf7f2 313#endif
9f95a23c 314
11fdf7f2 315FMT_BEGIN_NAMESPACE
20effc67 316FMT_MODULE_EXPORT_BEGIN
11fdf7f2 317
f67539c2
TL
318// Implementations of enable_if_t and other metafunctions for older systems.
319template <bool B, class T = void>
320using enable_if_t = typename std::enable_if<B, T>::type;
321template <bool B, class T, class F>
322using conditional_t = typename std::conditional<B, T, F>::type;
323template <bool B> using bool_constant = std::integral_constant<bool, B>;
324template <typename T>
325using remove_reference_t = typename std::remove_reference<T>::type;
11fdf7f2 326template <typename T>
f67539c2
TL
327using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
328template <typename T> struct type_identity { using type = T; };
329template <typename T> using type_identity_t = typename type_identity<T>::type;
330
20effc67
TL
331struct monostate {
332 constexpr monostate() {}
333};
f67539c2
TL
334
335// An enable_if helper to be used in template parameters which results in much
336// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
337// to workaround a bug in MSVC 2019 (see #1140 and #1186).
20effc67
TL
338#ifdef FMT_DOC
339# define FMT_ENABLE_IF(...)
340#else
341# define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0
342#endif
f67539c2 343
20effc67 344FMT_BEGIN_DETAIL_NAMESPACE
f67539c2 345
20effc67
TL
346constexpr FMT_INLINE auto is_constant_evaluated() FMT_NOEXCEPT -> bool {
347#ifdef __cpp_lib_is_constant_evaluated
348 return std::is_constant_evaluated();
349#else
350 return false;
351#endif
352}
353
354// A function to suppress "conditional expression is constant" warnings.
355template <typename T> constexpr auto const_check(T value) -> T { return value; }
f67539c2
TL
356
357FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
358 const char* message);
11fdf7f2 359
f67539c2
TL
360#ifndef FMT_ASSERT
361# ifdef NDEBUG
362// FMT_ASSERT is not empty to avoid -Werror=empty-body.
363# define FMT_ASSERT(condition, message) ((void)0)
364# else
365# define FMT_ASSERT(condition, message) \
366 ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
367 ? (void)0 \
368 : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
369# endif
370#endif
371
372#if defined(FMT_USE_STRING_VIEW)
373template <typename Char> using std_string_view = std::basic_string_view<Char>;
374#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
375template <typename Char>
376using std_string_view = std::experimental::basic_string_view<Char>;
377#else
378template <typename T> struct std_string_view {};
379#endif
11fdf7f2 380
f67539c2
TL
381#ifdef FMT_USE_INT128
382// Do nothing.
20effc67
TL
383#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \
384 !(FMT_CLANG_VERSION && FMT_MSC_VER)
f67539c2
TL
385# define FMT_USE_INT128 1
386using int128_t = __int128_t;
387using uint128_t = __uint128_t;
20effc67
TL
388template <typename T> inline auto convert_for_visit(T value) -> T {
389 return value;
390}
9f95a23c 391#else
f67539c2
TL
392# define FMT_USE_INT128 0
393#endif
394#if !FMT_USE_INT128
20effc67
TL
395enum class int128_t {};
396enum class uint128_t {};
397// Reduce template instantiations.
398template <typename T> inline auto convert_for_visit(T) -> monostate {
399 return {};
400}
9f95a23c 401#endif
11fdf7f2 402
f67539c2 403// Casts a nonnegative integer to unsigned.
11fdf7f2 404template <typename Int>
20effc67
TL
405FMT_CONSTEXPR auto to_unsigned(Int value) ->
406 typename std::make_unsigned<Int>::type {
11fdf7f2
TL
407 FMT_ASSERT(value >= 0, "negative value");
408 return static_cast<typename std::make_unsigned<Int>::type>(value);
409}
410
20effc67 411FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5";
eafe8130 412
20effc67
TL
413constexpr auto is_utf8() -> bool {
414 // Avoid buggy sign extensions in MSVC's constant evaluation mode.
415 // https://developercommunity.visualstudio.com/t/C-difference-in-behavior-for-unsigned/1233612
416 using uchar = unsigned char;
417 return FMT_UNICODE || (sizeof(micro) == 3 && uchar(micro[0]) == 0xC2 &&
418 uchar(micro[1]) == 0xB5);
11fdf7f2 419}
20effc67 420FMT_END_DETAIL_NAMESPACE
eafe8130 421
11fdf7f2
TL
422/**
423 An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
424 subset of the API. ``fmt::basic_string_view`` is used for format strings even
425 if ``std::string_view`` is available to prevent issues when a library is
426 compiled with a different ``-std`` option than the client code (which is not
427 recommended).
428 */
9f95a23c 429template <typename Char> class basic_string_view {
11fdf7f2 430 private:
9f95a23c 431 const Char* data_;
11fdf7f2
TL
432 size_t size_;
433
434 public:
f67539c2
TL
435 using value_type = Char;
436 using iterator = const Char*;
11fdf7f2 437
f67539c2 438 constexpr basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {}
11fdf7f2
TL
439
440 /** Constructs a string reference object from a C string and a size. */
f67539c2 441 constexpr basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT
9f95a23c
TL
442 : data_(s),
443 size_(count) {}
11fdf7f2
TL
444
445 /**
446 \rst
447 Constructs a string reference object from a C string computing
448 the size with ``std::char_traits<Char>::length``.
449 \endrst
450 */
20effc67
TL
451 FMT_CONSTEXPR_CHAR_TRAITS
452 FMT_INLINE
453 basic_string_view(const Char* s) : data_(s) {
454 if (detail::const_check(std::is_same<Char, char>::value &&
455 !detail::is_constant_evaluated()))
456 size_ = std::strlen(reinterpret_cast<const char*>(s));
457 else
458 size_ = std::char_traits<Char>::length(s);
459 }
11fdf7f2
TL
460
461 /** Constructs a string reference from a ``std::basic_string`` object. */
f67539c2
TL
462 template <typename Traits, typename Alloc>
463 FMT_CONSTEXPR basic_string_view(
464 const std::basic_string<Char, Traits, Alloc>& s) FMT_NOEXCEPT
9f95a23c
TL
465 : data_(s.data()),
466 size_(s.size()) {}
f67539c2
TL
467
468 template <typename S, FMT_ENABLE_IF(std::is_same<
469 S, detail::std_string_view<Char>>::value)>
470 FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()),
471 size_(s.size()) {}
11fdf7f2
TL
472
473 /** Returns a pointer to the string data. */
20effc67 474 constexpr auto data() const -> const Char* { return data_; }
11fdf7f2
TL
475
476 /** Returns the string size. */
20effc67 477 constexpr auto size() const -> size_t { return size_; }
11fdf7f2 478
20effc67
TL
479 constexpr auto begin() const -> iterator { return data_; }
480 constexpr auto end() const -> iterator { return data_ + size_; }
f67539c2 481
20effc67
TL
482 constexpr auto operator[](size_t pos) const -> const Char& {
483 return data_[pos];
484 }
11fdf7f2
TL
485
486 FMT_CONSTEXPR void remove_prefix(size_t n) {
487 data_ += n;
488 size_ -= n;
489 }
490
491 // Lexicographically compare this string reference to other.
20effc67 492 FMT_CONSTEXPR_CHAR_TRAITS auto compare(basic_string_view other) const -> int {
11fdf7f2
TL
493 size_t str_size = size_ < other.size_ ? size_ : other.size_;
494 int result = std::char_traits<Char>::compare(data_, other.data_, str_size);
495 if (result == 0)
496 result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
497 return result;
498 }
499
20effc67
TL
500 FMT_CONSTEXPR_CHAR_TRAITS friend auto operator==(basic_string_view lhs,
501 basic_string_view rhs)
502 -> bool {
11fdf7f2
TL
503 return lhs.compare(rhs) == 0;
504 }
20effc67 505 friend auto operator!=(basic_string_view lhs, basic_string_view rhs) -> bool {
11fdf7f2
TL
506 return lhs.compare(rhs) != 0;
507 }
20effc67 508 friend auto operator<(basic_string_view lhs, basic_string_view rhs) -> bool {
11fdf7f2
TL
509 return lhs.compare(rhs) < 0;
510 }
20effc67 511 friend auto operator<=(basic_string_view lhs, basic_string_view rhs) -> bool {
11fdf7f2
TL
512 return lhs.compare(rhs) <= 0;
513 }
20effc67 514 friend auto operator>(basic_string_view lhs, basic_string_view rhs) -> bool {
11fdf7f2
TL
515 return lhs.compare(rhs) > 0;
516 }
20effc67 517 friend auto operator>=(basic_string_view lhs, basic_string_view rhs) -> bool {
11fdf7f2
TL
518 return lhs.compare(rhs) >= 0;
519 }
520};
521
f67539c2 522using string_view = basic_string_view<char>;
f67539c2
TL
523
524/** Specifies if ``T`` is a character type. Can be specialized by users. */
525template <typename T> struct is_char : std::false_type {};
526template <> struct is_char<char> : std::true_type {};
11fdf7f2 527
eafe8130
TL
528/**
529 \rst
f67539c2
TL
530 Returns a string view of `s`. In order to add custom string type support to
531 {fmt} provide an overload of `to_string_view` for it in the same namespace as
532 the type for the argument-dependent lookup to work.
eafe8130
TL
533
534 **Example**::
535
536 namespace my_ns {
f67539c2 537 inline string_view to_string_view(const my_string& s) {
9f95a23c 538 return {s.data(), s.length()};
eafe8130
TL
539 }
540 }
eafe8130
TL
541 std::string message = fmt::format(my_string("The answer is {}"), 42);
542 \endrst
543 */
f67539c2 544template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
20effc67 545FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view<Char> {
9f95a23c
TL
546 return s;
547}
eafe8130 548
f67539c2 549template <typename Char, typename Traits, typename Alloc>
20effc67
TL
550inline auto to_string_view(const std::basic_string<Char, Traits, Alloc>& s)
551 -> basic_string_view<Char> {
f67539c2 552 return s;
9f95a23c 553}
eafe8130
TL
554
555template <typename Char>
20effc67
TL
556constexpr auto to_string_view(basic_string_view<Char> s)
557 -> basic_string_view<Char> {
9f95a23c
TL
558 return s;
559}
eafe8130 560
f67539c2
TL
561template <typename Char,
562 FMT_ENABLE_IF(!std::is_empty<detail::std_string_view<Char>>::value)>
20effc67
TL
563inline auto to_string_view(detail::std_string_view<Char> s)
564 -> basic_string_view<Char> {
9f95a23c
TL
565 return s;
566}
eafe8130
TL
567
568// A base class for compile-time strings. It is defined in the fmt namespace to
20effc67 569// make formatting functions visible via ADL, e.g. format(FMT_STRING("{}"), 42).
eafe8130
TL
570struct compile_string {};
571
572template <typename S>
573struct is_compile_string : std::is_base_of<compile_string, S> {};
574
9f95a23c 575template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
20effc67
TL
576constexpr auto to_string_view(const S& s)
577 -> basic_string_view<typename S::char_type> {
578 return basic_string_view<typename S::char_type>(s);
9f95a23c 579}
eafe8130 580
20effc67
TL
581FMT_BEGIN_DETAIL_NAMESPACE
582
f67539c2 583void to_string_view(...);
20effc67 584using fmt::v7::to_string_view;
f67539c2
TL
585
586// Specifies whether S is a string type convertible to fmt::basic_string_view.
587// It should be a constexpr function but MSVC 2017 fails to compile it in
588// enable_if and MSVC 2015 fails to compile it as an alias template.
589template <typename S>
590struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> {
591};
592
593template <typename S, typename = void> struct char_t_impl {};
594template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
595 using result = decltype(to_string_view(std::declval<S>()));
596 using type = typename result::value_type;
597};
598
20effc67
TL
599// Reports a compile-time error if S is not a valid format string.
600template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
601FMT_INLINE void check_format_string(const S&) {
602#ifdef FMT_ENFORCE_COMPILE_STRING
603 static_assert(is_compile_string<S>::value,
604 "FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
605 "FMT_STRING.");
606#endif
607}
608template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
609void check_format_string(S);
610
f67539c2
TL
611struct error_handler {
612 constexpr error_handler() = default;
613 constexpr error_handler(const error_handler&) = default;
614
615 // This function is intentionally not constexpr to give a compile-time error.
616 FMT_NORETURN FMT_API void on_error(const char* message);
617};
20effc67 618FMT_END_DETAIL_NAMESPACE
f67539c2
TL
619
620/** String's character type. */
621template <typename S> using char_t = typename detail::char_t_impl<S>::type;
622
623/**
624 \rst
625 Parsing context consisting of a format string range being parsed and an
626 argument counter for automatic indexing.
20effc67 627 You can use the ```format_parse_context`` type alias for ``char`` instead.
f67539c2
TL
628 \endrst
629 */
630template <typename Char, typename ErrorHandler = detail::error_handler>
631class basic_format_parse_context : private ErrorHandler {
9f95a23c
TL
632 private:
633 basic_string_view<Char> format_str_;
634 int next_arg_id_;
11fdf7f2 635
9f95a23c 636 public:
f67539c2
TL
637 using char_type = Char;
638 using iterator = typename basic_string_view<Char>::iterator;
9f95a23c 639
f67539c2 640 explicit constexpr basic_format_parse_context(
20effc67
TL
641 basic_string_view<Char> format_str, ErrorHandler eh = {},
642 int next_arg_id = 0)
643 : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {}
9f95a23c 644
f67539c2
TL
645 /**
646 Returns an iterator to the beginning of the format string range being
647 parsed.
648 */
20effc67
TL
649 constexpr auto begin() const FMT_NOEXCEPT -> iterator {
650 return format_str_.begin();
651 }
9f95a23c 652
f67539c2
TL
653 /**
654 Returns an iterator past the end of the format string range being parsed.
655 */
20effc67
TL
656 constexpr auto end() const FMT_NOEXCEPT -> iterator {
657 return format_str_.end();
658 }
9f95a23c 659
f67539c2 660 /** Advances the begin iterator to ``it``. */
9f95a23c 661 FMT_CONSTEXPR void advance_to(iterator it) {
f67539c2 662 format_str_.remove_prefix(detail::to_unsigned(it - begin()));
9f95a23c
TL
663 }
664
f67539c2
TL
665 /**
666 Reports an error if using the manual argument indexing; otherwise returns
667 the next argument index and switches to the automatic indexing.
668 */
20effc67 669 FMT_CONSTEXPR auto next_arg_id() -> int {
f67539c2
TL
670 // Don't check if the argument id is valid to avoid overhead and because it
671 // will be checked during formatting anyway.
672 if (next_arg_id_ >= 0) return next_arg_id_++;
673 on_error("cannot switch from manual to automatic argument indexing");
674 return 0;
675 }
9f95a23c 676
f67539c2
TL
677 /**
678 Reports an error if using the automatic argument indexing; otherwise
679 switches to the manual indexing.
680 */
681 FMT_CONSTEXPR void check_arg_id(int) {
682 if (next_arg_id_ > 0)
9f95a23c 683 on_error("cannot switch from automatic to manual argument indexing");
f67539c2
TL
684 else
685 next_arg_id_ = -1;
9f95a23c
TL
686 }
687
688 FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
689
690 FMT_CONSTEXPR void on_error(const char* message) {
691 ErrorHandler::on_error(message);
692 }
693
20effc67 694 constexpr auto error_handler() const -> ErrorHandler { return *this; }
9f95a23c
TL
695};
696
f67539c2 697using format_parse_context = basic_format_parse_context<char>;
9f95a23c
TL
698
699template <typename Context> class basic_format_arg;
700template <typename Context> class basic_format_args;
f67539c2 701template <typename Context> class dynamic_format_arg_store;
11fdf7f2 702
11fdf7f2
TL
703// A formatter for objects of type T.
704template <typename T, typename Char = char, typename Enable = void>
705struct formatter {
f67539c2
TL
706 // A deleted default constructor indicates a disabled formatter.
707 formatter() = delete;
708};
709
710// Specifies if T has an enabled formatter specialization. A type can be
711// formattable even if it doesn't have a formatter e.g. via a conversion.
712template <typename T, typename Context>
713using has_formatter =
714 std::is_constructible<typename Context::template formatter_type<T>>;
715
20effc67
TL
716// Checks whether T is a container with contiguous storage.
717template <typename T> struct is_contiguous : std::false_type {};
718template <typename Char>
719struct is_contiguous<std::basic_string<Char>> : std::true_type {};
720
721class appender;
722
723FMT_BEGIN_DETAIL_NAMESPACE
724
725// Extracts a reference to the container from back_insert_iterator.
726template <typename Container>
727inline auto get_container(std::back_insert_iterator<Container> it)
728 -> Container& {
729 using bi_iterator = std::back_insert_iterator<Container>;
730 struct accessor : bi_iterator {
731 accessor(bi_iterator iter) : bi_iterator(iter) {}
732 using bi_iterator::container;
733 };
734 return *accessor(it).container;
735}
736
737template <typename Char, typename InputIt, typename OutputIt>
738FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out)
739 -> OutputIt {
740 while (begin != end) *out++ = static_cast<Char>(*begin++);
741 return out;
742}
743
744template <typename Char, FMT_ENABLE_IF(std::is_same<Char, char>::value)>
745FMT_CONSTEXPR auto copy_str(const Char* begin, const Char* end, Char* out)
746 -> Char* {
747 if (is_constant_evaluated())
748 return copy_str<Char, const Char*, Char*>(begin, end, out);
749 auto size = to_unsigned(end - begin);
750 memcpy(out, begin, size);
751 return out + size;
752}
f67539c2
TL
753
754/**
755 \rst
756 A contiguous memory buffer with an optional growing ability. It is an internal
757 class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`.
758 \endrst
759 */
760template <typename T> class buffer {
761 private:
762 T* ptr_;
763 size_t size_;
764 size_t capacity_;
765
766 protected:
767 // Don't initialize ptr_ since it is not accessed to save a few cycles.
20effc67 768 FMT_MSC_WARNING(suppress : 26495)
f67539c2
TL
769 buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}
770
771 buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT
772 : ptr_(p),
773 size_(sz),
774 capacity_(cap) {}
775
20effc67
TL
776 ~buffer() = default;
777 buffer(buffer&&) = default;
778
f67539c2
TL
779 /** Sets the buffer data and capacity. */
780 void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT {
781 ptr_ = buf_data;
782 capacity_ = buf_capacity;
783 }
784
785 /** Increases the buffer capacity to hold at least *capacity* elements. */
786 virtual void grow(size_t capacity) = 0;
787
788 public:
789 using value_type = T;
790 using const_reference = const T&;
791
792 buffer(const buffer&) = delete;
793 void operator=(const buffer&) = delete;
f67539c2 794
20effc67
TL
795 auto begin() FMT_NOEXCEPT -> T* { return ptr_; }
796 auto end() FMT_NOEXCEPT -> T* { return ptr_ + size_; }
f67539c2 797
20effc67
TL
798 auto begin() const FMT_NOEXCEPT -> const T* { return ptr_; }
799 auto end() const FMT_NOEXCEPT -> const T* { return ptr_ + size_; }
f67539c2
TL
800
801 /** Returns the size of this buffer. */
20effc67 802 auto size() const FMT_NOEXCEPT -> size_t { return size_; }
f67539c2
TL
803
804 /** Returns the capacity of this buffer. */
20effc67 805 auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; }
f67539c2
TL
806
807 /** Returns a pointer to the buffer data. */
20effc67 808 auto data() FMT_NOEXCEPT -> T* { return ptr_; }
f67539c2
TL
809
810 /** Returns a pointer to the buffer data. */
20effc67 811 auto data() const FMT_NOEXCEPT -> const T* { return ptr_; }
f67539c2
TL
812
813 /** Clears this buffer. */
814 void clear() { size_ = 0; }
815
20effc67
TL
816 // Tries resizing the buffer to contain *count* elements. If T is a POD type
817 // the new elements may not be initialized.
818 void try_resize(size_t count) {
819 try_reserve(count);
820 size_ = count <= capacity_ ? count : capacity_;
821 }
822
823 // Tries increasing the buffer capacity to *new_capacity*. It can increase the
824 // capacity by a smaller amount than requested but guarantees there is space
825 // for at least one additional element either by increasing the capacity or by
826 // flushing the buffer if it is full.
827 void try_reserve(size_t new_capacity) {
f67539c2
TL
828 if (new_capacity > capacity_) grow(new_capacity);
829 }
830
831 void push_back(const T& value) {
20effc67 832 try_reserve(size_ + 1);
f67539c2
TL
833 ptr_[size_++] = value;
834 }
835
836 /** Appends data to the end of the buffer. */
837 template <typename U> void append(const U* begin, const U* end);
838
20effc67
TL
839 template <typename I> auto operator[](I index) -> T& { return ptr_[index]; }
840 template <typename I> auto operator[](I index) const -> const T& {
f67539c2
TL
841 return ptr_[index];
842 }
11fdf7f2
TL
843};
844
20effc67
TL
845struct buffer_traits {
846 explicit buffer_traits(size_t) {}
847 auto count() const -> size_t { return 0; }
848 auto limit(size_t size) -> size_t { return size; }
849};
850
851class fixed_buffer_traits {
852 private:
853 size_t count_ = 0;
854 size_t limit_;
855
856 public:
857 explicit fixed_buffer_traits(size_t limit) : limit_(limit) {}
858 auto count() const -> size_t { return count_; }
859 auto limit(size_t size) -> size_t {
860 size_t n = limit_ > count_ ? limit_ - count_ : 0;
861 count_ += size;
862 return size < n ? size : n;
863 }
864};
865
866// A buffer that writes to an output iterator when flushed.
867template <typename OutputIt, typename T, typename Traits = buffer_traits>
868class iterator_buffer final : public Traits, public buffer<T> {
869 private:
870 OutputIt out_;
871 enum { buffer_size = 256 };
872 T data_[buffer_size];
873
874 protected:
875 void grow(size_t) final FMT_OVERRIDE {
876 if (this->size() == buffer_size) flush();
877 }
878
879 void flush() {
880 auto size = this->size();
881 this->clear();
882 out_ = copy_str<T>(data_, data_ + this->limit(size), out_);
883 }
884
885 public:
886 explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
887 : Traits(n), buffer<T>(data_, 0, buffer_size), out_(out) {}
888 iterator_buffer(iterator_buffer&& other)
889 : Traits(other), buffer<T>(data_, 0, buffer_size), out_(other.out_) {}
890 ~iterator_buffer() { flush(); }
891
892 auto out() -> OutputIt {
893 flush();
894 return out_;
895 }
896 auto count() const -> size_t { return Traits::count() + this->size(); }
897};
898
899template <typename T> class iterator_buffer<T*, T> final : public buffer<T> {
900 protected:
901 void grow(size_t) final FMT_OVERRIDE {}
902
903 public:
904 explicit iterator_buffer(T* out, size_t = 0) : buffer<T>(out, 0, ~size_t()) {}
905
906 auto out() -> T* { return &*this->end(); }
907};
908
909// A buffer that writes to a container with the contiguous storage.
f67539c2 910template <typename Container>
20effc67
TL
911class iterator_buffer<std::back_insert_iterator<Container>,
912 enable_if_t<is_contiguous<Container>::value,
913 typename Container::value_type>>
914 final : public buffer<typename Container::value_type> {
f67539c2
TL
915 private:
916 Container& container_;
917
918 protected:
20effc67 919 void grow(size_t capacity) final FMT_OVERRIDE {
f67539c2
TL
920 container_.resize(capacity);
921 this->set(&container_[0], capacity);
922 }
11fdf7f2 923
f67539c2 924 public:
20effc67 925 explicit iterator_buffer(Container& c)
f67539c2 926 : buffer<typename Container::value_type>(c.size()), container_(c) {}
20effc67
TL
927 explicit iterator_buffer(std::back_insert_iterator<Container> out, size_t = 0)
928 : iterator_buffer(get_container(out)) {}
929 auto out() -> std::back_insert_iterator<Container> {
930 return std::back_inserter(container_);
931 }
f67539c2 932};
11fdf7f2 933
20effc67
TL
934// A buffer that counts the number of code units written discarding the output.
935template <typename T = char> class counting_buffer final : public buffer<T> {
936 private:
937 enum { buffer_size = 256 };
938 T data_[buffer_size];
939 size_t count_ = 0;
940
941 protected:
942 void grow(size_t) final FMT_OVERRIDE {
943 if (this->size() != buffer_size) return;
944 count_ += this->size();
945 this->clear();
946 }
947
948 public:
949 counting_buffer() : buffer<T>(data_, 0, buffer_size) {}
950
951 auto count() -> size_t { return count_ + this->size(); }
952};
953
954template <typename T>
955using buffer_appender = conditional_t<std::is_same<T, char>::value, appender,
956 std::back_insert_iterator<buffer<T>>>;
957
958// Maps an output iterator to a buffer.
959template <typename T, typename OutputIt>
960auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
961 return iterator_buffer<OutputIt, T>(out);
962}
963
964template <typename Buffer>
965auto get_iterator(Buffer& buf) -> decltype(buf.out()) {
966 return buf.out();
967}
968template <typename T> auto get_iterator(buffer<T>& buf) -> buffer_appender<T> {
969 return buffer_appender<T>(buf);
f67539c2 970}
9f95a23c
TL
971
972template <typename T, typename Char = char, typename Enable = void>
973struct fallback_formatter {
f67539c2 974 fallback_formatter() = delete;
9f95a23c
TL
975};
976
f67539c2 977// Specifies if T has an enabled fallback_formatter specialization.
20effc67 978template <typename T, typename Char>
f67539c2 979using has_fallback_formatter =
20effc67 980 std::is_constructible<fallback_formatter<T, Char>>;
f67539c2
TL
981
982struct view {};
983
984template <typename Char, typename T> struct named_arg : view {
985 const Char* name;
986 const T& value;
987 named_arg(const Char* n, const T& v) : name(n), value(v) {}
9f95a23c 988};
11fdf7f2 989
f67539c2
TL
990template <typename Char> struct named_arg_info {
991 const Char* name;
992 int id;
993};
994
995template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
996struct arg_data {
997 // args_[0].named_args points to named_args_ to avoid bloating format_args.
20effc67
TL
998 // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
999 T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)];
f67539c2
TL
1000 named_arg_info<Char> named_args_[NUM_NAMED_ARGS];
1001
1002 template <typename... U>
1003 arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {}
1004 arg_data(const arg_data& other) = delete;
20effc67
TL
1005 auto args() const -> const T* { return args_ + 1; }
1006 auto named_args() -> named_arg_info<Char>* { return named_args_; }
9f95a23c 1007};
11fdf7f2 1008
f67539c2
TL
1009template <typename T, typename Char, size_t NUM_ARGS>
1010struct arg_data<T, Char, NUM_ARGS, 0> {
20effc67
TL
1011 // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
1012 T args_[NUM_ARGS != 0 ? NUM_ARGS : +1];
9f95a23c 1013
f67539c2 1014 template <typename... U>
20effc67
TL
1015 FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {}
1016 FMT_CONSTEXPR FMT_INLINE auto args() const -> const T* { return args_; }
1017 FMT_CONSTEXPR FMT_INLINE auto named_args() -> std::nullptr_t {
1018 return nullptr;
1019 }
11fdf7f2
TL
1020};
1021
f67539c2
TL
1022template <typename Char>
1023inline void init_named_args(named_arg_info<Char>*, int, int) {}
1024
20effc67
TL
1025template <typename T> struct is_named_arg : std::false_type {};
1026template <typename T> struct is_statically_named_arg : std::false_type {};
1027
1028template <typename T, typename Char>
1029struct is_named_arg<named_arg<Char, T>> : std::true_type {};
1030
1031template <typename Char, typename T, typename... Tail,
1032 FMT_ENABLE_IF(!is_named_arg<T>::value)>
f67539c2
TL
1033void init_named_args(named_arg_info<Char>* named_args, int arg_count,
1034 int named_arg_count, const T&, const Tail&... args) {
1035 init_named_args(named_args, arg_count + 1, named_arg_count, args...);
1036}
1037
20effc67
TL
1038template <typename Char, typename T, typename... Tail,
1039 FMT_ENABLE_IF(is_named_arg<T>::value)>
f67539c2 1040void init_named_args(named_arg_info<Char>* named_args, int arg_count,
20effc67 1041 int named_arg_count, const T& arg, const Tail&... args) {
f67539c2
TL
1042 named_args[named_arg_count++] = {arg.name, arg_count};
1043 init_named_args(named_args, arg_count + 1, named_arg_count, args...);
1044}
1045
1046template <typename... Args>
20effc67
TL
1047FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int,
1048 const Args&...) {}
f67539c2 1049
20effc67
TL
1050template <bool B = false> constexpr auto count() -> size_t { return B ? 1 : 0; }
1051template <bool B1, bool B2, bool... Tail> constexpr auto count() -> size_t {
f67539c2
TL
1052 return (B1 ? 1 : 0) + count<B2, Tail...>();
1053}
11fdf7f2 1054
20effc67 1055template <typename... Args> constexpr auto count_named_args() -> size_t {
f67539c2
TL
1056 return count<is_named_arg<Args>::value...>();
1057}
11fdf7f2 1058
f67539c2 1059enum class type {
9f95a23c 1060 none_type,
11fdf7f2 1061 // Integer types should go first,
9f95a23c
TL
1062 int_type,
1063 uint_type,
1064 long_long_type,
1065 ulong_long_type,
f67539c2
TL
1066 int128_type,
1067 uint128_type,
9f95a23c
TL
1068 bool_type,
1069 char_type,
11fdf7f2
TL
1070 last_integer_type = char_type,
1071 // followed by floating-point types.
f67539c2 1072 float_type,
9f95a23c
TL
1073 double_type,
1074 long_double_type,
1075 last_numeric_type = long_double_type,
1076 cstring_type,
1077 string_type,
1078 pointer_type,
1079 custom_type
11fdf7f2
TL
1080};
1081
f67539c2
TL
1082// Maps core type T to the corresponding type enum constant.
1083template <typename T, typename Char>
1084struct type_constant : std::integral_constant<type, type::custom_type> {};
1085
1086#define FMT_TYPE_CONSTANT(Type, constant) \
1087 template <typename Char> \
1088 struct type_constant<Type, Char> \
1089 : std::integral_constant<type, type::constant> {}
1090
1091FMT_TYPE_CONSTANT(int, int_type);
1092FMT_TYPE_CONSTANT(unsigned, uint_type);
1093FMT_TYPE_CONSTANT(long long, long_long_type);
1094FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
1095FMT_TYPE_CONSTANT(int128_t, int128_type);
1096FMT_TYPE_CONSTANT(uint128_t, uint128_type);
1097FMT_TYPE_CONSTANT(bool, bool_type);
1098FMT_TYPE_CONSTANT(Char, char_type);
1099FMT_TYPE_CONSTANT(float, float_type);
1100FMT_TYPE_CONSTANT(double, double_type);
1101FMT_TYPE_CONSTANT(long double, long_double_type);
1102FMT_TYPE_CONSTANT(const Char*, cstring_type);
1103FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
1104FMT_TYPE_CONSTANT(const void*, pointer_type);
1105
1106constexpr bool is_integral_type(type t) {
1107 return t > type::none_type && t <= type::last_integer_type;
11fdf7f2
TL
1108}
1109
f67539c2
TL
1110constexpr bool is_arithmetic_type(type t) {
1111 return t > type::none_type && t <= type::last_numeric_type;
11fdf7f2
TL
1112}
1113
9f95a23c 1114template <typename Char> struct string_value {
f67539c2
TL
1115 const Char* data;
1116 size_t size;
1117};
1118
1119template <typename Char> struct named_arg_value {
1120 const named_arg_info<Char>* data;
1121 size_t size;
11fdf7f2
TL
1122};
1123
9f95a23c 1124template <typename Context> struct custom_value {
f67539c2 1125 using parse_context = typename Context::parse_context_type;
9f95a23c 1126 const void* value;
f67539c2 1127 void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx);
11fdf7f2
TL
1128};
1129
1130// A formatting argument value.
9f95a23c 1131template <typename Context> class value {
11fdf7f2 1132 public:
f67539c2 1133 using char_type = typename Context::char_type;
11fdf7f2
TL
1134
1135 union {
20effc67 1136 monostate no_value;
11fdf7f2
TL
1137 int int_value;
1138 unsigned uint_value;
1139 long long long_long_value;
1140 unsigned long long ulong_long_value;
f67539c2
TL
1141 int128_t int128_value;
1142 uint128_t uint128_value;
1143 bool bool_value;
1144 char_type char_value;
1145 float float_value;
11fdf7f2
TL
1146 double double_value;
1147 long double long_double_value;
9f95a23c 1148 const void* pointer;
11fdf7f2 1149 string_value<char_type> string;
11fdf7f2 1150 custom_value<Context> custom;
f67539c2 1151 named_arg_value<char_type> named_args;
11fdf7f2
TL
1152 };
1153
20effc67
TL
1154 constexpr FMT_INLINE value() : no_value() {}
1155 constexpr FMT_INLINE value(int val) : int_value(val) {}
f67539c2 1156 constexpr FMT_INLINE value(unsigned val) : uint_value(val) {}
20effc67
TL
1157 constexpr FMT_INLINE value(long long val) : long_long_value(val) {}
1158 constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {}
f67539c2
TL
1159 FMT_INLINE value(int128_t val) : int128_value(val) {}
1160 FMT_INLINE value(uint128_t val) : uint128_value(val) {}
1161 FMT_INLINE value(float val) : float_value(val) {}
1162 FMT_INLINE value(double val) : double_value(val) {}
1163 FMT_INLINE value(long double val) : long_double_value(val) {}
20effc67
TL
1164 constexpr FMT_INLINE value(bool val) : bool_value(val) {}
1165 constexpr FMT_INLINE value(char_type val) : char_value(val) {}
1166 FMT_CONSTEXPR FMT_INLINE value(const char_type* val) {
1167 string.data = val;
1168 if (is_constant_evaluated()) string.size = {};
1169 }
1170 FMT_CONSTEXPR FMT_INLINE value(basic_string_view<char_type> val) {
f67539c2 1171 string.data = val.data();
11fdf7f2
TL
1172 string.size = val.size();
1173 }
f67539c2
TL
1174 FMT_INLINE value(const void* val) : pointer(val) {}
1175 FMT_INLINE value(const named_arg_info<char_type>* args, size_t size)
1176 : named_args{args, size} {}
11fdf7f2 1177
20effc67 1178 template <typename T> FMT_CONSTEXPR FMT_INLINE value(const T& val) {
11fdf7f2 1179 custom.value = &val;
9f95a23c
TL
1180 // Get the formatter type through the context to allow different contexts
1181 // have different extension points, e.g. `formatter<T>` for `format` and
1182 // `printf_formatter<T>` for `printf`.
f67539c2
TL
1183 custom.format = format_custom_arg<
1184 T, conditional_t<has_formatter<T, Context>::value,
1185 typename Context::template formatter_type<T>,
1186 fallback_formatter<T, char_type>>>;
11fdf7f2
TL
1187 }
1188
1189 private:
1190 // Formats an argument of a custom type, such as a user-defined class.
9f95a23c
TL
1191 template <typename T, typename Formatter>
1192 static void format_custom_arg(const void* arg,
f67539c2 1193 typename Context::parse_context_type& parse_ctx,
9f95a23c
TL
1194 Context& ctx) {
1195 Formatter f;
11fdf7f2
TL
1196 parse_ctx.advance_to(f.parse(parse_ctx));
1197 ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));
1198 }
1199};
1200
11fdf7f2 1201template <typename Context, typename T>
20effc67 1202FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context>;
11fdf7f2 1203
11fdf7f2
TL
1204// To minimize the number of types we need to deal with, long is translated
1205// either to int or to long long depending on its size.
f67539c2
TL
1206enum { long_short = sizeof(long) == sizeof(int) };
1207using long_type = conditional_t<long_short, int, long long>;
1208using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
1209
20effc67
TL
1210struct unformattable {};
1211
f67539c2
TL
1212// Maps formatting arguments to core types.
1213template <typename Context> struct arg_mapper {
1214 using char_type = typename Context::char_type;
1215
20effc67
TL
1216 FMT_CONSTEXPR FMT_INLINE auto map(signed char val) -> int { return val; }
1217 FMT_CONSTEXPR FMT_INLINE auto map(unsigned char val) -> unsigned {
1218 return val;
1219 }
1220 FMT_CONSTEXPR FMT_INLINE auto map(short val) -> int { return val; }
1221 FMT_CONSTEXPR FMT_INLINE auto map(unsigned short val) -> unsigned {
1222 return val;
1223 }
1224 FMT_CONSTEXPR FMT_INLINE auto map(int val) -> int { return val; }
1225 FMT_CONSTEXPR FMT_INLINE auto map(unsigned val) -> unsigned { return val; }
1226 FMT_CONSTEXPR FMT_INLINE auto map(long val) -> long_type { return val; }
1227 FMT_CONSTEXPR FMT_INLINE auto map(unsigned long val) -> ulong_type {
1228 return val;
1229 }
1230 FMT_CONSTEXPR FMT_INLINE auto map(long long val) -> long long { return val; }
1231 FMT_CONSTEXPR FMT_INLINE auto map(unsigned long long val)
1232 -> unsigned long long {
1233 return val;
1234 }
1235 FMT_CONSTEXPR FMT_INLINE auto map(int128_t val) -> int128_t { return val; }
1236 FMT_CONSTEXPR FMT_INLINE auto map(uint128_t val) -> uint128_t { return val; }
1237 FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; }
f67539c2
TL
1238
1239 template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
20effc67 1240 FMT_CONSTEXPR FMT_INLINE auto map(T val) -> char_type {
f67539c2
TL
1241 static_assert(
1242 std::is_same<T, char>::value || std::is_same<T, char_type>::value,
1243 "mixing character types is disallowed");
1244 return val;
1245 }
11fdf7f2 1246
20effc67
TL
1247 FMT_CONSTEXPR FMT_INLINE auto map(float val) -> float { return val; }
1248 FMT_CONSTEXPR FMT_INLINE auto map(double val) -> double { return val; }
1249 FMT_CONSTEXPR FMT_INLINE auto map(long double val) -> long double {
1250 return val;
1251 }
f67539c2 1252
20effc67
TL
1253 FMT_CONSTEXPR FMT_INLINE auto map(char_type* val) -> const char_type* {
1254 return val;
1255 }
1256 FMT_CONSTEXPR FMT_INLINE auto map(const char_type* val) -> const char_type* {
1257 return val;
1258 }
f67539c2 1259 template <typename T, FMT_ENABLE_IF(is_string<T>::value)>
20effc67
TL
1260 FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
1261 -> basic_string_view<char_type> {
f67539c2
TL
1262 static_assert(std::is_same<char_type, char_t<T>>::value,
1263 "mixing character types is disallowed");
1264 return to_string_view(val);
1265 }
1266 template <typename T,
1267 FMT_ENABLE_IF(
1268 std::is_constructible<basic_string_view<char_type>, T>::value &&
1269 !is_string<T>::value && !has_formatter<T, Context>::value &&
20effc67
TL
1270 !has_fallback_formatter<T, char_type>::value)>
1271 FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
1272 -> basic_string_view<char_type> {
f67539c2
TL
1273 return basic_string_view<char_type>(val);
1274 }
1275 template <
1276 typename T,
1277 FMT_ENABLE_IF(
1278 std::is_constructible<std_string_view<char_type>, T>::value &&
1279 !std::is_constructible<basic_string_view<char_type>, T>::value &&
1280 !is_string<T>::value && !has_formatter<T, Context>::value &&
20effc67
TL
1281 !has_fallback_formatter<T, char_type>::value)>
1282 FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
1283 -> basic_string_view<char_type> {
f67539c2
TL
1284 return std_string_view<char_type>(val);
1285 }
20effc67 1286 FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) -> const char* {
f67539c2
TL
1287 static_assert(std::is_same<char_type, char>::value, "invalid string type");
1288 return reinterpret_cast<const char*>(val);
1289 }
20effc67 1290 FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) -> const char* {
f67539c2
TL
1291 static_assert(std::is_same<char_type, char>::value, "invalid string type");
1292 return reinterpret_cast<const char*>(val);
1293 }
20effc67 1294 FMT_CONSTEXPR FMT_INLINE auto map(signed char* val) -> const char* {
f67539c2
TL
1295 const auto* const_val = val;
1296 return map(const_val);
1297 }
20effc67 1298 FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val) -> const char* {
f67539c2
TL
1299 const auto* const_val = val;
1300 return map(const_val);
1301 }
11fdf7f2 1302
20effc67
TL
1303 FMT_CONSTEXPR FMT_INLINE auto map(void* val) -> const void* { return val; }
1304 FMT_CONSTEXPR FMT_INLINE auto map(const void* val) -> const void* {
1305 return val;
1306 }
1307 FMT_CONSTEXPR FMT_INLINE auto map(std::nullptr_t val) -> const void* {
1308 return val;
1309 }
1310
1311 // We use SFINAE instead of a const T* parameter to avoid conflicting with
1312 // the C array overload.
1313 template <typename T>
1314 FMT_CONSTEXPR auto map(T) -> enable_if_t<std::is_pointer<T>::value, int> {
f67539c2
TL
1315 // Formatting of arbitrary pointers is disallowed. If you want to output
1316 // a pointer cast it to "void *" or "const void *". In particular, this
1317 // forbids formatting of "[const] volatile char *" which is printed as bool
1318 // by iostreams.
1319 static_assert(!sizeof(T), "formatting of non-void pointers is disallowed");
1320 return 0;
1321 }
9f95a23c 1322
20effc67
TL
1323 template <typename T, std::size_t N>
1324 FMT_CONSTEXPR FMT_INLINE auto map(const T (&values)[N]) -> const T (&)[N] {
1325 return values;
1326 }
1327
f67539c2
TL
1328 template <typename T,
1329 FMT_ENABLE_IF(std::is_enum<T>::value &&
1330 !has_formatter<T, Context>::value &&
20effc67
TL
1331 !has_fallback_formatter<T, char_type>::value)>
1332 FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
f67539c2
TL
1333 -> decltype(std::declval<arg_mapper>().map(
1334 static_cast<typename std::underlying_type<T>::type>(val))) {
1335 return map(static_cast<typename std::underlying_type<T>::type>(val));
1336 }
1337 template <typename T,
1338 FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
1339 (has_formatter<T, Context>::value ||
20effc67
TL
1340 has_fallback_formatter<T, char_type>::value))>
1341 FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> const T& {
f67539c2
TL
1342 return val;
1343 }
9f95a23c 1344
20effc67
TL
1345 template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
1346 FMT_CONSTEXPR FMT_INLINE auto map(const T& named_arg)
1347 -> decltype(std::declval<arg_mapper>().map(named_arg.value)) {
1348 return map(named_arg.value);
f67539c2 1349 }
11fdf7f2 1350
20effc67 1351 auto map(...) -> unformattable { return {}; }
f67539c2 1352};
11fdf7f2 1353
f67539c2
TL
1354// A type constant after applying arg_mapper<Context>.
1355template <typename T, typename Context>
1356using mapped_type_constant =
1357 type_constant<decltype(arg_mapper<Context>().map(std::declval<const T&>())),
1358 typename Context::char_type>;
eafe8130 1359
f67539c2 1360enum { packed_arg_bits = 4 };
11fdf7f2 1361// Maximum number of arguments with packed types.
f67539c2
TL
1362enum { max_packed_args = 62 / packed_arg_bits };
1363enum : unsigned long long { is_unpacked_bit = 1ULL << 63 };
1364enum : unsigned long long { has_named_args_bit = 1ULL << 62 };
20effc67
TL
1365
1366FMT_END_DETAIL_NAMESPACE
1367
1368// An output iterator that appends to a buffer.
1369// It is used to reduce symbol sizes for the common case.
1370class appender : public std::back_insert_iterator<detail::buffer<char>> {
1371 using base = std::back_insert_iterator<detail::buffer<char>>;
1372
1373 template <typename T>
1374 friend auto get_buffer(appender out) -> detail::buffer<char>& {
1375 return detail::get_container(out);
1376 }
1377
1378 public:
1379 using std::back_insert_iterator<detail::buffer<char>>::back_insert_iterator;
1380 appender(base it) : base(it) {}
1381 using _Unchecked_type = appender; // Mark iterator as checked.
1382
1383 auto operator++() -> appender& {
1384 base::operator++();
1385 return *this;
1386 }
1387
1388 auto operator++(int) -> appender {
1389 auto tmp = *this;
1390 ++*this;
1391 return tmp;
1392 }
1393};
11fdf7f2
TL
1394
1395// A formatting argument. It is a trivially copyable/constructible type to
1396// allow storage in basic_memory_buffer.
9f95a23c 1397template <typename Context> class basic_format_arg {
11fdf7f2 1398 private:
f67539c2
TL
1399 detail::value<Context> value_;
1400 detail::type type_;
11fdf7f2
TL
1401
1402 template <typename ContextType, typename T>
20effc67
TL
1403 friend FMT_CONSTEXPR auto detail::make_arg(const T& value)
1404 -> basic_format_arg<ContextType>;
11fdf7f2
TL
1405
1406 template <typename Visitor, typename Ctx>
f67539c2
TL
1407 friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
1408 const basic_format_arg<Ctx>& arg)
1409 -> decltype(vis(0));
11fdf7f2
TL
1410
1411 friend class basic_format_args<Context>;
f67539c2
TL
1412 friend class dynamic_format_arg_store<Context>;
1413
1414 using char_type = typename Context::char_type;
11fdf7f2 1415
f67539c2
TL
1416 template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
1417 friend struct detail::arg_data;
1418
1419 basic_format_arg(const detail::named_arg_info<char_type>* args, size_t size)
1420 : value_(args, size) {}
11fdf7f2
TL
1421
1422 public:
1423 class handle {
1424 public:
f67539c2 1425 explicit handle(detail::custom_value<Context> custom) : custom_(custom) {}
11fdf7f2 1426
f67539c2
TL
1427 void format(typename Context::parse_context_type& parse_ctx,
1428 Context& ctx) const {
9f95a23c
TL
1429 custom_.format(custom_.value, parse_ctx, ctx);
1430 }
11fdf7f2
TL
1431
1432 private:
f67539c2 1433 detail::custom_value<Context> custom_;
11fdf7f2
TL
1434 };
1435
f67539c2 1436 constexpr basic_format_arg() : type_(detail::type::none_type) {}
11fdf7f2 1437
f67539c2
TL
1438 constexpr explicit operator bool() const FMT_NOEXCEPT {
1439 return type_ != detail::type::none_type;
11fdf7f2
TL
1440 }
1441
20effc67 1442 auto type() const -> detail::type { return type_; }
11fdf7f2 1443
20effc67
TL
1444 auto is_integral() const -> bool { return detail::is_integral_type(type_); }
1445 auto is_arithmetic() const -> bool {
1446 return detail::is_arithmetic_type(type_);
1447 }
11fdf7f2
TL
1448};
1449
11fdf7f2
TL
1450/**
1451 \rst
1452 Visits an argument dispatching to the appropriate visit method based on
1453 the argument type. For example, if the argument type is ``double`` then
1454 ``vis(value)`` will be called with the value of type ``double``.
1455 \endrst
1456 */
1457template <typename Visitor, typename Context>
20effc67
TL
1458FMT_CONSTEXPR FMT_INLINE auto visit_format_arg(
1459 Visitor&& vis, const basic_format_arg<Context>& arg) -> decltype(vis(0)) {
11fdf7f2 1460 switch (arg.type_) {
f67539c2 1461 case detail::type::none_type:
11fdf7f2 1462 break;
f67539c2 1463 case detail::type::int_type:
11fdf7f2 1464 return vis(arg.value_.int_value);
f67539c2 1465 case detail::type::uint_type:
11fdf7f2 1466 return vis(arg.value_.uint_value);
f67539c2 1467 case detail::type::long_long_type:
11fdf7f2 1468 return vis(arg.value_.long_long_value);
f67539c2 1469 case detail::type::ulong_long_type:
11fdf7f2 1470 return vis(arg.value_.ulong_long_value);
f67539c2 1471 case detail::type::int128_type:
20effc67 1472 return vis(detail::convert_for_visit(arg.value_.int128_value));
f67539c2 1473 case detail::type::uint128_type:
20effc67 1474 return vis(detail::convert_for_visit(arg.value_.uint128_value));
f67539c2
TL
1475 case detail::type::bool_type:
1476 return vis(arg.value_.bool_value);
1477 case detail::type::char_type:
1478 return vis(arg.value_.char_value);
1479 case detail::type::float_type:
1480 return vis(arg.value_.float_value);
1481 case detail::type::double_type:
11fdf7f2 1482 return vis(arg.value_.double_value);
f67539c2 1483 case detail::type::long_double_type:
11fdf7f2 1484 return vis(arg.value_.long_double_value);
f67539c2
TL
1485 case detail::type::cstring_type:
1486 return vis(arg.value_.string.data);
1487 case detail::type::string_type:
20effc67
TL
1488 using sv = basic_string_view<typename Context::char_type>;
1489 return vis(sv(arg.value_.string.data, arg.value_.string.size));
f67539c2 1490 case detail::type::pointer_type:
11fdf7f2 1491 return vis(arg.value_.pointer);
f67539c2 1492 case detail::type::custom_type:
11fdf7f2
TL
1493 return vis(typename basic_format_arg<Context>::handle(arg.value_.custom));
1494 }
1495 return vis(monostate());
1496}
1497
20effc67
TL
1498FMT_BEGIN_DETAIL_NAMESPACE
1499
1500template <typename Char, typename InputIt>
1501auto copy_str(InputIt begin, InputIt end, appender out) -> appender {
1502 get_container(out).append(begin, end);
1503 return out;
1504}
1505
1506#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
1507// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
1508template <typename... Ts> struct void_t_impl { using type = void; };
1509template <typename... Ts>
1510using void_t = typename detail::void_t_impl<Ts...>::type;
1511#else
1512template <typename...> using void_t = void;
1513#endif
1514
1515template <typename It, typename T, typename Enable = void>
1516struct is_output_iterator : std::false_type {};
1517
1518template <typename It, typename T>
1519struct is_output_iterator<
1520 It, T,
1521 void_t<typename std::iterator_traits<It>::iterator_category,
1522 decltype(*std::declval<It>() = std::declval<T>())>>
1523 : std::true_type {};
1524
1525template <typename OutputIt>
1526struct is_back_insert_iterator : std::false_type {};
1527template <typename Container>
1528struct is_back_insert_iterator<std::back_insert_iterator<Container>>
1529 : std::true_type {};
1530
1531template <typename OutputIt>
1532struct is_contiguous_back_insert_iterator : std::false_type {};
1533template <typename Container>
1534struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
1535 : is_contiguous<Container> {};
1536template <>
1537struct is_contiguous_back_insert_iterator<appender> : std::true_type {};
1538
eafe8130
TL
1539// A type-erased reference to an std::locale to avoid heavy <locale> include.
1540class locale_ref {
1541 private:
9f95a23c 1542 const void* locale_; // A type-erased pointer to std::locale.
eafe8130
TL
1543
1544 public:
20effc67 1545 constexpr locale_ref() : locale_(nullptr) {}
9f95a23c 1546 template <typename Locale> explicit locale_ref(const Locale& loc);
eafe8130 1547
f67539c2 1548 explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; }
eafe8130 1549
20effc67 1550 template <typename Locale> auto get() const -> Locale;
eafe8130
TL
1551};
1552
20effc67
TL
1553template <typename> constexpr auto encode_types() -> unsigned long long {
1554 return 0;
1555}
eafe8130
TL
1556
1557template <typename Context, typename Arg, typename... Args>
20effc67 1558constexpr auto encode_types() -> unsigned long long {
f67539c2
TL
1559 return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) |
1560 (encode_types<Context, Args...>() << packed_arg_bits);
eafe8130
TL
1561}
1562
1563template <typename Context, typename T>
20effc67 1564FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context> {
eafe8130 1565 basic_format_arg<Context> arg;
f67539c2
TL
1566 arg.type_ = mapped_type_constant<T, Context>::value;
1567 arg.value_ = arg_mapper<Context>().map(value);
eafe8130
TL
1568 return arg;
1569}
1570
f67539c2
TL
1571// The type template parameter is there to avoid an ODR violation when using
1572// a fallback formatter in one translation unit and an implicit conversion in
1573// another (not recommended).
1574template <bool IS_PACKED, typename Context, type, typename T,
9f95a23c 1575 FMT_ENABLE_IF(IS_PACKED)>
20effc67
TL
1576FMT_CONSTEXPR FMT_INLINE auto make_arg(const T& val) -> value<Context> {
1577 const auto& arg = arg_mapper<Context>().map(val);
1578 static_assert(
1579 !std::is_same<decltype(arg), const unformattable&>::value,
1580 "Cannot format an argument. To make type T formattable provide a "
1581 "formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
1582 return {arg};
eafe8130
TL
1583}
1584
f67539c2 1585template <bool IS_PACKED, typename Context, type, typename T,
9f95a23c 1586 FMT_ENABLE_IF(!IS_PACKED)>
20effc67 1587inline auto make_arg(const T& value) -> basic_format_arg<Context> {
eafe8130 1588 return make_arg<Context>(value);
11fdf7f2 1589}
20effc67 1590FMT_END_DETAIL_NAMESPACE
11fdf7f2
TL
1591
1592// Formatting context.
9f95a23c 1593template <typename OutputIt, typename Char> class basic_format_context {
11fdf7f2
TL
1594 public:
1595 /** The character type for the output. */
f67539c2 1596 using char_type = Char;
11fdf7f2 1597
11fdf7f2 1598 private:
9f95a23c
TL
1599 OutputIt out_;
1600 basic_format_args<basic_format_context> args_;
f67539c2 1601 detail::locale_ref loc_;
11fdf7f2
TL
1602
1603 public:
f67539c2
TL
1604 using iterator = OutputIt;
1605 using format_arg = basic_format_arg<basic_format_context>;
1606 using parse_context_type = basic_format_parse_context<Char>;
1607 template <typename T> using formatter_type = formatter<T, char_type>;
11fdf7f2 1608
20effc67 1609 basic_format_context(basic_format_context&&) = default;
f67539c2
TL
1610 basic_format_context(const basic_format_context&) = delete;
1611 void operator=(const basic_format_context&) = delete;
11fdf7f2
TL
1612 /**
1613 Constructs a ``basic_format_context`` object. References to the arguments are
1614 stored in the object so make sure they have appropriate lifetimes.
1615 */
20effc67
TL
1616 constexpr basic_format_context(
1617 OutputIt out, basic_format_args<basic_format_context> ctx_args,
1618 detail::locale_ref loc = detail::locale_ref())
9f95a23c 1619 : out_(out), args_(ctx_args), loc_(loc) {}
11fdf7f2 1620
20effc67
TL
1621 constexpr auto arg(int id) const -> format_arg { return args_.get(id); }
1622 FMT_CONSTEXPR auto arg(basic_string_view<char_type> name) -> format_arg {
1623 return args_.get(name);
1624 }
1625 FMT_CONSTEXPR auto arg_id(basic_string_view<char_type> name) -> int {
1626 return args_.get_id(name);
1627 }
1628 auto args() const -> const basic_format_args<basic_format_context>& {
1629 return args_;
1630 }
9f95a23c 1631
20effc67 1632 FMT_CONSTEXPR auto error_handler() -> detail::error_handler { return {}; }
9f95a23c
TL
1633 void on_error(const char* message) { error_handler().on_error(message); }
1634
1635 // Returns an iterator to the beginning of the output range.
20effc67 1636 FMT_CONSTEXPR auto out() -> iterator { return out_; }
9f95a23c
TL
1637
1638 // Advances the begin iterator to ``it``.
20effc67
TL
1639 void advance_to(iterator it) {
1640 if (!detail::is_back_insert_iterator<iterator>()) out_ = it;
1641 }
9f95a23c 1642
20effc67 1643 FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; }
11fdf7f2
TL
1644};
1645
f67539c2
TL
1646template <typename Char>
1647using buffer_context =
20effc67 1648 basic_format_context<detail::buffer_appender<Char>, Char>;
f67539c2 1649using format_context = buffer_context<char>;
20effc67
TL
1650
1651// Workaround an alias issue: https://stackoverflow.com/q/62767544/471164.
1652#define FMT_BUFFER_CONTEXT(Char) \
1653 basic_format_context<detail::buffer_appender<Char>, Char>
1654
1655template <typename T, typename Char = char>
1656using is_formattable = bool_constant<
1657 !std::is_same<decltype(detail::arg_mapper<buffer_context<Char>>().map(
1658 std::declval<T>())),
1659 detail::unformattable>::value &&
1660 !detail::has_fallback_formatter<T, Char>::value>;
11fdf7f2 1661
11fdf7f2
TL
1662/**
1663 \rst
1664 An array of references to arguments. It can be implicitly converted into
1665 `~fmt::basic_format_args` for passing into type-erased formatting functions
1666 such as `~fmt::vformat`.
1667 \endrst
1668 */
f67539c2
TL
1669template <typename Context, typename... Args>
1670class format_arg_store
1671#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1672 // Workaround a GCC template argument substitution bug.
1673 : public basic_format_args<Context>
1674#endif
1675{
11fdf7f2 1676 private:
f67539c2
TL
1677 static const size_t num_args = sizeof...(Args);
1678 static const size_t num_named_args = detail::count_named_args<Args...>();
1679 static const bool is_packed = num_args <= detail::max_packed_args;
11fdf7f2 1680
f67539c2
TL
1681 using value_type = conditional_t<is_packed, detail::value<Context>,
1682 basic_format_arg<Context>>;
11fdf7f2 1683
f67539c2
TL
1684 detail::arg_data<value_type, typename Context::char_type, num_args,
1685 num_named_args>
1686 data_;
11fdf7f2
TL
1687
1688 friend class basic_format_args<Context>;
1689
f67539c2
TL
1690 static constexpr unsigned long long desc =
1691 (is_packed ? detail::encode_types<Context, Args...>()
1692 : detail::is_unpacked_bit | num_args) |
1693 (num_named_args != 0
1694 ? static_cast<unsigned long long>(detail::has_named_args_bit)
1695 : 0);
11fdf7f2
TL
1696
1697 public:
20effc67 1698 FMT_CONSTEXPR FMT_INLINE format_arg_store(const Args&... args)
f67539c2
TL
1699 :
1700#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1701 basic_format_args<Context>(*this),
11fdf7f2 1702#endif
f67539c2
TL
1703 data_{detail::make_arg<
1704 is_packed, Context,
1705 detail::mapped_type_constant<Args, Context>::value>(args)...} {
1706 detail::init_named_args(data_.named_args(), 0, 0, args...);
1707 }
11fdf7f2
TL
1708};
1709
11fdf7f2
TL
1710/**
1711 \rst
20effc67 1712 Constructs a `~fmt::format_arg_store` object that contains references to
11fdf7f2
TL
1713 arguments and can be implicitly converted to `~fmt::format_args`. `Context`
1714 can be omitted in which case it defaults to `~fmt::context`.
9f95a23c 1715 See `~fmt::arg` for lifetime considerations.
11fdf7f2
TL
1716 \endrst
1717 */
9f95a23c 1718template <typename Context = format_context, typename... Args>
20effc67
TL
1719constexpr auto make_format_args(const Args&... args)
1720 -> format_arg_store<Context, Args...> {
9f95a23c
TL
1721 return {args...};
1722}
11fdf7f2 1723
f67539c2
TL
1724/**
1725 \rst
20effc67
TL
1726 Returns a named argument to be used in a formatting function.
1727 It should only be used in a call to a formatting function or
1728 `dynamic_format_arg_store::push_back`.
f67539c2
TL
1729
1730 **Example**::
1731
1732 fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
1733 \endrst
1734 */
1735template <typename Char, typename T>
20effc67 1736inline auto arg(const Char* name, const T& arg) -> detail::named_arg<Char, T> {
f67539c2
TL
1737 static_assert(!detail::is_named_arg<T>(), "nested named arguments");
1738 return {name, arg};
1739}
1740
f67539c2
TL
1741/**
1742 \rst
1743 A view of a collection of formatting arguments. To avoid lifetime issues it
1744 should only be used as a parameter type in type-erased functions such as
1745 ``vformat``::
1746
1747 void vlog(string_view format_str, format_args args); // OK
1748 format_args args = make_format_args(42); // Error: dangling reference
1749 \endrst
1750 */
9f95a23c 1751template <typename Context> class basic_format_args {
11fdf7f2 1752 public:
f67539c2
TL
1753 using size_type = int;
1754 using format_arg = basic_format_arg<Context>;
11fdf7f2
TL
1755
1756 private:
f67539c2
TL
1757 // A descriptor that contains information about formatting arguments.
1758 // If the number of arguments is less or equal to max_packed_args then
1759 // argument types are passed in the descriptor. This reduces binary code size
1760 // per formatting function call.
1761 unsigned long long desc_;
11fdf7f2 1762 union {
f67539c2
TL
1763 // If is_packed() returns true then argument values are stored in values_;
1764 // otherwise they are stored in args_. This is done to improve cache
1765 // locality and reduce compiled code size since storing larger objects
11fdf7f2
TL
1766 // may require more code (at least on x86-64) even if the same amount of
1767 // data is actually copied to stack. It saves ~10% on the bloat test.
f67539c2 1768 const detail::value<Context>* values_;
9f95a23c 1769 const format_arg* args_;
11fdf7f2
TL
1770 };
1771
20effc67
TL
1772 constexpr auto is_packed() const -> bool {
1773 return (desc_ & detail::is_unpacked_bit) == 0;
1774 }
1775 auto has_named_args() const -> bool {
f67539c2 1776 return (desc_ & detail::has_named_args_bit) != 0;
11fdf7f2
TL
1777 }
1778
20effc67 1779 FMT_CONSTEXPR auto type(int index) const -> detail::type {
f67539c2
TL
1780 int shift = index * detail::packed_arg_bits;
1781 unsigned int mask = (1 << detail::packed_arg_bits) - 1;
1782 return static_cast<detail::type>((desc_ >> shift) & mask);
11fdf7f2
TL
1783 }
1784
20effc67
TL
1785 constexpr FMT_INLINE basic_format_args(unsigned long long desc,
1786 const detail::value<Context>* values)
f67539c2 1787 : desc_(desc), values_(values) {}
20effc67 1788 constexpr basic_format_args(unsigned long long desc, const format_arg* args)
f67539c2
TL
1789 : desc_(desc), args_(args) {}
1790
11fdf7f2 1791 public:
20effc67 1792 constexpr basic_format_args() : desc_(0), args_(nullptr) {}
11fdf7f2
TL
1793
1794 /**
1795 \rst
1796 Constructs a `basic_format_args` object from `~fmt::format_arg_store`.
1797 \endrst
1798 */
1799 template <typename... Args>
20effc67
TL
1800 constexpr FMT_INLINE basic_format_args(
1801 const format_arg_store<Context, Args...>& store)
1802 : basic_format_args(format_arg_store<Context, Args...>::desc,
1803 store.data_.args()) {}
f67539c2
TL
1804
1805 /**
1806 \rst
1807 Constructs a `basic_format_args` object from
1808 `~fmt::dynamic_format_arg_store`.
1809 \endrst
1810 */
20effc67
TL
1811 constexpr FMT_INLINE basic_format_args(
1812 const dynamic_format_arg_store<Context>& store)
f67539c2 1813 : basic_format_args(store.get_types(), store.data()) {}
11fdf7f2
TL
1814
1815 /**
1816 \rst
1817 Constructs a `basic_format_args` object from a dynamic set of arguments.
1818 \endrst
1819 */
20effc67 1820 constexpr basic_format_args(const format_arg* args, int count)
f67539c2
TL
1821 : basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count),
1822 args) {}
11fdf7f2 1823
f67539c2 1824 /** Returns the argument with the specified id. */
20effc67 1825 FMT_CONSTEXPR auto get(int id) const -> format_arg {
f67539c2
TL
1826 format_arg arg;
1827 if (!is_packed()) {
1828 if (id < max_size()) arg = args_[id];
1829 return arg;
1830 }
1831 if (id >= detail::max_packed_args) return arg;
1832 arg.type_ = type(id);
1833 if (arg.type_ == detail::type::none_type) return arg;
1834 arg.value_ = values_[id];
11fdf7f2
TL
1835 return arg;
1836 }
1837
20effc67
TL
1838 template <typename Char>
1839 auto get(basic_string_view<Char> name) const -> format_arg {
1840 int id = get_id(name);
1841 return id >= 0 ? get(id) : format_arg();
1842 }
1843
1844 template <typename Char>
1845 auto get_id(basic_string_view<Char> name) const -> int {
1846 if (!has_named_args()) return -1;
f67539c2
TL
1847 const auto& named_args =
1848 (is_packed() ? values_[-1] : args_[-1].value_).named_args;
1849 for (size_t i = 0; i < named_args.size; ++i) {
20effc67 1850 if (named_args.data[i].name == name) return named_args.data[i].id;
f67539c2 1851 }
20effc67 1852 return -1;
f67539c2
TL
1853 }
1854
20effc67 1855 auto max_size() const -> int {
f67539c2
TL
1856 unsigned long long max_packed = detail::max_packed_args;
1857 return static_cast<int>(is_packed() ? max_packed
1858 : desc_ & ~detail::is_unpacked_bit);
11fdf7f2
TL
1859 }
1860};
1861
20effc67
TL
1862/** An alias to ``basic_format_args<format_context>``. */
1863// A separate type would result in shorter symbols but break ABI compatibility
1864// between clang and gcc on ARM (#1919).
1865using format_args = basic_format_args<format_context>;
1866
1867// We cannot use enum classes as bit fields because of a gcc bug
1868// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414.
1869namespace align {
1870enum type { none, left, right, center, numeric };
1871}
1872using align_t = align::type;
1873namespace sign {
1874enum type { none, minus, plus, space };
1875}
1876using sign_t = sign::type;
1877
1878FMT_BEGIN_DETAIL_NAMESPACE
1879
1880void throw_format_error(const char* message);
1881
1882// Workaround an array initialization issue in gcc 4.8.
1883template <typename Char> struct fill_t {
1884 private:
1885 enum { max_size = 4 };
1886 Char data_[max_size] = {Char(' '), Char(0), Char(0), Char(0)};
1887 unsigned char size_ = 1;
1888
1889 public:
1890 FMT_CONSTEXPR void operator=(basic_string_view<Char> s) {
1891 auto size = s.size();
1892 if (size > max_size) return throw_format_error("invalid fill");
1893 for (size_t i = 0; i < size; ++i) data_[i] = s[i];
1894 size_ = static_cast<unsigned char>(size);
1895 }
1896
1897 constexpr auto size() const -> size_t { return size_; }
1898 constexpr auto data() const -> const Char* { return data_; }
1899
1900 FMT_CONSTEXPR auto operator[](size_t index) -> Char& { return data_[index]; }
1901 FMT_CONSTEXPR auto operator[](size_t index) const -> const Char& {
1902 return data_[index];
1903 }
11fdf7f2 1904};
20effc67
TL
1905FMT_END_DETAIL_NAMESPACE
1906
1907// Format specifiers for built-in and string types.
1908template <typename Char> struct basic_format_specs {
1909 int width;
1910 int precision;
1911 char type;
1912 align_t align : 4;
1913 sign_t sign : 3;
1914 bool alt : 1; // Alternate form ('#').
1915 bool localized : 1;
1916 detail::fill_t<Char> fill;
1917
1918 constexpr basic_format_specs()
1919 : width(0),
1920 precision(-1),
1921 type(0),
1922 align(align::none),
1923 sign(sign::none),
1924 alt(false),
1925 localized(false) {}
11fdf7f2
TL
1926};
1927
20effc67 1928using format_specs = basic_format_specs<char>;
11fdf7f2 1929
20effc67
TL
1930FMT_BEGIN_DETAIL_NAMESPACE
1931
1932enum class arg_id_kind { none, index, name };
1933
1934// An argument reference.
1935template <typename Char> struct arg_ref {
1936 FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {}
1937
1938 FMT_CONSTEXPR explicit arg_ref(int index)
1939 : kind(arg_id_kind::index), val(index) {}
1940 FMT_CONSTEXPR explicit arg_ref(basic_string_view<Char> name)
1941 : kind(arg_id_kind::name), val(name) {}
11fdf7f2 1942
20effc67
TL
1943 FMT_CONSTEXPR auto operator=(int idx) -> arg_ref& {
1944 kind = arg_id_kind::index;
1945 val.index = idx;
1946 return *this;
1947 }
1948
1949 arg_id_kind kind;
1950 union value {
1951 FMT_CONSTEXPR value(int id = 0) : index{id} {}
1952 FMT_CONSTEXPR value(basic_string_view<Char> n) : name(n) {}
1953
1954 int index;
1955 basic_string_view<Char> name;
1956 } val;
1957};
1958
1959// Format specifiers with width and precision resolved at formatting rather
1960// than parsing time to allow re-using the same parsed specifiers with
1961// different sets of arguments (precompilation of format strings).
f67539c2 1962template <typename Char>
20effc67
TL
1963struct dynamic_format_specs : basic_format_specs<Char> {
1964 arg_ref<Char> width_ref;
1965 arg_ref<Char> precision_ref;
1966};
11fdf7f2 1967
20effc67 1968struct auto_id {};
eafe8130 1969
20effc67
TL
1970// A format specifier handler that sets fields in basic_format_specs.
1971template <typename Char> class specs_setter {
1972 protected:
1973 basic_format_specs<Char>& specs_;
f67539c2 1974
20effc67
TL
1975 public:
1976 explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char>& specs)
1977 : specs_(specs) {}
1978
1979 FMT_CONSTEXPR specs_setter(const specs_setter& other)
1980 : specs_(other.specs_) {}
1981
1982 FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; }
1983 FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) {
1984 specs_.fill = fill;
1985 }
1986 FMT_CONSTEXPR void on_sign(sign_t s) { specs_.sign = s; }
1987 FMT_CONSTEXPR void on_hash() { specs_.alt = true; }
1988 FMT_CONSTEXPR void on_localized() { specs_.localized = true; }
1989
1990 FMT_CONSTEXPR void on_zero() {
1991 if (specs_.align == align::none) specs_.align = align::numeric;
1992 specs_.fill[0] = Char('0');
1993 }
1994
1995 FMT_CONSTEXPR void on_width(int width) { specs_.width = width; }
1996 FMT_CONSTEXPR void on_precision(int precision) {
1997 specs_.precision = precision;
1998 }
1999 FMT_CONSTEXPR void end_precision() {}
2000
2001 FMT_CONSTEXPR void on_type(Char type) {
2002 specs_.type = static_cast<char>(type);
2003 }
2004};
2005
2006// Format spec handler that saves references to arguments representing dynamic
2007// width and precision to be resolved at formatting time.
2008template <typename ParseContext>
2009class dynamic_specs_handler
2010 : public specs_setter<typename ParseContext::char_type> {
2011 public:
2012 using char_type = typename ParseContext::char_type;
2013
2014 FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs<char_type>& specs,
2015 ParseContext& ctx)
2016 : specs_setter<char_type>(specs), specs_(specs), context_(ctx) {}
2017
2018 FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler& other)
2019 : specs_setter<char_type>(other),
2020 specs_(other.specs_),
2021 context_(other.context_) {}
2022
2023 template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
2024 specs_.width_ref = make_arg_ref(arg_id);
2025 }
2026
2027 template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
2028 specs_.precision_ref = make_arg_ref(arg_id);
2029 }
2030
2031 FMT_CONSTEXPR void on_error(const char* message) {
2032 context_.on_error(message);
2033 }
2034
2035 private:
2036 dynamic_format_specs<char_type>& specs_;
2037 ParseContext& context_;
2038
2039 using arg_ref_type = arg_ref<char_type>;
2040
2041 FMT_CONSTEXPR auto make_arg_ref(int arg_id) -> arg_ref_type {
2042 context_.check_arg_id(arg_id);
2043 return arg_ref_type(arg_id);
2044 }
2045
2046 FMT_CONSTEXPR auto make_arg_ref(auto_id) -> arg_ref_type {
2047 return arg_ref_type(context_.next_arg_id());
2048 }
2049
2050 FMT_CONSTEXPR auto make_arg_ref(basic_string_view<char_type> arg_id)
2051 -> arg_ref_type {
2052 context_.check_arg_id(arg_id);
2053 basic_string_view<char_type> format_str(
2054 context_.begin(), to_unsigned(context_.end() - context_.begin()));
2055 return arg_ref_type(arg_id);
2056 }
2057};
2058
2059template <typename Char> constexpr bool is_ascii_letter(Char c) {
2060 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
f67539c2 2061}
9f95a23c 2062
20effc67
TL
2063// Converts a character to ASCII. Returns a number > 127 on conversion failure.
2064template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
2065constexpr auto to_ascii(Char value) -> Char {
2066 return value;
2067}
2068template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
2069constexpr auto to_ascii(Char value) ->
2070 typename std::underlying_type<Char>::type {
2071 return value;
9f95a23c 2072}
eafe8130
TL
2073
2074template <typename Char>
20effc67
TL
2075FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int {
2076 if (const_check(sizeof(Char) != 1)) return 1;
2077 constexpr char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2078 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0};
2079 int len = lengths[static_cast<unsigned char>(*begin) >> 3];
2080
2081 // Compute the pointer to the next character early so that the next
2082 // iteration can start working on the next character. Neither Clang
2083 // nor GCC figure out this reordering on their own.
2084 return len + !len;
2085}
2086
2087// Return the result via the out param to workaround gcc bug 77539.
2088template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
2089FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool {
2090 for (out = first; out != last; ++out) {
2091 if (*out == value) return true;
2092 }
2093 return false;
2094}
eafe8130 2095
20effc67
TL
2096template <>
2097inline auto find<false, char>(const char* first, const char* last, char value,
2098 const char*& out) -> bool {
2099 out = static_cast<const char*>(
2100 std::memchr(first, value, to_unsigned(last - first)));
2101 return out != nullptr;
2102}
2103
2104// Parses the range [begin, end) as an unsigned integer. This function assumes
2105// that the range is non-empty and the first character is a digit.
eafe8130 2106template <typename Char>
20effc67
TL
2107FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end,
2108 int error_value) noexcept -> int {
2109 FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', "");
2110 unsigned value = 0, prev = 0;
2111 auto p = begin;
2112 do {
2113 prev = value;
2114 value = value * 10 + unsigned(*p - '0');
2115 ++p;
2116 } while (p != end && '0' <= *p && *p <= '9');
2117 auto num_digits = p - begin;
2118 begin = p;
2119 if (num_digits <= std::numeric_limits<int>::digits10)
2120 return static_cast<int>(value);
2121 // Check for overflow.
2122 const unsigned max = to_unsigned((std::numeric_limits<int>::max)());
2123 return num_digits == std::numeric_limits<int>::digits10 + 1 &&
2124 prev * 10ull + unsigned(p[-1] - '0') <= max
2125 ? static_cast<int>(value)
2126 : error_value;
2127}
2128
2129// Parses fill and alignment.
2130template <typename Char, typename Handler>
2131FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
2132 Handler&& handler) -> const Char* {
2133 FMT_ASSERT(begin != end, "");
2134 auto align = align::none;
2135 auto p = begin + code_point_length(begin);
2136 if (p >= end) p = begin;
2137 for (;;) {
2138 switch (to_ascii(*p)) {
2139 case '<':
2140 align = align::left;
2141 break;
2142 case '>':
2143 align = align::right;
2144 break;
2145 case '^':
2146 align = align::center;
2147 break;
2148 default:
2149 break;
2150 }
2151 if (align != align::none) {
2152 if (p != begin) {
2153 auto c = *begin;
2154 if (c == '{')
2155 return handler.on_error("invalid fill character '{'"), begin;
2156 handler.on_fill(basic_string_view<Char>(begin, to_unsigned(p - begin)));
2157 begin = p + 1;
2158 } else
2159 ++begin;
2160 handler.on_align(align);
2161 break;
2162 } else if (p == begin) {
2163 break;
2164 }
2165 p = begin;
2166 }
2167 return begin;
2168}
2169
2170template <typename Char> FMT_CONSTEXPR bool is_name_start(Char c) {
2171 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
2172}
2173
2174template <typename Char, typename IDHandler>
2175FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end,
2176 IDHandler&& handler) -> const Char* {
2177 FMT_ASSERT(begin != end, "");
2178 Char c = *begin;
2179 if (c >= '0' && c <= '9') {
2180 int index = 0;
2181 if (c != '0')
2182 index =
2183 parse_nonnegative_int(begin, end, (std::numeric_limits<int>::max)());
2184 else
2185 ++begin;
2186 if (begin == end || (*begin != '}' && *begin != ':'))
2187 handler.on_error("invalid format string");
2188 else
2189 handler(index);
2190 return begin;
2191 }
2192 if (!is_name_start(c)) {
2193 handler.on_error("invalid format string");
2194 return begin;
2195 }
2196 auto it = begin;
2197 do {
2198 ++it;
2199 } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9')));
2200 handler(basic_string_view<Char>(begin, to_unsigned(it - begin)));
2201 return it;
2202}
2203
2204template <typename Char, typename IDHandler>
2205FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end,
2206 IDHandler&& handler) -> const Char* {
2207 Char c = *begin;
2208 if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler);
2209 handler();
2210 return begin;
2211}
11fdf7f2 2212
20effc67
TL
2213template <typename Char, typename Handler>
2214FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end,
2215 Handler&& handler) -> const Char* {
2216 using detail::auto_id;
2217 struct width_adapter {
2218 Handler& handler;
2219
2220 FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); }
2221 FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); }
2222 FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
2223 handler.on_dynamic_width(id);
2224 }
2225 FMT_CONSTEXPR void on_error(const char* message) {
2226 if (message) handler.on_error(message);
2227 }
2228 };
2229
2230 FMT_ASSERT(begin != end, "");
2231 if ('0' <= *begin && *begin <= '9') {
2232 int width = parse_nonnegative_int(begin, end, -1);
2233 if (width != -1)
2234 handler.on_width(width);
2235 else
2236 handler.on_error("number is too big");
2237 } else if (*begin == '{') {
2238 ++begin;
2239 if (begin != end) begin = parse_arg_id(begin, end, width_adapter{handler});
2240 if (begin == end || *begin != '}')
2241 return handler.on_error("invalid format string"), begin;
2242 ++begin;
2243 }
2244 return begin;
2245}
2246
2247template <typename Char, typename Handler>
2248FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
2249 Handler&& handler) -> const Char* {
2250 using detail::auto_id;
2251 struct precision_adapter {
2252 Handler& handler;
2253
2254 FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); }
2255 FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); }
2256 FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
2257 handler.on_dynamic_precision(id);
2258 }
2259 FMT_CONSTEXPR void on_error(const char* message) {
2260 if (message) handler.on_error(message);
2261 }
2262 };
2263
2264 ++begin;
2265 auto c = begin != end ? *begin : Char();
2266 if ('0' <= c && c <= '9') {
2267 auto precision = parse_nonnegative_int(begin, end, -1);
2268 if (precision != -1)
2269 handler.on_precision(precision);
2270 else
2271 handler.on_error("number is too big");
2272 } else if (c == '{') {
2273 ++begin;
2274 if (begin != end)
2275 begin = parse_arg_id(begin, end, precision_adapter{handler});
2276 if (begin == end || *begin++ != '}')
2277 return handler.on_error("invalid format string"), begin;
2278 } else {
2279 return handler.on_error("missing precision specifier"), begin;
2280 }
2281 handler.end_precision();
2282 return begin;
2283}
2284
2285// Parses standard format specifiers and sends notifications about parsed
2286// components to handler.
2287template <typename Char, typename SpecHandler>
2288FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin,
2289 const Char* end,
2290 SpecHandler&& handler)
2291 -> const Char* {
2292 if (begin + 1 < end && begin[1] == '}' && is_ascii_letter(*begin) &&
2293 *begin != 'L') {
2294 handler.on_type(*begin++);
2295 return begin;
2296 }
2297
2298 if (begin == end) return begin;
2299
2300 begin = parse_align(begin, end, handler);
2301 if (begin == end) return begin;
2302
2303 // Parse sign.
2304 switch (to_ascii(*begin)) {
2305 case '+':
2306 handler.on_sign(sign::plus);
2307 ++begin;
2308 break;
2309 case '-':
2310 handler.on_sign(sign::minus);
2311 ++begin;
2312 break;
2313 case ' ':
2314 handler.on_sign(sign::space);
2315 ++begin;
2316 break;
2317 default:
2318 break;
2319 }
2320 if (begin == end) return begin;
2321
2322 if (*begin == '#') {
2323 handler.on_hash();
2324 if (++begin == end) return begin;
2325 }
2326
2327 // Parse zero flag.
2328 if (*begin == '0') {
2329 handler.on_zero();
2330 if (++begin == end) return begin;
2331 }
2332
2333 begin = parse_width(begin, end, handler);
2334 if (begin == end) return begin;
2335
2336 // Parse precision.
2337 if (*begin == '.') {
2338 begin = parse_precision(begin, end, handler);
2339 if (begin == end) return begin;
2340 }
2341
2342 if (*begin == 'L') {
2343 handler.on_localized();
2344 ++begin;
2345 }
2346
2347 // Parse type.
2348 if (begin != end && *begin != '}') handler.on_type(*begin++);
2349 return begin;
2350}
2351
2352template <typename Char, typename Handler>
2353FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end,
2354 Handler&& handler) -> const Char* {
2355 struct id_adapter {
2356 Handler& handler;
2357 int arg_id;
2358
2359 FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); }
2360 FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); }
2361 FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
2362 arg_id = handler.on_arg_id(id);
2363 }
2364 FMT_CONSTEXPR void on_error(const char* message) {
2365 if (message) handler.on_error(message);
2366 }
2367 };
2368
2369 ++begin;
2370 if (begin == end) return handler.on_error("invalid format string"), end;
2371 if (*begin == '}') {
2372 handler.on_replacement_field(handler.on_arg_id(), begin);
2373 } else if (*begin == '{') {
2374 handler.on_text(begin, begin + 1);
2375 } else {
2376 auto adapter = id_adapter{handler, 0};
2377 begin = parse_arg_id(begin, end, adapter);
2378 Char c = begin != end ? *begin : Char();
2379 if (c == '}') {
2380 handler.on_replacement_field(adapter.arg_id, begin);
2381 } else if (c == ':') {
2382 begin = handler.on_format_specs(adapter.arg_id, begin + 1, end);
2383 if (begin == end || *begin != '}')
2384 return handler.on_error("unknown format specifier"), end;
2385 } else {
2386 return handler.on_error("missing '}' in format string"), end;
2387 }
2388 }
2389 return begin + 1;
2390}
2391
2392template <bool IS_CONSTEXPR, typename Char, typename Handler>
2393FMT_CONSTEXPR FMT_INLINE void parse_format_string(
2394 basic_string_view<Char> format_str, Handler&& handler) {
2395 // this is most likely a name-lookup defect in msvc's modules implementation
2396 using detail::find;
2397
2398 auto begin = format_str.data();
2399 auto end = begin + format_str.size();
2400 if (end - begin < 32) {
2401 // Use a simple loop instead of memchr for small strings.
2402 const Char* p = begin;
2403 while (p != end) {
2404 auto c = *p++;
2405 if (c == '{') {
2406 handler.on_text(begin, p - 1);
2407 begin = p = parse_replacement_field(p - 1, end, handler);
2408 } else if (c == '}') {
2409 if (p == end || *p != '}')
2410 return handler.on_error("unmatched '}' in format string");
2411 handler.on_text(begin, p);
2412 begin = ++p;
2413 }
2414 }
2415 handler.on_text(begin, end);
2416 return;
2417 }
2418 struct writer {
2419 FMT_CONSTEXPR void operator()(const Char* pbegin, const Char* pend) {
2420 if (pbegin == pend) return;
2421 for (;;) {
2422 const Char* p = nullptr;
2423 if (!find<IS_CONSTEXPR>(pbegin, pend, '}', p))
2424 return handler_.on_text(pbegin, pend);
2425 ++p;
2426 if (p == pend || *p != '}')
2427 return handler_.on_error("unmatched '}' in format string");
2428 handler_.on_text(pbegin, p);
2429 pbegin = p + 1;
2430 }
2431 }
2432 Handler& handler_;
2433 } write{handler};
2434 while (begin != end) {
2435 // Doing two passes with memchr (one for '{' and another for '}') is up to
2436 // 2.5x faster than the naive one-pass implementation on big format strings.
2437 const Char* p = begin;
2438 if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, '{', p))
2439 return write(begin, end);
2440 write(begin, p);
2441 begin = parse_replacement_field(p, end, handler);
2442 }
2443}
2444
2445template <typename T, typename ParseContext>
2446FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx)
2447 -> decltype(ctx.begin()) {
2448 using char_type = typename ParseContext::char_type;
2449 using context = buffer_context<char_type>;
2450 using mapped_type = conditional_t<
2451 mapped_type_constant<T, context>::value != type::custom_type,
2452 decltype(arg_mapper<context>().map(std::declval<const T&>())), T>;
2453 auto f = conditional_t<has_formatter<mapped_type, context>::value,
2454 formatter<mapped_type, char_type>,
2455 fallback_formatter<T, char_type>>();
2456 return f.parse(ctx);
2457}
2458
2459// A parse context with extra argument id checks. It is only used at compile
2460// time because adding checks at runtime would introduce substantial overhead
2461// and would be redundant since argument ids are checked when arguments are
2462// retrieved anyway.
2463template <typename Char, typename ErrorHandler = error_handler>
2464class compile_parse_context
2465 : public basic_format_parse_context<Char, ErrorHandler> {
2466 private:
2467 int num_args_;
2468 using base = basic_format_parse_context<Char, ErrorHandler>;
2469
2470 public:
2471 explicit FMT_CONSTEXPR compile_parse_context(
2472 basic_string_view<Char> format_str,
2473 int num_args = (std::numeric_limits<int>::max)(), ErrorHandler eh = {})
2474 : base(format_str, eh), num_args_(num_args) {}
2475
2476 FMT_CONSTEXPR auto next_arg_id() -> int {
2477 int id = base::next_arg_id();
2478 if (id >= num_args_) this->on_error("argument not found");
2479 return id;
2480 }
2481
2482 FMT_CONSTEXPR void check_arg_id(int id) {
2483 base::check_arg_id(id);
2484 if (id >= num_args_) this->on_error("argument not found");
2485 }
2486 using base::check_arg_id;
2487};
2488
2489template <typename ErrorHandler>
2490FMT_CONSTEXPR void check_int_type_spec(char spec, ErrorHandler&& eh) {
2491 switch (spec) {
2492 case 0:
2493 case 'd':
2494 case 'x':
2495 case 'X':
2496 case 'b':
2497 case 'B':
2498 case 'o':
2499 case 'c':
2500 break;
2501 default:
2502 eh.on_error("invalid type specifier");
2503 break;
2504 }
2505}
2506
2507// Checks char specs and returns true if the type spec is char (and not int).
2508template <typename Char, typename ErrorHandler = error_handler>
2509FMT_CONSTEXPR auto check_char_specs(const basic_format_specs<Char>& specs,
2510 ErrorHandler&& eh = {}) -> bool {
2511 if (specs.type && specs.type != 'c') {
2512 check_int_type_spec(specs.type, eh);
2513 return false;
2514 }
2515 if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
2516 eh.on_error("invalid format specifier for char");
2517 return true;
2518}
2519
2520// A floating-point presentation format.
2521enum class float_format : unsigned char {
2522 general, // General: exponent notation or fixed point based on magnitude.
2523 exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3.
2524 fixed, // Fixed point with the default precision of 6, e.g. 0.0012.
2525 hex
2526};
2527
2528struct float_specs {
2529 int precision;
2530 float_format format : 8;
2531 sign_t sign : 8;
2532 bool upper : 1;
2533 bool locale : 1;
2534 bool binary32 : 1;
2535 bool use_grisu : 1;
2536 bool showpoint : 1;
2537};
2538
2539template <typename ErrorHandler = error_handler, typename Char>
2540FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs<Char>& specs,
2541 ErrorHandler&& eh = {})
2542 -> float_specs {
2543 auto result = float_specs();
2544 result.showpoint = specs.alt;
2545 result.locale = specs.localized;
2546 switch (specs.type) {
2547 case 0:
2548 result.format = float_format::general;
2549 break;
2550 case 'G':
2551 result.upper = true;
2552 FMT_FALLTHROUGH;
2553 case 'g':
2554 result.format = float_format::general;
2555 break;
2556 case 'E':
2557 result.upper = true;
2558 FMT_FALLTHROUGH;
2559 case 'e':
2560 result.format = float_format::exp;
2561 result.showpoint |= specs.precision != 0;
2562 break;
2563 case 'F':
2564 result.upper = true;
2565 FMT_FALLTHROUGH;
2566 case 'f':
2567 result.format = float_format::fixed;
2568 result.showpoint |= specs.precision != 0;
2569 break;
2570 case 'A':
2571 result.upper = true;
2572 FMT_FALLTHROUGH;
2573 case 'a':
2574 result.format = float_format::hex;
2575 break;
2576 default:
2577 eh.on_error("invalid type specifier");
2578 break;
2579 }
2580 return result;
2581}
2582
2583template <typename Char, typename ErrorHandler = error_handler>
2584FMT_CONSTEXPR auto check_cstring_type_spec(Char spec, ErrorHandler&& eh = {})
2585 -> bool {
2586 if (spec == 0 || spec == 's') return true;
2587 if (spec != 'p') eh.on_error("invalid type specifier");
2588 return false;
2589}
2590
2591template <typename Char, typename ErrorHandler>
2592FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh) {
2593 if (spec != 0 && spec != 's') eh.on_error("invalid type specifier");
2594}
2595
2596template <typename Char, typename ErrorHandler>
2597FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) {
2598 if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier");
2599}
2600
2601// A parse_format_specs handler that checks if specifiers are consistent with
2602// the argument type.
2603template <typename Handler> class specs_checker : public Handler {
2604 private:
2605 detail::type arg_type_;
2606
2607 FMT_CONSTEXPR void require_numeric_argument() {
2608 if (!is_arithmetic_type(arg_type_))
2609 this->on_error("format specifier requires numeric argument");
2610 }
2611
2612 public:
2613 FMT_CONSTEXPR specs_checker(const Handler& handler, detail::type arg_type)
2614 : Handler(handler), arg_type_(arg_type) {}
2615
2616 FMT_CONSTEXPR void on_align(align_t align) {
2617 if (align == align::numeric) require_numeric_argument();
2618 Handler::on_align(align);
2619 }
2620
2621 FMT_CONSTEXPR void on_sign(sign_t s) {
2622 require_numeric_argument();
2623 if (is_integral_type(arg_type_) && arg_type_ != type::int_type &&
2624 arg_type_ != type::long_long_type && arg_type_ != type::char_type) {
2625 this->on_error("format specifier requires signed argument");
2626 }
2627 Handler::on_sign(s);
2628 }
2629
2630 FMT_CONSTEXPR void on_hash() {
2631 require_numeric_argument();
2632 Handler::on_hash();
2633 }
2634
2635 FMT_CONSTEXPR void on_localized() {
2636 require_numeric_argument();
2637 Handler::on_localized();
2638 }
2639
2640 FMT_CONSTEXPR void on_zero() {
2641 require_numeric_argument();
2642 Handler::on_zero();
2643 }
2644
2645 FMT_CONSTEXPR void end_precision() {
2646 if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type)
2647 this->on_error("precision not allowed for this argument type");
2648 }
2649};
2650
2651constexpr int invalid_arg_index = -1;
2652
2653#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
2654template <int N, typename T, typename... Args, typename Char>
2655constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
2656 if constexpr (detail::is_statically_named_arg<T>()) {
2657 if (name == T::name) return N;
2658 }
2659 if constexpr (sizeof...(Args) > 0)
2660 return get_arg_index_by_name<N + 1, Args...>(name);
2661 (void)name; // Workaround an MSVC bug about "unused" parameter.
2662 return invalid_arg_index;
2663}
2664#endif
2665
2666template <typename... Args, typename Char>
2667FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
2668#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
2669 if constexpr (sizeof...(Args) > 0)
2670 return get_arg_index_by_name<0, Args...>(name);
2671#endif
2672 (void)name;
2673 return invalid_arg_index;
2674}
2675
2676template <typename Char, typename ErrorHandler, typename... Args>
2677class format_string_checker {
2678 private:
2679 using parse_context_type = compile_parse_context<Char, ErrorHandler>;
2680 enum { num_args = sizeof...(Args) };
2681
2682 // Format specifier parsing function.
2683 using parse_func = const Char* (*)(parse_context_type&);
2684
2685 parse_context_type context_;
2686 parse_func parse_funcs_[num_args > 0 ? num_args : 1];
2687
2688 public:
2689 explicit FMT_CONSTEXPR format_string_checker(
2690 basic_string_view<Char> format_str, ErrorHandler eh)
2691 : context_(format_str, num_args, eh),
2692 parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}
2693
2694 FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
2695
2696 FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); }
2697 FMT_CONSTEXPR auto on_arg_id(int id) -> int {
2698 return context_.check_arg_id(id), id;
2699 }
2700 FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
2701#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
2702 auto index = get_arg_index_by_name<Args...>(id);
2703 if (index == invalid_arg_index) on_error("named argument is not found");
2704 return context_.check_arg_id(index), index;
2705#else
2706 (void)id;
2707 on_error("compile-time checks for named arguments require C++20 support");
2708 return 0;
2709#endif
2710 }
2711
2712 FMT_CONSTEXPR void on_replacement_field(int, const Char*) {}
2713
2714 FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char*)
2715 -> const Char* {
2716 context_.advance_to(context_.begin() + (begin - &*context_.begin()));
2717 // id >= 0 check is a workaround for gcc 10 bug (#2065).
2718 return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin;
2719 }
2720
2721 FMT_CONSTEXPR void on_error(const char* message) {
2722 context_.on_error(message);
2723 }
2724};
2725
2726template <typename... Args, typename S,
2727 enable_if_t<(is_compile_string<S>::value), int>>
2728void check_format_string(S format_str) {
2729 FMT_CONSTEXPR auto s = to_string_view(format_str);
2730 using checker = format_string_checker<typename S::char_type, error_handler,
2731 remove_cvref_t<Args>...>;
2732 FMT_CONSTEXPR bool invalid_format =
2733 (parse_format_string<true>(s, checker(s, {})), true);
2734 (void)invalid_format;
2735}
2736
2737template <typename Char>
2738void vformat_to(
2739 buffer<Char>& buf, basic_string_view<Char> fmt,
2740 basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args,
2741 detail::locale_ref loc = {});
11fdf7f2 2742
f67539c2
TL
2743FMT_API void vprint_mojibake(std::FILE*, string_view, format_args);
2744#ifndef _WIN32
2745inline void vprint_mojibake(std::FILE*, string_view, format_args) {}
2746#endif
20effc67 2747FMT_END_DETAIL_NAMESPACE
11fdf7f2 2748
20effc67
TL
2749// A formatter specialization for the core types corresponding to detail::type
2750// constants.
2751template <typename T, typename Char>
2752struct formatter<T, Char,
2753 enable_if_t<detail::type_constant<T, Char>::value !=
2754 detail::type::custom_type>> {
2755 private:
2756 detail::dynamic_format_specs<Char> specs_;
11fdf7f2 2757
20effc67
TL
2758 public:
2759 // Parses format specifiers stopping either at the end of the range or at the
2760 // terminating '}'.
2761 template <typename ParseContext>
2762 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
2763 auto begin = ctx.begin(), end = ctx.end();
2764 if (begin == end) return begin;
2765 using handler_type = detail::dynamic_specs_handler<ParseContext>;
2766 auto type = detail::type_constant<T, Char>::value;
2767 auto checker =
2768 detail::specs_checker<handler_type>(handler_type(specs_, ctx), type);
2769 auto it = detail::parse_format_specs(begin, end, checker);
2770 auto eh = ctx.error_handler();
2771 switch (type) {
2772 case detail::type::none_type:
2773 FMT_ASSERT(false, "invalid argument type");
2774 break;
2775 case detail::type::bool_type:
2776 if (!specs_.type || specs_.type == 's') break;
2777 FMT_FALLTHROUGH;
2778 case detail::type::int_type:
2779 case detail::type::uint_type:
2780 case detail::type::long_long_type:
2781 case detail::type::ulong_long_type:
2782 case detail::type::int128_type:
2783 case detail::type::uint128_type:
2784 detail::check_int_type_spec(specs_.type, eh);
2785 break;
2786 case detail::type::char_type:
2787 detail::check_char_specs(specs_, eh);
2788 break;
2789 case detail::type::float_type:
2790 if (detail::const_check(FMT_USE_FLOAT))
2791 detail::parse_float_type_spec(specs_, eh);
2792 else
2793 FMT_ASSERT(false, "float support disabled");
2794 break;
2795 case detail::type::double_type:
2796 if (detail::const_check(FMT_USE_DOUBLE))
2797 detail::parse_float_type_spec(specs_, eh);
2798 else
2799 FMT_ASSERT(false, "double support disabled");
2800 break;
2801 case detail::type::long_double_type:
2802 if (detail::const_check(FMT_USE_LONG_DOUBLE))
2803 detail::parse_float_type_spec(specs_, eh);
2804 else
2805 FMT_ASSERT(false, "long double support disabled");
2806 break;
2807 case detail::type::cstring_type:
2808 detail::check_cstring_type_spec(specs_.type, eh);
2809 break;
2810 case detail::type::string_type:
2811 detail::check_string_type_spec(specs_.type, eh);
2812 break;
2813 case detail::type::pointer_type:
2814 detail::check_pointer_type_spec(specs_.type, eh);
2815 break;
2816 case detail::type::custom_type:
2817 // Custom format specifiers are checked in parse functions of
2818 // formatter specializations.
2819 break;
2820 }
2821 return it;
2822 }
2823
2824 template <typename FormatContext>
2825 FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const
2826 -> decltype(ctx.out());
2827};
2828
2829template <typename Char> struct basic_runtime { basic_string_view<Char> str; };
2830
2831template <typename Char, typename... Args> class basic_format_string {
2832 private:
2833 basic_string_view<Char> str_;
2834
2835 public:
2836 template <typename S,
2837 FMT_ENABLE_IF(
2838 std::is_convertible<const S&, basic_string_view<Char>>::value)>
2839 FMT_CONSTEVAL basic_format_string(const S& s) : str_(s) {
2840 static_assert(
2841 detail::count<
2842 (std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
2843 std::is_reference<Args>::value)...>() == 0,
2844 "passing views as lvalues is disallowed");
2845#ifdef FMT_HAS_CONSTEVAL
2846 if constexpr (detail::count_named_args<Args...>() == 0) {
2847 using checker = detail::format_string_checker<Char, detail::error_handler,
2848 remove_cvref_t<Args>...>;
2849 detail::parse_format_string<true>(str_, checker(s, {}));
2850 }
2851#else
2852 detail::check_format_string<Args...>(s);
2853#endif
2854 }
2855 basic_format_string(basic_runtime<Char> r) : str_(r.str) {}
11fdf7f2 2856
20effc67
TL
2857 FMT_INLINE operator basic_string_view<Char>() const { return str_; }
2858};
2859
2860#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
2861// Workaround broken conversion on older gcc.
2862template <typename... Args> using format_string = string_view;
2863template <typename S> auto runtime(const S& s) -> basic_string_view<char_t<S>> {
2864 return s;
2865}
2866#else
2867template <typename... Args>
2868using format_string = basic_format_string<char, type_identity_t<Args>...>;
2869// Creates a runtime format string.
2870template <typename S> auto runtime(const S& s) -> basic_runtime<char_t<S>> {
2871 return {{s}};
11fdf7f2 2872}
20effc67
TL
2873#endif
2874
2875FMT_API auto vformat(string_view fmt, format_args args) -> std::string;
11fdf7f2
TL
2876
2877/**
2878 \rst
20effc67
TL
2879 Formats ``args`` according to specifications in ``fmt`` and returns the result
2880 as a string.
11fdf7f2
TL
2881
2882 **Example**::
2883
2884 #include <fmt/core.h>
2885 std::string message = fmt::format("The answer is {}", 42);
2886 \endrst
2887*/
20effc67
TL
2888template <typename... T>
2889FMT_INLINE auto format(format_string<T...> fmt, T&&... args) -> std::string {
2890 return vformat(fmt, fmt::make_format_args(args...));
2891}
2892
2893/** Formats a string and writes the output to ``out``. */
2894template <typename OutputIt,
2895 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
2896auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt {
2897 using detail::get_buffer;
2898 auto&& buf = get_buffer<char>(out);
2899 detail::vformat_to(buf, string_view(fmt), args);
2900 return detail::get_iterator(buf);
2901}
2902
2903/**
2904 \rst
2905 Formats ``args`` according to specifications in ``fmt``, writes the result to
2906 the output iterator ``out`` and returns the iterator past the end of the output
2907 range.
2908
2909 **Example**::
2910
2911 auto out = std::vector<char>();
2912 fmt::format_to(std::back_inserter(out), "{}", 42);
2913 \endrst
2914 */
2915template <typename OutputIt, typename... T,
2916 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
2917FMT_INLINE auto format_to(OutputIt out, format_string<T...> fmt, T&&... args)
2918 -> OutputIt {
2919 return vformat_to(out, fmt, fmt::make_format_args(args...));
11fdf7f2
TL
2920}
2921
20effc67
TL
2922template <typename OutputIt> struct format_to_n_result {
2923 /** Iterator past the end of the output range. */
2924 OutputIt out;
2925 /** Total (not truncated) output size. */
2926 size_t size;
2927};
2928
2929template <typename OutputIt, typename... T,
2930 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
2931auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args)
2932 -> format_to_n_result<OutputIt> {
2933 using buffer =
2934 detail::iterator_buffer<OutputIt, char, detail::fixed_buffer_traits>;
2935 auto buf = buffer(out, n);
2936 detail::vformat_to(buf, fmt, args);
2937 return {buf.out(), buf.count()};
2938}
11fdf7f2
TL
2939
2940/**
2941 \rst
20effc67
TL
2942 Formats ``args`` according to specifications in ``fmt``, writes up to ``n``
2943 characters of the result to the output iterator ``out`` and returns the total
2944 (not truncated) output size and the iterator past the end of the output range.
2945 \endrst
2946 */
2947template <typename OutputIt, typename... T,
2948 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
2949FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string<T...> fmt,
2950 const T&... args) -> format_to_n_result<OutputIt> {
2951 return vformat_to_n(out, n, fmt, fmt::make_format_args(args...));
2952}
2953
2954/** Returns the number of chars in the output of ``format(fmt, args...)``. */
2955template <typename... T>
2956FMT_INLINE auto formatted_size(format_string<T...> fmt, T&&... args) -> size_t {
2957 auto buf = detail::counting_buffer<>();
2958 detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...));
2959 return buf.count();
2960}
2961
2962FMT_API void vprint(string_view fmt, format_args args);
2963FMT_API void vprint(std::FILE* f, string_view fmt, format_args args);
2964
2965/**
2966 \rst
2967 Formats ``args`` according to specifications in ``fmt`` and writes the output
2968 to ``stdout``.
11fdf7f2
TL
2969
2970 **Example**::
2971
20effc67 2972 fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
11fdf7f2
TL
2973 \endrst
2974 */
20effc67
TL
2975template <typename... T>
2976FMT_INLINE void print(format_string<T...> fmt, T&&... args) {
2977 const auto& vargs = fmt::make_format_args(args...);
2978 return detail::is_utf8() ? vprint(fmt, vargs)
2979 : detail::vprint_mojibake(stdout, fmt, vargs);
11fdf7f2
TL
2980}
2981
11fdf7f2
TL
2982/**
2983 \rst
20effc67
TL
2984 Formats ``args`` according to specifications in ``fmt`` and writes the
2985 output to the file ``f``.
11fdf7f2
TL
2986
2987 **Example**::
2988
20effc67 2989 fmt::print(stderr, "Don't {}!", "panic");
11fdf7f2
TL
2990 \endrst
2991 */
20effc67
TL
2992template <typename... T>
2993FMT_INLINE void print(std::FILE* f, format_string<T...> fmt, T&&... args) {
2994 const auto& vargs = fmt::make_format_args(args...);
2995 return detail::is_utf8() ? vprint(f, fmt, vargs)
2996 : detail::vprint_mojibake(f, fmt, vargs);
11fdf7f2 2997}
20effc67
TL
2998
2999FMT_MODULE_EXPORT_END
3000FMT_GCC_PRAGMA("GCC pop_options")
11fdf7f2
TL
3001FMT_END_NAMESPACE
3002
20effc67
TL
3003#ifdef FMT_HEADER_ONLY
3004# include "format.h"
3005#endif
11fdf7f2 3006#endif // FMT_CORE_H_