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