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