1 // Formatting library for C++ - the core API for char/UTF-8
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
6 // For the license information refer to format.h.
11 #include <cstddef> // std::byte
12 #include <cstdio> // std::FILE
13 #include <cstring> // std::strlen
17 #include <type_traits>
19 // The fmt library version in the form major * 10000 + minor * 100 + patch.
20 #define FMT_VERSION 90100
22 #if defined(__clang__) && !defined(__ibmxl__)
23 # define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
25 # define FMT_CLANG_VERSION 0
28 #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && \
29 !defined(__NVCOMPILER)
30 # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
32 # define FMT_GCC_VERSION 0
35 #ifndef FMT_GCC_PRAGMA
36 // Workaround _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884.
37 # if FMT_GCC_VERSION >= 504
38 # define FMT_GCC_PRAGMA(arg) _Pragma(arg)
40 # define FMT_GCC_PRAGMA(arg)
45 # define FMT_ICC_VERSION __ICL
46 #elif defined(__INTEL_COMPILER)
47 # define FMT_ICC_VERSION __INTEL_COMPILER
49 # define FMT_ICC_VERSION 0
53 # define FMT_MSC_VERSION _MSC_VER
54 # define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__))
56 # define FMT_MSC_VERSION 0
57 # define FMT_MSC_WARNING(...)
61 # define FMT_CPLUSPLUS _MSVC_LANG
63 # define FMT_CPLUSPLUS __cplusplus
67 # define FMT_HAS_FEATURE(x) __has_feature(x)
69 # define FMT_HAS_FEATURE(x) 0
72 #if (defined(__has_include) || FMT_ICC_VERSION >= 1600 || \
73 FMT_MSC_VERSION > 1900) && \
74 !defined(__INTELLISENSE__)
75 # define FMT_HAS_INCLUDE(x) __has_include(x)
77 # define FMT_HAS_INCLUDE(x) 0
80 #ifdef __has_cpp_attribute
81 # define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
83 # define FMT_HAS_CPP_ATTRIBUTE(x) 0
86 #define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
87 (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
89 #define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
90 (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
92 // Check if relaxed C++14 constexpr is supported.
93 // GCC doesn't allow throw in constexpr until version 6 (bug 67371).
94 #ifndef FMT_USE_CONSTEXPR
95 # if (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912 || \
96 (FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L)) && \
97 !FMT_ICC_VERSION && !defined(__NVCC__)
98 # define FMT_USE_CONSTEXPR 1
100 # define FMT_USE_CONSTEXPR 0
103 #if FMT_USE_CONSTEXPR
104 # define FMT_CONSTEXPR constexpr
106 # define FMT_CONSTEXPR
109 #if ((FMT_CPLUSPLUS >= 202002L) && \
110 (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 9)) || \
111 (FMT_CPLUSPLUS >= 201709L && FMT_GCC_VERSION >= 1002)
112 # define FMT_CONSTEXPR20 constexpr
114 # define FMT_CONSTEXPR20
117 // Check if constexpr std::char_traits<>::{compare,length} are supported.
118 #if defined(__GLIBCXX__)
119 # if FMT_CPLUSPLUS >= 201703L && defined(_GLIBCXX_RELEASE) && \
120 _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE.
121 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr
123 #elif defined(_LIBCPP_VERSION) && FMT_CPLUSPLUS >= 201703L && \
124 _LIBCPP_VERSION >= 4000
125 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr
126 #elif FMT_MSC_VERSION >= 1914 && FMT_CPLUSPLUS >= 201703L
127 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr
129 #ifndef FMT_CONSTEXPR_CHAR_TRAITS
130 # define FMT_CONSTEXPR_CHAR_TRAITS
133 // Check if exceptions are disabled.
134 #ifndef FMT_EXCEPTIONS
135 # if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
136 (FMT_MSC_VERSION && !_HAS_EXCEPTIONS)
137 # define FMT_EXCEPTIONS 0
139 # define FMT_EXCEPTIONS 1
143 #ifndef FMT_DEPRECATED
144 # if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VERSION >= 1900
145 # define FMT_DEPRECATED [[deprecated]]
147 # if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
148 # define FMT_DEPRECATED __attribute__((deprecated))
149 # elif FMT_MSC_VERSION
150 # define FMT_DEPRECATED __declspec(deprecated)
152 # define FMT_DEPRECATED /* deprecated */
157 // [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code
159 #if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && \
161 # define FMT_NORETURN [[noreturn]]
163 # define FMT_NORETURN
166 #if FMT_HAS_CPP17_ATTRIBUTE(fallthrough)
167 # define FMT_FALLTHROUGH [[fallthrough]]
168 #elif defined(__clang__)
169 # define FMT_FALLTHROUGH [[clang::fallthrough]]
170 #elif FMT_GCC_VERSION >= 700 && \
171 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
172 # define FMT_FALLTHROUGH [[gnu::fallthrough]]
174 # define FMT_FALLTHROUGH
177 #ifndef FMT_NODISCARD
178 # if FMT_HAS_CPP17_ATTRIBUTE(nodiscard)
179 # define FMT_NODISCARD [[nodiscard]]
181 # define FMT_NODISCARD
185 #ifndef FMT_USE_FLOAT
186 # define FMT_USE_FLOAT 1
188 #ifndef FMT_USE_DOUBLE
189 # define FMT_USE_DOUBLE 1
191 #ifndef FMT_USE_LONG_DOUBLE
192 # define FMT_USE_LONG_DOUBLE 1
196 # if FMT_GCC_VERSION || FMT_CLANG_VERSION
197 # define FMT_INLINE inline __attribute__((always_inline))
199 # define FMT_INLINE inline
203 // An inline std::forward replacement.
204 #define FMT_FORWARD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
207 # define FMT_UNCHECKED_ITERATOR(It) \
208 using _Unchecked_type = It // Mark iterator as checked.
210 # define FMT_UNCHECKED_ITERATOR(It) using unchecked_type = It
213 #ifndef FMT_BEGIN_NAMESPACE
214 # define FMT_BEGIN_NAMESPACE \
216 inline namespace v9 {
217 # define FMT_END_NAMESPACE \
222 #ifndef FMT_MODULE_EXPORT
223 # define FMT_MODULE_EXPORT
224 # define FMT_MODULE_EXPORT_BEGIN
225 # define FMT_MODULE_EXPORT_END
226 # define FMT_BEGIN_DETAIL_NAMESPACE namespace detail {
227 # define FMT_END_DETAIL_NAMESPACE }
230 #if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
231 # define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275)
233 # define FMT_API __declspec(dllexport)
234 # elif defined(FMT_SHARED)
235 # define FMT_API __declspec(dllimport)
238 # define FMT_CLASS_API
239 # if defined(FMT_EXPORT) || defined(FMT_SHARED)
240 # if defined(__GNUC__) || defined(__clang__)
241 # define FMT_API __attribute__((visibility("default")))
249 // libc++ supports string_view in pre-c++17.
250 #if FMT_HAS_INCLUDE(<string_view>) && \
251 (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION))
252 # include <string_view>
253 # define FMT_USE_STRING_VIEW
254 #elif FMT_HAS_INCLUDE("experimental/string_view") && FMT_CPLUSPLUS >= 201402L
255 # include <experimental/string_view>
256 # define FMT_USE_EXPERIMENTAL_STRING_VIEW
260 # define FMT_UNICODE !FMT_MSC_VERSION
263 #ifndef FMT_CONSTEVAL
264 # if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \
265 FMT_CPLUSPLUS >= 202002L && !defined(__apple_build_version__)) || \
266 (defined(__cpp_consteval) && \
267 (!FMT_MSC_VERSION || _MSC_FULL_VER >= 193030704))
268 // consteval is broken in MSVC before VS2022 and Apple clang 13.
269 # define FMT_CONSTEVAL consteval
270 # define FMT_HAS_CONSTEVAL
272 # define FMT_CONSTEVAL
276 #ifndef FMT_USE_NONTYPE_TEMPLATE_ARGS
277 # if defined(__cpp_nontype_template_args) && \
278 ((FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L) || \
279 __cpp_nontype_template_args >= 201911L) && \
280 !defined(__NVCOMPILER)
281 # define FMT_USE_NONTYPE_TEMPLATE_ARGS 1
283 # define FMT_USE_NONTYPE_TEMPLATE_ARGS 0
287 // Enable minimal optimizations for more compact code in debug mode.
288 FMT_GCC_PRAGMA("GCC push_options")
289 #if !defined(__OPTIMIZE__) && !defined(__NVCOMPILER)
290 FMT_GCC_PRAGMA("GCC optimize(\"Og\")")
294 FMT_MODULE_EXPORT_BEGIN
296 // Implementations of enable_if_t and other metafunctions for older systems.
297 template <bool B
, typename T
= void>
298 using enable_if_t
= typename
std::enable_if
<B
, T
>::type
;
299 template <bool B
, typename T
, typename F
>
300 using conditional_t
= typename
std::conditional
<B
, T
, F
>::type
;
301 template <bool B
> using bool_constant
= std::integral_constant
<bool, B
>;
302 template <typename T
>
303 using remove_reference_t
= typename
std::remove_reference
<T
>::type
;
304 template <typename T
>
305 using remove_const_t
= typename
std::remove_const
<T
>::type
;
306 template <typename T
>
307 using remove_cvref_t
= typename
std::remove_cv
<remove_reference_t
<T
>>::type
;
308 template <typename T
> struct type_identity
{ using type
= T
; };
309 template <typename T
> using type_identity_t
= typename type_identity
<T
>::type
;
310 template <typename T
>
311 using underlying_t
= typename
std::underlying_type
<T
>::type
;
313 template <typename
...> struct disjunction
: std::false_type
{};
314 template <typename P
> struct disjunction
<P
> : P
{};
315 template <typename P1
, typename
... Pn
>
316 struct disjunction
<P1
, Pn
...>
317 : conditional_t
<bool(P1::value
), P1
, disjunction
<Pn
...>> {};
319 template <typename
...> struct conjunction
: std::true_type
{};
320 template <typename P
> struct conjunction
<P
> : P
{};
321 template <typename P1
, typename
... Pn
>
322 struct conjunction
<P1
, Pn
...>
323 : conditional_t
<bool(P1::value
), conjunction
<Pn
...>, P1
> {};
326 constexpr monostate() {}
329 // An enable_if helper to be used in template parameters which results in much
330 // shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
331 // to workaround a bug in MSVC 2019 (see #1140 and #1186).
333 # define FMT_ENABLE_IF(...)
335 # define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0
338 FMT_BEGIN_DETAIL_NAMESPACE
340 // Suppresses "unused variable" warnings with the method described in
341 // https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/.
342 // (void)var does not work on many Intel compilers.
343 template <typename
... T
> FMT_CONSTEXPR
void ignore_unused(const T
&...) {}
345 constexpr FMT_INLINE
auto is_constant_evaluated(
346 bool default_value
= false) noexcept
-> bool {
347 #ifdef __cpp_lib_is_constant_evaluated
348 ignore_unused(default_value
);
349 return std::is_constant_evaluated();
351 return default_value
;
355 // Suppresses "conditional expression is constant" warnings.
356 template <typename T
> constexpr FMT_INLINE
auto const_check(T value
) -> T
{
360 FMT_NORETURN FMT_API
void assert_fail(const char* file
, int line
,
361 const char* message
);
365 // FMT_ASSERT is not empty to avoid -Wempty-body.
366 # define FMT_ASSERT(condition, message) \
367 ::fmt::detail::ignore_unused((condition), (message))
369 # define FMT_ASSERT(condition, message) \
370 ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
372 : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
376 #if defined(FMT_USE_STRING_VIEW)
377 template <typename Char
> using std_string_view
= std::basic_string_view
<Char
>;
378 #elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
379 template <typename Char
>
380 using std_string_view
= std::experimental::basic_string_view
<Char
>;
382 template <typename T
> struct std_string_view
{};
385 #ifdef FMT_USE_INT128
387 #elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \
388 !(FMT_CLANG_VERSION && FMT_MSC_VERSION)
389 # define FMT_USE_INT128 1
390 using int128_opt
= __int128_t
; // An optional native 128-bit integer.
391 using uint128_opt
= __uint128_t
;
392 template <typename T
> inline auto convert_for_visit(T value
) -> T
{
396 # define FMT_USE_INT128 0
399 enum class int128_opt
{};
400 enum class uint128_opt
{};
401 // Reduce template instantiations.
402 template <typename T
> auto convert_for_visit(T
) -> monostate
{ return {}; }
405 // Casts a nonnegative integer to unsigned.
406 template <typename Int
>
407 FMT_CONSTEXPR
auto to_unsigned(Int value
) ->
408 typename
std::make_unsigned
<Int
>::type
{
409 FMT_ASSERT(std::is_unsigned
<Int
>::value
|| value
>= 0, "negative value");
410 return static_cast<typename
std::make_unsigned
<Int
>::type
>(value
);
413 FMT_MSC_WARNING(suppress
: 4566) constexpr unsigned char micro
[] = "\u00B5";
415 constexpr auto is_utf8() -> bool {
416 // Avoid buggy sign extensions in MSVC's constant evaluation mode (#2297).
417 using uchar
= unsigned char;
418 return FMT_UNICODE
|| (sizeof(micro
) == 3 && uchar(micro
[0]) == 0xC2 &&
419 uchar(micro
[1]) == 0xB5);
421 FMT_END_DETAIL_NAMESPACE
424 An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
425 subset of the API. ``fmt::basic_string_view`` is used for format strings even
426 if ``std::string_view`` is available to prevent issues when a library is
427 compiled with a different ``-std`` option than the client code (which is not
430 template <typename Char
> class basic_string_view
{
436 using value_type
= Char
;
437 using iterator
= const Char
*;
439 constexpr basic_string_view() noexcept
: data_(nullptr), size_(0) {}
441 /** Constructs a string reference object from a C string and a size. */
442 constexpr basic_string_view(const Char
* s
, size_t count
) noexcept
443 : data_(s
), size_(count
) {}
447 Constructs a string reference object from a C string computing
448 the size with ``std::char_traits<Char>::length``.
451 FMT_CONSTEXPR_CHAR_TRAITS
453 basic_string_view(const Char
* s
)
455 size_(detail::const_check(std::is_same
<Char
, char>::value
&&
456 !detail::is_constant_evaluated(true))
457 ? std::strlen(reinterpret_cast<const char*>(s
))
458 : std::char_traits
<Char
>::length(s
)) {}
460 /** Constructs a string reference from a ``std::basic_string`` object. */
461 template <typename Traits
, typename Alloc
>
462 FMT_CONSTEXPR
basic_string_view(
463 const std::basic_string
<Char
, Traits
, Alloc
>& s
) noexcept
464 : data_(s
.data()), size_(s
.size()) {}
466 template <typename S
, FMT_ENABLE_IF(std::is_same
<
467 S
, detail::std_string_view
<Char
>>::value
)>
468 FMT_CONSTEXPR
basic_string_view(S s
) noexcept
469 : data_(s
.data()), size_(s
.size()) {}
471 /** Returns a pointer to the string data. */
472 constexpr auto data() const noexcept
-> const Char
* { return data_
; }
474 /** Returns the string size. */
475 constexpr auto size() const noexcept
-> size_t { return size_
; }
477 constexpr auto begin() const noexcept
-> iterator
{ return data_
; }
478 constexpr auto end() const noexcept
-> iterator
{ return data_
+ size_
; }
480 constexpr auto operator[](size_t pos
) const noexcept
-> const Char
& {
484 FMT_CONSTEXPR
void remove_prefix(size_t n
) noexcept
{
489 // Lexicographically compare this string reference to other.
490 FMT_CONSTEXPR_CHAR_TRAITS
auto compare(basic_string_view other
) const -> int {
491 size_t str_size
= size_
< other
.size_
? size_
: other
.size_
;
492 int result
= std::char_traits
<Char
>::compare(data_
, other
.data_
, str_size
);
494 result
= size_
== other
.size_
? 0 : (size_
< other
.size_
? -1 : 1);
498 FMT_CONSTEXPR_CHAR_TRAITS
friend auto operator==(basic_string_view lhs
,
499 basic_string_view rhs
)
501 return lhs
.compare(rhs
) == 0;
503 friend auto operator!=(basic_string_view lhs
, basic_string_view rhs
) -> bool {
504 return lhs
.compare(rhs
) != 0;
506 friend auto operator<(basic_string_view lhs
, basic_string_view rhs
) -> bool {
507 return lhs
.compare(rhs
) < 0;
509 friend auto operator<=(basic_string_view lhs
, basic_string_view rhs
) -> bool {
510 return lhs
.compare(rhs
) <= 0;
512 friend auto operator>(basic_string_view lhs
, basic_string_view rhs
) -> bool {
513 return lhs
.compare(rhs
) > 0;
515 friend auto operator>=(basic_string_view lhs
, basic_string_view rhs
) -> bool {
516 return lhs
.compare(rhs
) >= 0;
520 using string_view
= basic_string_view
<char>;
522 /** Specifies if ``T`` is a character type. Can be specialized by users. */
523 template <typename T
> struct is_char
: std::false_type
{};
524 template <> struct is_char
<char> : std::true_type
{};
526 FMT_BEGIN_DETAIL_NAMESPACE
528 // A base class for compile-time strings.
529 struct compile_string
{};
531 template <typename S
>
532 struct is_compile_string
: std::is_base_of
<compile_string
, S
> {};
534 // Returns a string view of `s`.
535 template <typename Char
, FMT_ENABLE_IF(is_char
<Char
>::value
)>
536 FMT_INLINE
auto to_string_view(const Char
* s
) -> basic_string_view
<Char
> {
539 template <typename Char
, typename Traits
, typename Alloc
>
540 inline auto to_string_view(const std::basic_string
<Char
, Traits
, Alloc
>& s
)
541 -> basic_string_view
<Char
> {
544 template <typename Char
>
545 constexpr auto to_string_view(basic_string_view
<Char
> s
)
546 -> basic_string_view
<Char
> {
549 template <typename Char
,
550 FMT_ENABLE_IF(!std::is_empty
<std_string_view
<Char
>>::value
)>
551 inline auto to_string_view(std_string_view
<Char
> s
) -> basic_string_view
<Char
> {
554 template <typename S
, FMT_ENABLE_IF(is_compile_string
<S
>::value
)>
555 constexpr auto to_string_view(const S
& s
)
556 -> basic_string_view
<typename
S::char_type
> {
557 return basic_string_view
<typename
S::char_type
>(s
);
559 void to_string_view(...);
561 // Specifies whether S is a string type convertible to fmt::basic_string_view.
562 // It should be a constexpr function but MSVC 2017 fails to compile it in
563 // enable_if and MSVC 2015 fails to compile it as an alias template.
564 // ADL invocation of to_string_view is DEPRECATED!
565 template <typename S
>
566 struct is_string
: std::is_class
<decltype(to_string_view(std::declval
<S
>()))> {
569 template <typename S
, typename
= void> struct char_t_impl
{};
570 template <typename S
> struct char_t_impl
<S
, enable_if_t
<is_string
<S
>::value
>> {
571 using result
= decltype(to_string_view(std::declval
<S
>()));
572 using type
= typename
result::value_type
;
577 // Integer types should go first,
586 last_integer_type
= char_type
,
587 // followed by floating-point types.
591 last_numeric_type
= long_double_type
,
598 // Maps core type T to the corresponding type enum constant.
599 template <typename T
, typename Char
>
600 struct type_constant
: std::integral_constant
<type
, type::custom_type
> {};
602 #define FMT_TYPE_CONSTANT(Type, constant) \
603 template <typename Char> \
604 struct type_constant<Type, Char> \
605 : std::integral_constant<type, type::constant> {}
607 FMT_TYPE_CONSTANT(int, int_type
);
608 FMT_TYPE_CONSTANT(unsigned, uint_type
);
609 FMT_TYPE_CONSTANT(long long, long_long_type
);
610 FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type
);
611 FMT_TYPE_CONSTANT(int128_opt
, int128_type
);
612 FMT_TYPE_CONSTANT(uint128_opt
, uint128_type
);
613 FMT_TYPE_CONSTANT(bool, bool_type
);
614 FMT_TYPE_CONSTANT(Char
, char_type
);
615 FMT_TYPE_CONSTANT(float, float_type
);
616 FMT_TYPE_CONSTANT(double, double_type
);
617 FMT_TYPE_CONSTANT(long double, long_double_type
);
618 FMT_TYPE_CONSTANT(const Char
*, cstring_type
);
619 FMT_TYPE_CONSTANT(basic_string_view
<Char
>, string_type
);
620 FMT_TYPE_CONSTANT(const void*, pointer_type
);
622 constexpr bool is_integral_type(type t
) {
623 return t
> type::none_type
&& t
<= type::last_integer_type
;
626 constexpr bool is_arithmetic_type(type t
) {
627 return t
> type::none_type
&& t
<= type::last_numeric_type
;
630 FMT_NORETURN FMT_API
void throw_format_error(const char* message
);
632 struct error_handler
{
633 constexpr error_handler() = default;
634 constexpr error_handler(const error_handler
&) = default;
636 // This function is intentionally not constexpr to give a compile-time error.
637 FMT_NORETURN
void on_error(const char* message
) {
638 throw_format_error(message
);
641 FMT_END_DETAIL_NAMESPACE
643 /** String's character type. */
644 template <typename S
> using char_t
= typename
detail::char_t_impl
<S
>::type
;
648 Parsing context consisting of a format string range being parsed and an
649 argument counter for automatic indexing.
650 You can use the ``format_parse_context`` type alias for ``char`` instead.
653 template <typename Char
, typename ErrorHandler
= detail::error_handler
>
654 class basic_format_parse_context
: private ErrorHandler
{
656 basic_string_view
<Char
> format_str_
;
659 FMT_CONSTEXPR
void do_check_arg_id(int id
);
662 using char_type
= Char
;
663 using iterator
= typename basic_string_view
<Char
>::iterator
;
665 explicit constexpr basic_format_parse_context(
666 basic_string_view
<Char
> format_str
, ErrorHandler eh
= {},
668 : ErrorHandler(eh
), format_str_(format_str
), next_arg_id_(next_arg_id
) {}
671 Returns an iterator to the beginning of the format string range being
674 constexpr auto begin() const noexcept
-> iterator
{
675 return format_str_
.begin();
679 Returns an iterator past the end of the format string range being parsed.
681 constexpr auto end() const noexcept
-> iterator
{ return format_str_
.end(); }
683 /** Advances the begin iterator to ``it``. */
684 FMT_CONSTEXPR
void advance_to(iterator it
) {
685 format_str_
.remove_prefix(detail::to_unsigned(it
- begin()));
689 Reports an error if using the manual argument indexing; otherwise returns
690 the next argument index and switches to the automatic indexing.
692 FMT_CONSTEXPR
auto next_arg_id() -> int {
693 if (next_arg_id_
< 0) {
694 on_error("cannot switch from manual to automatic argument indexing");
697 int id
= next_arg_id_
++;
703 Reports an error if using the automatic argument indexing; otherwise
704 switches to the manual indexing.
706 FMT_CONSTEXPR
void check_arg_id(int id
) {
707 if (next_arg_id_
> 0) {
708 on_error("cannot switch from automatic to manual argument indexing");
714 FMT_CONSTEXPR
void check_arg_id(basic_string_view
<Char
>) {}
715 FMT_CONSTEXPR
void check_dynamic_spec(int arg_id
);
717 FMT_CONSTEXPR
void on_error(const char* message
) {
718 ErrorHandler::on_error(message
);
721 constexpr auto error_handler() const -> ErrorHandler
{ return *this; }
724 using format_parse_context
= basic_format_parse_context
<char>;
726 FMT_BEGIN_DETAIL_NAMESPACE
727 // A parse context with extra data used only in compile-time checks.
728 template <typename Char
, typename ErrorHandler
= detail::error_handler
>
729 class compile_parse_context
730 : public basic_format_parse_context
<Char
, ErrorHandler
> {
734 using base
= basic_format_parse_context
<Char
, ErrorHandler
>;
737 explicit FMT_CONSTEXPR
compile_parse_context(
738 basic_string_view
<Char
> format_str
, int num_args
, const type
* types
,
739 ErrorHandler eh
= {}, int next_arg_id
= 0)
740 : base(format_str
, eh
, next_arg_id
), num_args_(num_args
), types_(types
) {}
742 constexpr auto num_args() const -> int { return num_args_
; }
743 constexpr auto arg_type(int id
) const -> type
{ return types_
[id
]; }
745 FMT_CONSTEXPR
auto next_arg_id() -> int {
746 int id
= base::next_arg_id();
747 if (id
>= num_args_
) this->on_error("argument not found");
751 FMT_CONSTEXPR
void check_arg_id(int id
) {
752 base::check_arg_id(id
);
753 if (id
>= num_args_
) this->on_error("argument not found");
755 using base::check_arg_id
;
757 FMT_CONSTEXPR
void check_dynamic_spec(int arg_id
) {
758 if (arg_id
< num_args_
&& types_
&& !is_integral_type(types_
[arg_id
]))
759 this->on_error("width/precision is not integer");
762 FMT_END_DETAIL_NAMESPACE
764 template <typename Char
, typename ErrorHandler
>
766 basic_format_parse_context
<Char
, ErrorHandler
>::do_check_arg_id(int id
) {
767 // Argument id is only checked at compile-time during parsing because
768 // formatting has its own validation.
769 if (detail::is_constant_evaluated() && FMT_GCC_VERSION
>= 1200) {
770 using context
= detail::compile_parse_context
<Char
, ErrorHandler
>;
771 if (id
>= static_cast<context
*>(this)->num_args())
772 on_error("argument not found");
776 template <typename Char
, typename ErrorHandler
>
778 basic_format_parse_context
<Char
, ErrorHandler
>::check_dynamic_spec(int arg_id
) {
779 if (detail::is_constant_evaluated()) {
780 using context
= detail::compile_parse_context
<Char
, ErrorHandler
>;
781 static_cast<context
*>(this)->check_dynamic_spec(arg_id
);
785 template <typename Context
> class basic_format_arg
;
786 template <typename Context
> class basic_format_args
;
787 template <typename Context
> class dynamic_format_arg_store
;
789 // A formatter for objects of type T.
790 template <typename T
, typename Char
= char, typename Enable
= void>
792 // A deleted default constructor indicates a disabled formatter.
793 formatter() = delete;
796 // Specifies if T has an enabled formatter specialization. A type can be
797 // formattable even if it doesn't have a formatter e.g. via a conversion.
798 template <typename T
, typename Context
>
799 using has_formatter
=
800 std::is_constructible
<typename
Context::template formatter_type
<T
>>;
802 // Checks whether T is a container with contiguous storage.
803 template <typename T
> struct is_contiguous
: std::false_type
{};
804 template <typename Char
>
805 struct is_contiguous
<std::basic_string
<Char
>> : std::true_type
{};
809 FMT_BEGIN_DETAIL_NAMESPACE
811 template <typename Context
, typename T
>
812 constexpr auto has_const_formatter_impl(T
*)
813 -> decltype(typename
Context::template formatter_type
<T
>().format(
814 std::declval
<const T
&>(), std::declval
<Context
&>()),
818 template <typename Context
>
819 constexpr auto has_const_formatter_impl(...) -> bool {
822 template <typename T
, typename Context
>
823 constexpr auto has_const_formatter() -> bool {
824 return has_const_formatter_impl
<Context
>(static_cast<T
*>(nullptr));
827 // Extracts a reference to the container from back_insert_iterator.
828 template <typename Container
>
829 inline auto get_container(std::back_insert_iterator
<Container
> it
)
831 using base
= std::back_insert_iterator
<Container
>;
832 struct accessor
: base
{
833 accessor(base b
) : base(b
) {}
834 using base::container
;
836 return *accessor(it
).container
;
839 template <typename Char
, typename InputIt
, typename OutputIt
>
840 FMT_CONSTEXPR
auto copy_str(InputIt begin
, InputIt end
, OutputIt out
)
842 while (begin
!= end
) *out
++ = static_cast<Char
>(*begin
++);
846 template <typename Char
, typename T
, typename U
,
848 std::is_same
<remove_const_t
<T
>, U
>::value
&& is_char
<U
>::value
)>
849 FMT_CONSTEXPR
auto copy_str(T
* begin
, T
* end
, U
* out
) -> U
* {
850 if (is_constant_evaluated()) return copy_str
<Char
, T
*, U
*>(begin
, end
, out
);
851 auto size
= to_unsigned(end
- begin
);
852 memcpy(out
, begin
, size
* sizeof(U
));
858 A contiguous memory buffer with an optional growing ability. It is an internal
859 class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`.
862 template <typename T
> class buffer
{
869 // Don't initialize ptr_ since it is not accessed to save a few cycles.
870 FMT_MSC_WARNING(suppress
: 26495)
871 buffer(size_t sz
) noexcept
: size_(sz
), capacity_(sz
) {}
873 FMT_CONSTEXPR20
buffer(T
* p
= nullptr, size_t sz
= 0, size_t cap
= 0) noexcept
874 : ptr_(p
), size_(sz
), capacity_(cap
) {}
876 FMT_CONSTEXPR20
~buffer() = default;
877 buffer(buffer
&&) = default;
879 /** Sets the buffer data and capacity. */
880 FMT_CONSTEXPR
void set(T
* buf_data
, size_t buf_capacity
) noexcept
{
882 capacity_
= buf_capacity
;
885 /** Increases the buffer capacity to hold at least *capacity* elements. */
886 virtual FMT_CONSTEXPR20
void grow(size_t capacity
) = 0;
889 using value_type
= T
;
890 using const_reference
= const T
&;
892 buffer(const buffer
&) = delete;
893 void operator=(const buffer
&) = delete;
895 auto begin() noexcept
-> T
* { return ptr_
; }
896 auto end() noexcept
-> T
* { return ptr_
+ size_
; }
898 auto begin() const noexcept
-> const T
* { return ptr_
; }
899 auto end() const noexcept
-> const T
* { return ptr_
+ size_
; }
901 /** Returns the size of this buffer. */
902 constexpr auto size() const noexcept
-> size_t { return size_
; }
904 /** Returns the capacity of this buffer. */
905 constexpr auto capacity() const noexcept
-> size_t { return capacity_
; }
907 /** Returns a pointer to the buffer data. */
908 FMT_CONSTEXPR
auto data() noexcept
-> T
* { return ptr_
; }
910 /** Returns a pointer to the buffer data. */
911 FMT_CONSTEXPR
auto data() const noexcept
-> const T
* { return ptr_
; }
913 /** Clears this buffer. */
914 void clear() { size_
= 0; }
916 // Tries resizing the buffer to contain *count* elements. If T is a POD type
917 // the new elements may not be initialized.
918 FMT_CONSTEXPR20
void try_resize(size_t count
) {
920 size_
= count
<= capacity_
? count
: capacity_
;
923 // Tries increasing the buffer capacity to *new_capacity*. It can increase the
924 // capacity by a smaller amount than requested but guarantees there is space
925 // for at least one additional element either by increasing the capacity or by
926 // flushing the buffer if it is full.
927 FMT_CONSTEXPR20
void try_reserve(size_t new_capacity
) {
928 if (new_capacity
> capacity_
) grow(new_capacity
);
931 FMT_CONSTEXPR20
void push_back(const T
& value
) {
932 try_reserve(size_
+ 1);
933 ptr_
[size_
++] = value
;
936 /** Appends data to the end of the buffer. */
937 template <typename U
> void append(const U
* begin
, const U
* end
);
939 template <typename Idx
> FMT_CONSTEXPR
auto operator[](Idx index
) -> T
& {
942 template <typename Idx
>
943 FMT_CONSTEXPR
auto operator[](Idx index
) const -> const T
& {
948 struct buffer_traits
{
949 explicit buffer_traits(size_t) {}
950 auto count() const -> size_t { return 0; }
951 auto limit(size_t size
) -> size_t { return size
; }
954 class fixed_buffer_traits
{
960 explicit fixed_buffer_traits(size_t limit
) : limit_(limit
) {}
961 auto count() const -> size_t { return count_
; }
962 auto limit(size_t size
) -> size_t {
963 size_t n
= limit_
> count_
? limit_
- count_
: 0;
965 return size
< n
? size
: n
;
969 // A buffer that writes to an output iterator when flushed.
970 template <typename OutputIt
, typename T
, typename Traits
= buffer_traits
>
971 class iterator_buffer final
: public Traits
, public buffer
<T
> {
974 enum { buffer_size
= 256 };
975 T data_
[buffer_size
];
978 FMT_CONSTEXPR20
void grow(size_t) override
{
979 if (this->size() == buffer_size
) flush();
983 auto size
= this->size();
985 out_
= copy_str
<T
>(data_
, data_
+ this->limit(size
), out_
);
989 explicit iterator_buffer(OutputIt out
, size_t n
= buffer_size
)
990 : Traits(n
), buffer
<T
>(data_
, 0, buffer_size
), out_(out
) {}
991 iterator_buffer(iterator_buffer
&& other
)
992 : Traits(other
), buffer
<T
>(data_
, 0, buffer_size
), out_(other
.out_
) {}
993 ~iterator_buffer() { flush(); }
995 auto out() -> OutputIt
{
999 auto count() const -> size_t { return Traits::count() + this->size(); }
1002 template <typename T
>
1003 class iterator_buffer
<T
*, T
, fixed_buffer_traits
> final
1004 : public fixed_buffer_traits
,
1008 enum { buffer_size
= 256 };
1009 T data_
[buffer_size
];
1012 FMT_CONSTEXPR20
void grow(size_t) override
{
1013 if (this->size() == this->capacity()) flush();
1017 size_t n
= this->limit(this->size());
1018 if (this->data() == out_
) {
1020 this->set(data_
, buffer_size
);
1026 explicit iterator_buffer(T
* out
, size_t n
= buffer_size
)
1027 : fixed_buffer_traits(n
), buffer
<T
>(out
, 0, n
), out_(out
) {}
1028 iterator_buffer(iterator_buffer
&& other
)
1029 : fixed_buffer_traits(other
),
1030 buffer
<T
>(std::move(other
)),
1032 if (this->data() != out_
) {
1033 this->set(data_
, buffer_size
);
1037 ~iterator_buffer() { flush(); }
1043 auto count() const -> size_t {
1044 return fixed_buffer_traits::count() + this->size();
1048 template <typename T
> class iterator_buffer
<T
*, T
> final
: public buffer
<T
> {
1050 FMT_CONSTEXPR20
void grow(size_t) override
{}
1053 explicit iterator_buffer(T
* out
, size_t = 0) : buffer
<T
>(out
, 0, ~size_t()) {}
1055 auto out() -> T
* { return &*this->end(); }
1058 // A buffer that writes to a container with the contiguous storage.
1059 template <typename Container
>
1060 class iterator_buffer
<std::back_insert_iterator
<Container
>,
1061 enable_if_t
<is_contiguous
<Container
>::value
,
1062 typename
Container::value_type
>>
1063 final
: public buffer
<typename
Container::value_type
> {
1065 Container
& container_
;
1068 FMT_CONSTEXPR20
void grow(size_t capacity
) override
{
1069 container_
.resize(capacity
);
1070 this->set(&container_
[0], capacity
);
1074 explicit iterator_buffer(Container
& c
)
1075 : buffer
<typename
Container::value_type
>(c
.size()), container_(c
) {}
1076 explicit iterator_buffer(std::back_insert_iterator
<Container
> out
, size_t = 0)
1077 : iterator_buffer(get_container(out
)) {}
1079 auto out() -> std::back_insert_iterator
<Container
> {
1080 return std::back_inserter(container_
);
1084 // A buffer that counts the number of code units written discarding the output.
1085 template <typename T
= char> class counting_buffer final
: public buffer
<T
> {
1087 enum { buffer_size
= 256 };
1088 T data_
[buffer_size
];
1092 FMT_CONSTEXPR20
void grow(size_t) override
{
1093 if (this->size() != buffer_size
) return;
1094 count_
+= this->size();
1099 counting_buffer() : buffer
<T
>(data_
, 0, buffer_size
) {}
1101 auto count() -> size_t { return count_
+ this->size(); }
1104 template <typename T
>
1105 using buffer_appender
= conditional_t
<std::is_same
<T
, char>::value
, appender
,
1106 std::back_insert_iterator
<buffer
<T
>>>;
1108 // Maps an output iterator to a buffer.
1109 template <typename T
, typename OutputIt
>
1110 auto get_buffer(OutputIt out
) -> iterator_buffer
<OutputIt
, T
> {
1111 return iterator_buffer
<OutputIt
, T
>(out
);
1114 template <typename Buffer
>
1115 auto get_iterator(Buffer
& buf
) -> decltype(buf
.out()) {
1118 template <typename T
> auto get_iterator(buffer
<T
>& buf
) -> buffer_appender
<T
> {
1119 return buffer_appender
<T
>(buf
);
1122 template <typename T
, typename Char
= char, typename Enable
= void>
1123 struct fallback_formatter
{
1124 fallback_formatter() = delete;
1127 // Specifies if T has an enabled fallback_formatter specialization.
1128 template <typename T
, typename Char
>
1129 using has_fallback_formatter
=
1130 #ifdef FMT_DEPRECATED_OSTREAM
1131 std::is_constructible
<fallback_formatter
<T
, Char
>>;
1138 template <typename Char
, typename T
> struct named_arg
: view
{
1141 named_arg(const Char
* n
, const T
& v
) : name(n
), value(v
) {}
1144 template <typename Char
> struct named_arg_info
{
1149 template <typename T
, typename Char
, size_t NUM_ARGS
, size_t NUM_NAMED_ARGS
>
1151 // args_[0].named_args points to named_args_ to avoid bloating format_args.
1152 // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
1153 T args_
[1 + (NUM_ARGS
!= 0 ? NUM_ARGS
: +1)];
1154 named_arg_info
<Char
> named_args_
[NUM_NAMED_ARGS
];
1156 template <typename
... U
>
1157 arg_data(const U
&... init
) : args_
{T(named_args_
, NUM_NAMED_ARGS
), init
...} {}
1158 arg_data(const arg_data
& other
) = delete;
1159 auto args() const -> const T
* { return args_
+ 1; }
1160 auto named_args() -> named_arg_info
<Char
>* { return named_args_
; }
1163 template <typename T
, typename Char
, size_t NUM_ARGS
>
1164 struct arg_data
<T
, Char
, NUM_ARGS
, 0> {
1165 // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
1166 T args_
[NUM_ARGS
!= 0 ? NUM_ARGS
: +1];
1168 template <typename
... U
>
1169 FMT_CONSTEXPR FMT_INLINE
arg_data(const U
&... init
) : args_
{init
...} {}
1170 FMT_CONSTEXPR FMT_INLINE
auto args() const -> const T
* { return args_
; }
1171 FMT_CONSTEXPR FMT_INLINE
auto named_args() -> std::nullptr_t
{
1176 template <typename Char
>
1177 inline void init_named_args(named_arg_info
<Char
>*, int, int) {}
1179 template <typename T
> struct is_named_arg
: std::false_type
{};
1180 template <typename T
> struct is_statically_named_arg
: std::false_type
{};
1182 template <typename T
, typename Char
>
1183 struct is_named_arg
<named_arg
<Char
, T
>> : std::true_type
{};
1185 template <typename Char
, typename T
, typename
... Tail
,
1186 FMT_ENABLE_IF(!is_named_arg
<T
>::value
)>
1187 void init_named_args(named_arg_info
<Char
>* named_args
, int arg_count
,
1188 int named_arg_count
, const T
&, const Tail
&... args
) {
1189 init_named_args(named_args
, arg_count
+ 1, named_arg_count
, args
...);
1192 template <typename Char
, typename T
, typename
... Tail
,
1193 FMT_ENABLE_IF(is_named_arg
<T
>::value
)>
1194 void init_named_args(named_arg_info
<Char
>* named_args
, int arg_count
,
1195 int named_arg_count
, const T
& arg
, const Tail
&... args
) {
1196 named_args
[named_arg_count
++] = {arg
.name
, arg_count
};
1197 init_named_args(named_args
, arg_count
+ 1, named_arg_count
, args
...);
1200 template <typename
... Args
>
1201 FMT_CONSTEXPR FMT_INLINE
void init_named_args(std::nullptr_t
, int, int,
1204 template <bool B
= false> constexpr auto count() -> size_t { return B
? 1 : 0; }
1205 template <bool B1
, bool B2
, bool... Tail
> constexpr auto count() -> size_t {
1206 return (B1
? 1 : 0) + count
<B2
, Tail
...>();
1209 template <typename
... Args
> constexpr auto count_named_args() -> size_t {
1210 return count
<is_named_arg
<Args
>::value
...>();
1213 template <typename
... Args
>
1214 constexpr auto count_statically_named_args() -> size_t {
1215 return count
<is_statically_named_arg
<Args
>::value
...>();
1218 struct unformattable
{};
1219 struct unformattable_char
: unformattable
{};
1220 struct unformattable_const
: unformattable
{};
1221 struct unformattable_pointer
: unformattable
{};
1223 template <typename Char
> struct string_value
{
1228 template <typename Char
> struct named_arg_value
{
1229 const named_arg_info
<Char
>* data
;
1233 template <typename Context
> struct custom_value
{
1234 using parse_context
= typename
Context::parse_context_type
;
1236 void (*format
)(void* arg
, parse_context
& parse_ctx
, Context
& ctx
);
1239 // A formatting argument value.
1240 template <typename Context
> class value
{
1242 using char_type
= typename
Context::char_type
;
1247 unsigned uint_value
;
1248 long long long_long_value
;
1249 unsigned long long ulong_long_value
;
1250 int128_opt int128_value
;
1251 uint128_opt uint128_value
;
1253 char_type char_value
;
1255 double double_value
;
1256 long double long_double_value
;
1257 const void* pointer
;
1258 string_value
<char_type
> string
;
1259 custom_value
<Context
> custom
;
1260 named_arg_value
<char_type
> named_args
;
1263 constexpr FMT_INLINE
value() : no_value() {}
1264 constexpr FMT_INLINE
value(int val
) : int_value(val
) {}
1265 constexpr FMT_INLINE
value(unsigned val
) : uint_value(val
) {}
1266 constexpr FMT_INLINE
value(long long val
) : long_long_value(val
) {}
1267 constexpr FMT_INLINE
value(unsigned long long val
) : ulong_long_value(val
) {}
1268 FMT_INLINE
value(int128_opt val
) : int128_value(val
) {}
1269 FMT_INLINE
value(uint128_opt val
) : uint128_value(val
) {}
1270 constexpr FMT_INLINE
value(float val
) : float_value(val
) {}
1271 constexpr FMT_INLINE
value(double val
) : double_value(val
) {}
1272 FMT_INLINE
value(long double val
) : long_double_value(val
) {}
1273 constexpr FMT_INLINE
value(bool val
) : bool_value(val
) {}
1274 constexpr FMT_INLINE
value(char_type val
) : char_value(val
) {}
1275 FMT_CONSTEXPR FMT_INLINE
value(const char_type
* val
) {
1277 if (is_constant_evaluated()) string
.size
= {};
1279 FMT_CONSTEXPR FMT_INLINE
value(basic_string_view
<char_type
> val
) {
1280 string
.data
= val
.data();
1281 string
.size
= val
.size();
1283 FMT_INLINE
value(const void* val
) : pointer(val
) {}
1284 FMT_INLINE
value(const named_arg_info
<char_type
>* args
, size_t size
)
1285 : named_args
{args
, size
} {}
1287 template <typename T
> FMT_CONSTEXPR FMT_INLINE
value(T
& val
) {
1288 using value_type
= remove_cvref_t
<T
>;
1289 custom
.value
= const_cast<value_type
*>(&val
);
1290 // Get the formatter type through the context to allow different contexts
1291 // have different extension points, e.g. `formatter<T>` for `format` and
1292 // `printf_formatter<T>` for `printf`.
1293 custom
.format
= format_custom_arg
<
1295 conditional_t
<has_formatter
<value_type
, Context
>::value
,
1296 typename
Context::template formatter_type
<value_type
>,
1297 fallback_formatter
<value_type
, char_type
>>>;
1299 value(unformattable
);
1300 value(unformattable_char
);
1301 value(unformattable_const
);
1302 value(unformattable_pointer
);
1305 // Formats an argument of a custom type, such as a user-defined class.
1306 template <typename T
, typename Formatter
>
1307 static void format_custom_arg(void* arg
,
1308 typename
Context::parse_context_type
& parse_ctx
,
1310 auto f
= Formatter();
1311 parse_ctx
.advance_to(f
.parse(parse_ctx
));
1312 using qualified_type
=
1313 conditional_t
<has_const_formatter
<T
, Context
>(), const T
, T
>;
1314 ctx
.advance_to(f
.format(*static_cast<qualified_type
*>(arg
), ctx
));
1318 template <typename Context
, typename T
>
1319 FMT_CONSTEXPR
auto make_arg(T
&& value
) -> basic_format_arg
<Context
>;
1321 // To minimize the number of types we need to deal with, long is translated
1322 // either to int or to long long depending on its size.
1323 enum { long_short
= sizeof(long) == sizeof(int) };
1324 using long_type
= conditional_t
<long_short
, int, long long>;
1325 using ulong_type
= conditional_t
<long_short
, unsigned, unsigned long long>;
1327 #ifdef __cpp_lib_byte
1328 inline auto format_as(std::byte b
) -> unsigned char {
1329 return static_cast<unsigned char>(b
);
1333 template <typename T
> struct has_format_as
{
1334 template <typename U
, typename V
= decltype(format_as(U())),
1335 FMT_ENABLE_IF(std::is_enum
<U
>::value
&& std::is_integral
<V
>::value
)>
1336 static auto check(U
*) -> std::true_type
;
1337 static auto check(...) -> std::false_type
;
1339 enum { value
= decltype(check(static_cast<T
*>(nullptr)))::value
};
1342 // Maps formatting arguments to core types.
1343 // arg_mapper reports errors by returning unformattable instead of using
1344 // static_assert because it's used in the is_formattable trait.
1345 template <typename Context
> struct arg_mapper
{
1346 using char_type
= typename
Context::char_type
;
1348 FMT_CONSTEXPR FMT_INLINE
auto map(signed char val
) -> int { return val
; }
1349 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned char val
) -> unsigned {
1352 FMT_CONSTEXPR FMT_INLINE
auto map(short val
) -> int { return val
; }
1353 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned short val
) -> unsigned {
1356 FMT_CONSTEXPR FMT_INLINE
auto map(int val
) -> int { return val
; }
1357 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned val
) -> unsigned { return val
; }
1358 FMT_CONSTEXPR FMT_INLINE
auto map(long val
) -> long_type
{ return val
; }
1359 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned long val
) -> ulong_type
{
1362 FMT_CONSTEXPR FMT_INLINE
auto map(long long val
) -> long long { return val
; }
1363 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned long long val
)
1364 -> unsigned long long {
1367 FMT_CONSTEXPR FMT_INLINE
auto map(int128_opt val
) -> int128_opt
{
1370 FMT_CONSTEXPR FMT_INLINE
auto map(uint128_opt val
) -> uint128_opt
{
1373 FMT_CONSTEXPR FMT_INLINE
auto map(bool val
) -> bool { return val
; }
1375 template <typename T
, FMT_ENABLE_IF(std::is_same
<T
, char>::value
||
1376 std::is_same
<T
, char_type
>::value
)>
1377 FMT_CONSTEXPR FMT_INLINE
auto map(T val
) -> char_type
{
1380 template <typename T
, enable_if_t
<(std::is_same
<T
, wchar_t>::value
||
1381 #ifdef __cpp_char8_t
1382 std::is_same
<T
, char8_t
>::value
||
1384 std::is_same
<T
, char16_t
>::value
||
1385 std::is_same
<T
, char32_t
>::value
) &&
1386 !std::is_same
<T
, char_type
>::value
,
1388 FMT_CONSTEXPR FMT_INLINE
auto map(T
) -> unformattable_char
{
1392 FMT_CONSTEXPR FMT_INLINE
auto map(float val
) -> float { return val
; }
1393 FMT_CONSTEXPR FMT_INLINE
auto map(double val
) -> double { return val
; }
1394 FMT_CONSTEXPR FMT_INLINE
auto map(long double val
) -> long double {
1398 FMT_CONSTEXPR FMT_INLINE
auto map(char_type
* val
) -> const char_type
* {
1401 FMT_CONSTEXPR FMT_INLINE
auto map(const char_type
* val
) -> const char_type
* {
1404 template <typename T
,
1405 FMT_ENABLE_IF(is_string
<T
>::value
&& !std::is_pointer
<T
>::value
&&
1406 std::is_same
<char_type
, char_t
<T
>>::value
)>
1407 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& val
)
1408 -> basic_string_view
<char_type
> {
1409 return to_string_view(val
);
1411 template <typename T
,
1412 FMT_ENABLE_IF(is_string
<T
>::value
&& !std::is_pointer
<T
>::value
&&
1413 !std::is_same
<char_type
, char_t
<T
>>::value
)>
1414 FMT_CONSTEXPR FMT_INLINE
auto map(const T
&) -> unformattable_char
{
1417 template <typename T
,
1419 std::is_convertible
<T
, basic_string_view
<char_type
>>::value
&&
1420 !is_string
<T
>::value
&& !has_formatter
<T
, Context
>::value
&&
1421 !has_fallback_formatter
<T
, char_type
>::value
)>
1422 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& val
)
1423 -> basic_string_view
<char_type
> {
1424 return basic_string_view
<char_type
>(val
);
1426 template <typename T
,
1428 std::is_convertible
<T
, std_string_view
<char_type
>>::value
&&
1429 !std::is_convertible
<T
, basic_string_view
<char_type
>>::value
&&
1430 !is_string
<T
>::value
&& !has_formatter
<T
, Context
>::value
&&
1431 !has_fallback_formatter
<T
, char_type
>::value
)>
1432 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& val
)
1433 -> basic_string_view
<char_type
> {
1434 return std_string_view
<char_type
>(val
);
1437 FMT_CONSTEXPR FMT_INLINE
auto map(void* val
) -> const void* { return val
; }
1438 FMT_CONSTEXPR FMT_INLINE
auto map(const void* val
) -> const void* {
1441 FMT_CONSTEXPR FMT_INLINE
auto map(std::nullptr_t val
) -> const void* {
1445 // We use SFINAE instead of a const T* parameter to avoid conflicting with
1446 // the C array overload.
1450 std::is_pointer
<T
>::value
|| std::is_member_pointer
<T
>::value
||
1451 std::is_function
<typename
std::remove_pointer
<T
>::type
>::value
||
1452 (std::is_convertible
<const T
&, const void*>::value
&&
1453 !std::is_convertible
<const T
&, const char_type
*>::value
&&
1454 !has_formatter
<T
, Context
>::value
))>
1455 FMT_CONSTEXPR
auto map(const T
&) -> unformattable_pointer
{
1459 template <typename T
, std::size_t N
,
1460 FMT_ENABLE_IF(!std::is_same
<T
, wchar_t>::value
)>
1461 FMT_CONSTEXPR FMT_INLINE
auto map(const T (&values
)[N
]) -> const T (&)[N
] {
1465 template <typename T
,
1467 std::is_enum
<T
>::value
&& std::is_convertible
<T
, int>::value
&&
1468 !has_format_as
<T
>::value
&& !has_formatter
<T
, Context
>::value
&&
1469 !has_fallback_formatter
<T
, char_type
>::value
)>
1470 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE
auto map(const T
& val
)
1471 -> decltype(std::declval
<arg_mapper
>().map(
1472 static_cast<underlying_t
<T
>>(val
))) {
1473 return map(static_cast<underlying_t
<T
>>(val
));
1476 template <typename T
, FMT_ENABLE_IF(has_format_as
<T
>::value
&&
1477 !has_formatter
<T
, Context
>::value
)>
1478 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& val
)
1479 -> decltype(std::declval
<arg_mapper
>().map(format_as(T()))) {
1480 return map(format_as(val
));
1483 template <typename T
, typename U
= remove_cvref_t
<T
>>
1485 : bool_constant
<has_const_formatter
<U
, Context
>() ||
1486 !std::is_const
<remove_reference_t
<T
>>::value
||
1487 has_fallback_formatter
<U
, char_type
>::value
> {};
1489 #if (FMT_MSC_VERSION != 0 && FMT_MSC_VERSION < 1910) || \
1490 FMT_ICC_VERSION != 0 || defined(__NVCC__)
1491 // Workaround a bug in MSVC and Intel (Issue 2746).
1492 template <typename T
> FMT_CONSTEXPR FMT_INLINE
auto do_map(T
&& val
) -> T
& {
1496 template <typename T
, FMT_ENABLE_IF(formattable
<T
>::value
)>
1497 FMT_CONSTEXPR FMT_INLINE
auto do_map(T
&& val
) -> T
& {
1500 template <typename T
, FMT_ENABLE_IF(!formattable
<T
>::value
)>
1501 FMT_CONSTEXPR FMT_INLINE
auto do_map(T
&&) -> unformattable_const
{
1506 template <typename T
, typename U
= remove_cvref_t
<T
>,
1507 FMT_ENABLE_IF(!is_string
<U
>::value
&& !is_char
<U
>::value
&&
1508 !std::is_array
<U
>::value
&&
1509 !std::is_pointer
<U
>::value
&&
1510 !has_format_as
<U
>::value
&&
1511 (has_formatter
<U
, Context
>::value
||
1512 has_fallback_formatter
<U
, char_type
>::value
))>
1513 FMT_CONSTEXPR FMT_INLINE
auto map(T
&& val
)
1514 -> decltype(this->do_map(std::forward
<T
>(val
))) {
1515 return do_map(std::forward
<T
>(val
));
1518 template <typename T
, FMT_ENABLE_IF(is_named_arg
<T
>::value
)>
1519 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& named_arg
)
1520 -> decltype(std::declval
<arg_mapper
>().map(named_arg
.value
)) {
1521 return map(named_arg
.value
);
1524 auto map(...) -> unformattable
{ return {}; }
1527 // A type constant after applying arg_mapper<Context>.
1528 template <typename T
, typename Context
>
1529 using mapped_type_constant
=
1530 type_constant
<decltype(arg_mapper
<Context
>().map(std::declval
<const T
&>())),
1531 typename
Context::char_type
>;
1533 enum { packed_arg_bits
= 4 };
1534 // Maximum number of arguments with packed types.
1535 enum { max_packed_args
= 62 / packed_arg_bits
};
1536 enum : unsigned long long { is_unpacked_bit
= 1ULL << 63 };
1537 enum : unsigned long long { has_named_args_bit
= 1ULL << 62 };
1539 FMT_END_DETAIL_NAMESPACE
1541 // An output iterator that appends to a buffer.
1542 // It is used to reduce symbol sizes for the common case.
1543 class appender
: public std::back_insert_iterator
<detail::buffer
<char>> {
1544 using base
= std::back_insert_iterator
<detail::buffer
<char>>;
1546 template <typename T
>
1547 friend auto get_buffer(appender out
) -> detail::buffer
<char>& {
1548 return detail::get_container(out
);
1552 using std::back_insert_iterator
<detail::buffer
<char>>::back_insert_iterator
;
1553 appender(base it
) noexcept
: base(it
) {}
1554 FMT_UNCHECKED_ITERATOR(appender
);
1556 auto operator++() noexcept
-> appender
& { return *this; }
1557 auto operator++(int) noexcept
-> appender
{ return *this; }
1560 // A formatting argument. It is a trivially copyable/constructible type to
1561 // allow storage in basic_memory_buffer.
1562 template <typename Context
> class basic_format_arg
{
1564 detail::value
<Context
> value_
;
1567 template <typename ContextType
, typename T
>
1568 friend FMT_CONSTEXPR
auto detail::make_arg(T
&& value
)
1569 -> basic_format_arg
<ContextType
>;
1571 template <typename Visitor
, typename Ctx
>
1572 friend FMT_CONSTEXPR
auto visit_format_arg(Visitor
&& vis
,
1573 const basic_format_arg
<Ctx
>& arg
)
1574 -> decltype(vis(0));
1576 friend class basic_format_args
<Context
>;
1577 friend class dynamic_format_arg_store
<Context
>;
1579 using char_type
= typename
Context::char_type
;
1581 template <typename T
, typename Char
, size_t NUM_ARGS
, size_t NUM_NAMED_ARGS
>
1582 friend struct detail::arg_data
;
1584 basic_format_arg(const detail::named_arg_info
<char_type
>* args
, size_t size
)
1585 : value_(args
, size
) {}
1590 explicit handle(detail::custom_value
<Context
> custom
) : custom_(custom
) {}
1592 void format(typename
Context::parse_context_type
& parse_ctx
,
1593 Context
& ctx
) const {
1594 custom_
.format(custom_
.value
, parse_ctx
, ctx
);
1598 detail::custom_value
<Context
> custom_
;
1601 constexpr basic_format_arg() : type_(detail::type::none_type
) {}
1603 constexpr explicit operator bool() const noexcept
{
1604 return type_
!= detail::type::none_type
;
1607 auto type() const -> detail::type
{ return type_
; }
1609 auto is_integral() const -> bool { return detail::is_integral_type(type_
); }
1610 auto is_arithmetic() const -> bool {
1611 return detail::is_arithmetic_type(type_
);
1617 Visits an argument dispatching to the appropriate visit method based on
1618 the argument type. For example, if the argument type is ``double`` then
1619 ``vis(value)`` will be called with the value of type ``double``.
1622 template <typename Visitor
, typename Context
>
1623 FMT_CONSTEXPR FMT_INLINE
auto visit_format_arg(
1624 Visitor
&& vis
, const basic_format_arg
<Context
>& arg
) -> decltype(vis(0)) {
1625 switch (arg
.type_
) {
1626 case detail::type::none_type
:
1628 case detail::type::int_type
:
1629 return vis(arg
.value_
.int_value
);
1630 case detail::type::uint_type
:
1631 return vis(arg
.value_
.uint_value
);
1632 case detail::type::long_long_type
:
1633 return vis(arg
.value_
.long_long_value
);
1634 case detail::type::ulong_long_type
:
1635 return vis(arg
.value_
.ulong_long_value
);
1636 case detail::type::int128_type
:
1637 return vis(detail::convert_for_visit(arg
.value_
.int128_value
));
1638 case detail::type::uint128_type
:
1639 return vis(detail::convert_for_visit(arg
.value_
.uint128_value
));
1640 case detail::type::bool_type
:
1641 return vis(arg
.value_
.bool_value
);
1642 case detail::type::char_type
:
1643 return vis(arg
.value_
.char_value
);
1644 case detail::type::float_type
:
1645 return vis(arg
.value_
.float_value
);
1646 case detail::type::double_type
:
1647 return vis(arg
.value_
.double_value
);
1648 case detail::type::long_double_type
:
1649 return vis(arg
.value_
.long_double_value
);
1650 case detail::type::cstring_type
:
1651 return vis(arg
.value_
.string
.data
);
1652 case detail::type::string_type
:
1653 using sv
= basic_string_view
<typename
Context::char_type
>;
1654 return vis(sv(arg
.value_
.string
.data
, arg
.value_
.string
.size
));
1655 case detail::type::pointer_type
:
1656 return vis(arg
.value_
.pointer
);
1657 case detail::type::custom_type
:
1658 return vis(typename basic_format_arg
<Context
>::handle(arg
.value_
.custom
));
1660 return vis(monostate());
1663 FMT_BEGIN_DETAIL_NAMESPACE
1665 template <typename Char
, typename InputIt
>
1666 auto copy_str(InputIt begin
, InputIt end
, appender out
) -> appender
{
1667 get_container(out
).append(begin
, end
);
1671 template <typename Char
, typename R
, typename OutputIt
>
1672 FMT_CONSTEXPR
auto copy_str(R
&& rng
, OutputIt out
) -> OutputIt
{
1673 return detail::copy_str
<Char
>(rng
.begin(), rng
.end(), out
);
1676 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
1677 // A workaround for gcc 4.8 to make void_t work in a SFINAE context.
1678 template <typename
... Ts
> struct void_t_impl
{ using type
= void; };
1679 template <typename
... Ts
>
1680 using void_t
= typename
detail::void_t_impl
<Ts
...>::type
;
1682 template <typename
...> using void_t
= void;
1685 template <typename It
, typename T
, typename Enable
= void>
1686 struct is_output_iterator
: std::false_type
{};
1688 template <typename It
, typename T
>
1689 struct is_output_iterator
<
1691 void_t
<typename
std::iterator_traits
<It
>::iterator_category
,
1692 decltype(*std::declval
<It
>() = std::declval
<T
>())>>
1693 : std::true_type
{};
1695 template <typename OutputIt
>
1696 struct is_back_insert_iterator
: std::false_type
{};
1697 template <typename Container
>
1698 struct is_back_insert_iterator
<std::back_insert_iterator
<Container
>>
1699 : std::true_type
{};
1701 template <typename OutputIt
>
1702 struct is_contiguous_back_insert_iterator
: std::false_type
{};
1703 template <typename Container
>
1704 struct is_contiguous_back_insert_iterator
<std::back_insert_iterator
<Container
>>
1705 : is_contiguous
<Container
> {};
1707 struct is_contiguous_back_insert_iterator
<appender
> : std::true_type
{};
1709 // A type-erased reference to an std::locale to avoid a heavy <locale> include.
1712 const void* locale_
; // A type-erased pointer to std::locale.
1715 constexpr locale_ref() : locale_(nullptr) {}
1716 template <typename Locale
> explicit locale_ref(const Locale
& loc
);
1718 explicit operator bool() const noexcept
{ return locale_
!= nullptr; }
1720 template <typename Locale
> auto get() const -> Locale
;
1723 template <typename
> constexpr auto encode_types() -> unsigned long long {
1727 template <typename Context
, typename Arg
, typename
... Args
>
1728 constexpr auto encode_types() -> unsigned long long {
1729 return static_cast<unsigned>(mapped_type_constant
<Arg
, Context
>::value
) |
1730 (encode_types
<Context
, Args
...>() << packed_arg_bits
);
1733 template <typename Context
, typename T
>
1734 FMT_CONSTEXPR FMT_INLINE
auto make_value(T
&& val
) -> value
<Context
> {
1735 const auto& arg
= arg_mapper
<Context
>().map(FMT_FORWARD(val
));
1737 constexpr bool formattable_char
=
1738 !std::is_same
<decltype(arg
), const unformattable_char
&>::value
;
1739 static_assert(formattable_char
, "Mixing character types is disallowed.");
1741 constexpr bool formattable_const
=
1742 !std::is_same
<decltype(arg
), const unformattable_const
&>::value
;
1743 static_assert(formattable_const
, "Cannot format a const argument.");
1745 // Formatting of arbitrary pointers is disallowed. If you want to output
1746 // a pointer cast it to "void *" or "const void *". In particular, this
1747 // forbids formatting of "[const] volatile char *" which is printed as bool
1749 constexpr bool formattable_pointer
=
1750 !std::is_same
<decltype(arg
), const unformattable_pointer
&>::value
;
1751 static_assert(formattable_pointer
,
1752 "Formatting of non-void pointers is disallowed.");
1754 constexpr bool formattable
=
1755 !std::is_same
<decltype(arg
), const unformattable
&>::value
;
1758 "Cannot format an argument. To make type T formattable provide a "
1759 "formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
1763 template <typename Context
, typename T
>
1764 FMT_CONSTEXPR
auto make_arg(T
&& value
) -> basic_format_arg
<Context
> {
1765 basic_format_arg
<Context
> arg
;
1766 arg
.type_
= mapped_type_constant
<T
, Context
>::value
;
1767 arg
.value_
= make_value
<Context
>(value
);
1771 // The type template parameter is there to avoid an ODR violation when using
1772 // a fallback formatter in one translation unit and an implicit conversion in
1773 // another (not recommended).
1774 template <bool IS_PACKED
, typename Context
, type
, typename T
,
1775 FMT_ENABLE_IF(IS_PACKED
)>
1776 FMT_CONSTEXPR FMT_INLINE
auto make_arg(T
&& val
) -> value
<Context
> {
1777 return make_value
<Context
>(val
);
1780 template <bool IS_PACKED
, typename Context
, type
, typename T
,
1781 FMT_ENABLE_IF(!IS_PACKED
)>
1782 FMT_CONSTEXPR
inline auto make_arg(T
&& value
) -> basic_format_arg
<Context
> {
1783 return make_arg
<Context
>(value
);
1785 FMT_END_DETAIL_NAMESPACE
1787 // Formatting context.
1788 template <typename OutputIt
, typename Char
> class basic_format_context
{
1790 /** The character type for the output. */
1791 using char_type
= Char
;
1795 basic_format_args
<basic_format_context
> args_
;
1796 detail::locale_ref loc_
;
1799 using iterator
= OutputIt
;
1800 using format_arg
= basic_format_arg
<basic_format_context
>;
1801 using parse_context_type
= basic_format_parse_context
<Char
>;
1802 template <typename T
> using formatter_type
= formatter
<T
, char_type
>;
1804 basic_format_context(basic_format_context
&&) = default;
1805 basic_format_context(const basic_format_context
&) = delete;
1806 void operator=(const basic_format_context
&) = delete;
1808 Constructs a ``basic_format_context`` object. References to the arguments are
1809 stored in the object so make sure they have appropriate lifetimes.
1811 constexpr basic_format_context(
1812 OutputIt out
, basic_format_args
<basic_format_context
> ctx_args
,
1813 detail::locale_ref loc
= detail::locale_ref())
1814 : out_(out
), args_(ctx_args
), loc_(loc
) {}
1816 constexpr auto arg(int id
) const -> format_arg
{ return args_
.get(id
); }
1817 FMT_CONSTEXPR
auto arg(basic_string_view
<char_type
> name
) -> format_arg
{
1818 return args_
.get(name
);
1820 FMT_CONSTEXPR
auto arg_id(basic_string_view
<char_type
> name
) -> int {
1821 return args_
.get_id(name
);
1823 auto args() const -> const basic_format_args
<basic_format_context
>& {
1827 FMT_CONSTEXPR
auto error_handler() -> detail::error_handler
{ return {}; }
1828 void on_error(const char* message
) { error_handler().on_error(message
); }
1830 // Returns an iterator to the beginning of the output range.
1831 FMT_CONSTEXPR
auto out() -> iterator
{ return out_
; }
1833 // Advances the begin iterator to ``it``.
1834 void advance_to(iterator it
) {
1835 if (!detail::is_back_insert_iterator
<iterator
>()) out_
= it
;
1838 FMT_CONSTEXPR
auto locale() -> detail::locale_ref
{ return loc_
; }
1841 template <typename Char
>
1842 using buffer_context
=
1843 basic_format_context
<detail::buffer_appender
<Char
>, Char
>;
1844 using format_context
= buffer_context
<char>;
1846 // Workaround an alias issue: https://stackoverflow.com/q/62767544/471164.
1847 #define FMT_BUFFER_CONTEXT(Char) \
1848 basic_format_context<detail::buffer_appender<Char>, Char>
1850 template <typename T
, typename Char
= char>
1851 using is_formattable
= bool_constant
<
1852 !std::is_base_of
<detail::unformattable
,
1853 decltype(detail::arg_mapper
<buffer_context
<Char
>>().map(
1854 std::declval
<T
>()))>::value
&&
1855 !detail::has_fallback_formatter
<T
, Char
>::value
>;
1859 An array of references to arguments. It can be implicitly converted into
1860 `~fmt::basic_format_args` for passing into type-erased formatting functions
1861 such as `~fmt::vformat`.
1864 template <typename Context
, typename
... Args
>
1865 class format_arg_store
1866 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1867 // Workaround a GCC template argument substitution bug.
1868 : public basic_format_args
<Context
>
1872 static const size_t num_args
= sizeof...(Args
);
1873 static const size_t num_named_args
= detail::count_named_args
<Args
...>();
1874 static const bool is_packed
= num_args
<= detail::max_packed_args
;
1876 using value_type
= conditional_t
<is_packed
, detail::value
<Context
>,
1877 basic_format_arg
<Context
>>;
1879 detail::arg_data
<value_type
, typename
Context::char_type
, num_args
,
1883 friend class basic_format_args
<Context
>;
1885 static constexpr unsigned long long desc
=
1886 (is_packed
? detail::encode_types
<Context
, Args
...>()
1887 : detail::is_unpacked_bit
| num_args
) |
1888 (num_named_args
!= 0
1889 ? static_cast<unsigned long long>(detail::has_named_args_bit
)
1893 template <typename
... T
>
1894 FMT_CONSTEXPR FMT_INLINE
format_arg_store(T
&&... args
)
1896 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1897 basic_format_args
<Context
>(*this),
1899 data_
{detail::make_arg
<
1901 detail::mapped_type_constant
<remove_cvref_t
<T
>, Context
>::value
>(
1902 FMT_FORWARD(args
))...} {
1903 detail::init_named_args(data_
.named_args(), 0, 0, args
...);
1909 Constructs a `~fmt::format_arg_store` object that contains references to
1910 arguments and can be implicitly converted to `~fmt::format_args`. `Context`
1911 can be omitted in which case it defaults to `~fmt::context`.
1912 See `~fmt::arg` for lifetime considerations.
1915 template <typename Context
= format_context
, typename
... Args
>
1916 constexpr auto make_format_args(Args
&&... args
)
1917 -> format_arg_store
<Context
, remove_cvref_t
<Args
>...> {
1918 return {FMT_FORWARD(args
)...};
1923 Returns a named argument to be used in a formatting function.
1924 It should only be used in a call to a formatting function or
1925 `dynamic_format_arg_store::push_back`.
1929 fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
1932 template <typename Char
, typename T
>
1933 inline auto arg(const Char
* name
, const T
& arg
) -> detail::named_arg
<Char
, T
> {
1934 static_assert(!detail::is_named_arg
<T
>(), "nested named arguments");
1940 A view of a collection of formatting arguments. To avoid lifetime issues it
1941 should only be used as a parameter type in type-erased functions such as
1944 void vlog(string_view format_str, format_args args); // OK
1945 format_args args = make_format_args(42); // Error: dangling reference
1948 template <typename Context
> class basic_format_args
{
1950 using size_type
= int;
1951 using format_arg
= basic_format_arg
<Context
>;
1954 // A descriptor that contains information about formatting arguments.
1955 // If the number of arguments is less or equal to max_packed_args then
1956 // argument types are passed in the descriptor. This reduces binary code size
1957 // per formatting function call.
1958 unsigned long long desc_
;
1960 // If is_packed() returns true then argument values are stored in values_;
1961 // otherwise they are stored in args_. This is done to improve cache
1962 // locality and reduce compiled code size since storing larger objects
1963 // may require more code (at least on x86-64) even if the same amount of
1964 // data is actually copied to stack. It saves ~10% on the bloat test.
1965 const detail::value
<Context
>* values_
;
1966 const format_arg
* args_
;
1969 constexpr auto is_packed() const -> bool {
1970 return (desc_
& detail::is_unpacked_bit
) == 0;
1972 auto has_named_args() const -> bool {
1973 return (desc_
& detail::has_named_args_bit
) != 0;
1976 FMT_CONSTEXPR
auto type(int index
) const -> detail::type
{
1977 int shift
= index
* detail::packed_arg_bits
;
1978 unsigned int mask
= (1 << detail::packed_arg_bits
) - 1;
1979 return static_cast<detail::type
>((desc_
>> shift
) & mask
);
1982 constexpr FMT_INLINE
basic_format_args(unsigned long long desc
,
1983 const detail::value
<Context
>* values
)
1984 : desc_(desc
), values_(values
) {}
1985 constexpr basic_format_args(unsigned long long desc
, const format_arg
* args
)
1986 : desc_(desc
), args_(args
) {}
1989 constexpr basic_format_args() : desc_(0), args_(nullptr) {}
1993 Constructs a `basic_format_args` object from `~fmt::format_arg_store`.
1996 template <typename
... Args
>
1997 constexpr FMT_INLINE
basic_format_args(
1998 const format_arg_store
<Context
, Args
...>& store
)
1999 : basic_format_args(format_arg_store
<Context
, Args
...>::desc
,
2000 store
.data_
.args()) {}
2004 Constructs a `basic_format_args` object from
2005 `~fmt::dynamic_format_arg_store`.
2008 constexpr FMT_INLINE
basic_format_args(
2009 const dynamic_format_arg_store
<Context
>& store
)
2010 : basic_format_args(store
.get_types(), store
.data()) {}
2014 Constructs a `basic_format_args` object from a dynamic set of arguments.
2017 constexpr basic_format_args(const format_arg
* args
, int count
)
2018 : basic_format_args(detail::is_unpacked_bit
| detail::to_unsigned(count
),
2021 /** Returns the argument with the specified id. */
2022 FMT_CONSTEXPR
auto get(int id
) const -> format_arg
{
2025 if (id
< max_size()) arg
= args_
[id
];
2028 if (id
>= detail::max_packed_args
) return arg
;
2029 arg
.type_
= type(id
);
2030 if (arg
.type_
== detail::type::none_type
) return arg
;
2031 arg
.value_
= values_
[id
];
2035 template <typename Char
>
2036 auto get(basic_string_view
<Char
> name
) const -> format_arg
{
2037 int id
= get_id(name
);
2038 return id
>= 0 ? get(id
) : format_arg();
2041 template <typename Char
>
2042 auto get_id(basic_string_view
<Char
> name
) const -> int {
2043 if (!has_named_args()) return -1;
2044 const auto& named_args
=
2045 (is_packed() ? values_
[-1] : args_
[-1].value_
).named_args
;
2046 for (size_t i
= 0; i
< named_args
.size
; ++i
) {
2047 if (named_args
.data
[i
].name
== name
) return named_args
.data
[i
].id
;
2052 auto max_size() const -> int {
2053 unsigned long long max_packed
= detail::max_packed_args
;
2054 return static_cast<int>(is_packed() ? max_packed
2055 : desc_
& ~detail::is_unpacked_bit
);
2059 /** An alias to ``basic_format_args<format_context>``. */
2060 // A separate type would result in shorter symbols but break ABI compatibility
2061 // between clang and gcc on ARM (#1919).
2062 using format_args
= basic_format_args
<format_context
>;
2064 // We cannot use enum classes as bit fields because of a gcc bug, so we put them
2065 // in namespaces instead (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414).
2066 // Additionally, if an underlying type is specified, older gcc incorrectly warns
2067 // that the type is too small. Both bugs are fixed in gcc 9.3.
2068 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 903
2069 # define FMT_ENUM_UNDERLYING_TYPE(type)
2071 # define FMT_ENUM_UNDERLYING_TYPE(type) : type
2074 enum type
FMT_ENUM_UNDERLYING_TYPE(unsigned char){none
, left
, right
, center
,
2077 using align_t
= align::type
;
2079 enum type
FMT_ENUM_UNDERLYING_TYPE(unsigned char){none
, minus
, plus
, space
};
2081 using sign_t
= sign::type
;
2083 FMT_BEGIN_DETAIL_NAMESPACE
2085 // Workaround an array initialization issue in gcc 4.8.
2086 template <typename Char
> struct fill_t
{
2088 enum { max_size
= 4 };
2089 Char data_
[max_size
] = {Char(' '), Char(0), Char(0), Char(0)};
2090 unsigned char size_
= 1;
2093 FMT_CONSTEXPR
void operator=(basic_string_view
<Char
> s
) {
2094 auto size
= s
.size();
2095 if (size
> max_size
) return throw_format_error("invalid fill");
2096 for (size_t i
= 0; i
< size
; ++i
) data_
[i
] = s
[i
];
2097 size_
= static_cast<unsigned char>(size
);
2100 constexpr auto size() const -> size_t { return size_
; }
2101 constexpr auto data() const -> const Char
* { return data_
; }
2103 FMT_CONSTEXPR
auto operator[](size_t index
) -> Char
& { return data_
[index
]; }
2104 FMT_CONSTEXPR
auto operator[](size_t index
) const -> const Char
& {
2105 return data_
[index
];
2108 FMT_END_DETAIL_NAMESPACE
2110 enum class presentation_type
: unsigned char {
2112 // Integer types should go first,
2119 hexfloat_lower
, // 'a'
2120 hexfloat_upper
, // 'A'
2125 general_lower
, // 'g'
2126 general_upper
, // 'G'
2133 // Format specifiers for built-in and string types.
2134 template <typename Char
> struct basic_format_specs
{
2137 presentation_type type
;
2140 bool alt
: 1; // Alternate form ('#').
2142 detail::fill_t
<Char
> fill
;
2144 constexpr basic_format_specs()
2147 type(presentation_type::none
),
2154 using format_specs
= basic_format_specs
<char>;
2156 FMT_BEGIN_DETAIL_NAMESPACE
2158 enum class arg_id_kind
{ none
, index
, name
};
2160 // An argument reference.
2161 template <typename Char
> struct arg_ref
{
2162 FMT_CONSTEXPR
arg_ref() : kind(arg_id_kind::none
), val() {}
2164 FMT_CONSTEXPR
explicit arg_ref(int index
)
2165 : kind(arg_id_kind::index
), val(index
) {}
2166 FMT_CONSTEXPR
explicit arg_ref(basic_string_view
<Char
> name
)
2167 : kind(arg_id_kind::name
), val(name
) {}
2169 FMT_CONSTEXPR
auto operator=(int idx
) -> arg_ref
& {
2170 kind
= arg_id_kind::index
;
2177 FMT_CONSTEXPR
value(int id
= 0) : index
{id
} {}
2178 FMT_CONSTEXPR
value(basic_string_view
<Char
> n
) : name(n
) {}
2181 basic_string_view
<Char
> name
;
2185 // Format specifiers with width and precision resolved at formatting rather
2186 // than parsing time to allow re-using the same parsed specifiers with
2187 // different sets of arguments (precompilation of format strings).
2188 template <typename Char
>
2189 struct dynamic_format_specs
: basic_format_specs
<Char
> {
2190 arg_ref
<Char
> width_ref
;
2191 arg_ref
<Char
> precision_ref
;
2196 // A format specifier handler that sets fields in basic_format_specs.
2197 template <typename Char
> class specs_setter
{
2199 basic_format_specs
<Char
>& specs_
;
2202 explicit FMT_CONSTEXPR
specs_setter(basic_format_specs
<Char
>& specs
)
2205 FMT_CONSTEXPR
specs_setter(const specs_setter
& other
)
2206 : specs_(other
.specs_
) {}
2208 FMT_CONSTEXPR
void on_align(align_t align
) { specs_
.align
= align
; }
2209 FMT_CONSTEXPR
void on_fill(basic_string_view
<Char
> fill
) {
2212 FMT_CONSTEXPR
void on_sign(sign_t s
) { specs_
.sign
= s
; }
2213 FMT_CONSTEXPR
void on_hash() { specs_
.alt
= true; }
2214 FMT_CONSTEXPR
void on_localized() { specs_
.localized
= true; }
2216 FMT_CONSTEXPR
void on_zero() {
2217 if (specs_
.align
== align::none
) specs_
.align
= align::numeric
;
2218 specs_
.fill
[0] = Char('0');
2221 FMT_CONSTEXPR
void on_width(int width
) { specs_
.width
= width
; }
2222 FMT_CONSTEXPR
void on_precision(int precision
) {
2223 specs_
.precision
= precision
;
2225 FMT_CONSTEXPR
void end_precision() {}
2227 FMT_CONSTEXPR
void on_type(presentation_type type
) { specs_
.type
= type
; }
2230 // Format spec handler that saves references to arguments representing dynamic
2231 // width and precision to be resolved at formatting time.
2232 template <typename ParseContext
>
2233 class dynamic_specs_handler
2234 : public specs_setter
<typename
ParseContext::char_type
> {
2236 using char_type
= typename
ParseContext::char_type
;
2238 FMT_CONSTEXPR
dynamic_specs_handler(dynamic_format_specs
<char_type
>& specs
,
2240 : specs_setter
<char_type
>(specs
), specs_(specs
), context_(ctx
) {}
2242 FMT_CONSTEXPR
dynamic_specs_handler(const dynamic_specs_handler
& other
)
2243 : specs_setter
<char_type
>(other
),
2244 specs_(other
.specs_
),
2245 context_(other
.context_
) {}
2247 template <typename Id
> FMT_CONSTEXPR
void on_dynamic_width(Id arg_id
) {
2248 specs_
.width_ref
= make_arg_ref(arg_id
);
2251 template <typename Id
> FMT_CONSTEXPR
void on_dynamic_precision(Id arg_id
) {
2252 specs_
.precision_ref
= make_arg_ref(arg_id
);
2255 FMT_CONSTEXPR
void on_error(const char* message
) {
2256 context_
.on_error(message
);
2260 dynamic_format_specs
<char_type
>& specs_
;
2261 ParseContext
& context_
;
2263 using arg_ref_type
= arg_ref
<char_type
>;
2265 FMT_CONSTEXPR
auto make_arg_ref(int arg_id
) -> arg_ref_type
{
2266 context_
.check_arg_id(arg_id
);
2267 context_
.check_dynamic_spec(arg_id
);
2268 return arg_ref_type(arg_id
);
2271 FMT_CONSTEXPR
auto make_arg_ref(auto_id
) -> arg_ref_type
{
2272 int arg_id
= context_
.next_arg_id();
2273 context_
.check_dynamic_spec(arg_id
);
2274 return arg_ref_type(arg_id
);
2277 FMT_CONSTEXPR
auto make_arg_ref(basic_string_view
<char_type
> arg_id
)
2279 context_
.check_arg_id(arg_id
);
2280 basic_string_view
<char_type
> format_str(
2281 context_
.begin(), to_unsigned(context_
.end() - context_
.begin()));
2282 return arg_ref_type(arg_id
);
2286 template <typename Char
> constexpr bool is_ascii_letter(Char c
) {
2287 return (c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z');
2290 // Converts a character to ASCII. Returns a number > 127 on conversion failure.
2291 template <typename Char
, FMT_ENABLE_IF(std::is_integral
<Char
>::value
)>
2292 constexpr auto to_ascii(Char c
) -> Char
{
2295 template <typename Char
, FMT_ENABLE_IF(std::is_enum
<Char
>::value
)>
2296 constexpr auto to_ascii(Char c
) -> underlying_t
<Char
> {
2300 FMT_CONSTEXPR
inline auto code_point_length_impl(char c
) -> int {
2301 return "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4"
2302 [static_cast<unsigned char>(c
) >> 3];
2305 template <typename Char
>
2306 FMT_CONSTEXPR
auto code_point_length(const Char
* begin
) -> int {
2307 if (const_check(sizeof(Char
) != 1)) return 1;
2308 int len
= code_point_length_impl(static_cast<char>(*begin
));
2310 // Compute the pointer to the next character early so that the next
2311 // iteration can start working on the next character. Neither Clang
2312 // nor GCC figure out this reordering on their own.
2316 // Return the result via the out param to workaround gcc bug 77539.
2317 template <bool IS_CONSTEXPR
, typename T
, typename Ptr
= const T
*>
2318 FMT_CONSTEXPR
auto find(Ptr first
, Ptr last
, T value
, Ptr
& out
) -> bool {
2319 for (out
= first
; out
!= last
; ++out
) {
2320 if (*out
== value
) return true;
2326 inline auto find
<false, char>(const char* first
, const char* last
, char value
,
2327 const char*& out
) -> bool {
2328 out
= static_cast<const char*>(
2329 std::memchr(first
, value
, to_unsigned(last
- first
)));
2330 return out
!= nullptr;
2333 // Parses the range [begin, end) as an unsigned integer. This function assumes
2334 // that the range is non-empty and the first character is a digit.
2335 template <typename Char
>
2336 FMT_CONSTEXPR
auto parse_nonnegative_int(const Char
*& begin
, const Char
* end
,
2337 int error_value
) noexcept
-> int {
2338 FMT_ASSERT(begin
!= end
&& '0' <= *begin
&& *begin
<= '9', "");
2339 unsigned value
= 0, prev
= 0;
2343 value
= value
* 10 + unsigned(*p
- '0');
2345 } while (p
!= end
&& '0' <= *p
&& *p
<= '9');
2346 auto num_digits
= p
- begin
;
2348 if (num_digits
<= std::numeric_limits
<int>::digits10
)
2349 return static_cast<int>(value
);
2350 // Check for overflow.
2351 const unsigned max
= to_unsigned((std::numeric_limits
<int>::max
)());
2352 return num_digits
== std::numeric_limits
<int>::digits10
+ 1 &&
2353 prev
* 10ull + unsigned(p
[-1] - '0') <= max
2354 ? static_cast<int>(value
)
2358 // Parses fill and alignment.
2359 template <typename Char
, typename Handler
>
2360 FMT_CONSTEXPR
auto parse_align(const Char
* begin
, const Char
* end
,
2361 Handler
&& handler
) -> const Char
* {
2362 FMT_ASSERT(begin
!= end
, "");
2363 auto align
= align::none
;
2364 auto p
= begin
+ code_point_length(begin
);
2365 if (end
- p
<= 0) p
= begin
;
2367 switch (to_ascii(*p
)) {
2369 align
= align::left
;
2372 align
= align::right
;
2375 align
= align::center
;
2380 if (align
!= align::none
) {
2384 return handler
.on_error("invalid fill character '{'"), begin
;
2385 handler
.on_fill(basic_string_view
<Char
>(begin
, to_unsigned(p
- begin
)));
2389 handler
.on_align(align
);
2391 } else if (p
== begin
) {
2399 template <typename Char
> FMT_CONSTEXPR
bool is_name_start(Char c
) {
2400 return ('a' <= c
&& c
<= 'z') || ('A' <= c
&& c
<= 'Z') || '_' == c
;
2403 template <typename Char
, typename IDHandler
>
2404 FMT_CONSTEXPR
auto do_parse_arg_id(const Char
* begin
, const Char
* end
,
2405 IDHandler
&& handler
) -> const Char
* {
2406 FMT_ASSERT(begin
!= end
, "");
2408 if (c
>= '0' && c
<= '9') {
2412 parse_nonnegative_int(begin
, end
, (std::numeric_limits
<int>::max
)());
2415 if (begin
== end
|| (*begin
!= '}' && *begin
!= ':'))
2416 handler
.on_error("invalid format string");
2421 if (!is_name_start(c
)) {
2422 handler
.on_error("invalid format string");
2428 } while (it
!= end
&& (is_name_start(c
= *it
) || ('0' <= c
&& c
<= '9')));
2429 handler(basic_string_view
<Char
>(begin
, to_unsigned(it
- begin
)));
2433 template <typename Char
, typename IDHandler
>
2434 FMT_CONSTEXPR FMT_INLINE
auto parse_arg_id(const Char
* begin
, const Char
* end
,
2435 IDHandler
&& handler
) -> const Char
* {
2437 if (c
!= '}' && c
!= ':') return do_parse_arg_id(begin
, end
, handler
);
2442 template <typename Char
, typename Handler
>
2443 FMT_CONSTEXPR
auto parse_width(const Char
* begin
, const Char
* end
,
2444 Handler
&& handler
) -> const Char
* {
2445 using detail::auto_id
;
2446 struct width_adapter
{
2449 FMT_CONSTEXPR
void operator()() { handler
.on_dynamic_width(auto_id()); }
2450 FMT_CONSTEXPR
void operator()(int id
) { handler
.on_dynamic_width(id
); }
2451 FMT_CONSTEXPR
void operator()(basic_string_view
<Char
> id
) {
2452 handler
.on_dynamic_width(id
);
2454 FMT_CONSTEXPR
void on_error(const char* message
) {
2455 if (message
) handler
.on_error(message
);
2459 FMT_ASSERT(begin
!= end
, "");
2460 if ('0' <= *begin
&& *begin
<= '9') {
2461 int width
= parse_nonnegative_int(begin
, end
, -1);
2463 handler
.on_width(width
);
2465 handler
.on_error("number is too big");
2466 } else if (*begin
== '{') {
2468 if (begin
!= end
) begin
= parse_arg_id(begin
, end
, width_adapter
{handler
});
2469 if (begin
== end
|| *begin
!= '}')
2470 return handler
.on_error("invalid format string"), begin
;
2476 template <typename Char
, typename Handler
>
2477 FMT_CONSTEXPR
auto parse_precision(const Char
* begin
, const Char
* end
,
2478 Handler
&& handler
) -> const Char
* {
2479 using detail::auto_id
;
2480 struct precision_adapter
{
2483 FMT_CONSTEXPR
void operator()() { handler
.on_dynamic_precision(auto_id()); }
2484 FMT_CONSTEXPR
void operator()(int id
) { handler
.on_dynamic_precision(id
); }
2485 FMT_CONSTEXPR
void operator()(basic_string_view
<Char
> id
) {
2486 handler
.on_dynamic_precision(id
);
2488 FMT_CONSTEXPR
void on_error(const char* message
) {
2489 if (message
) handler
.on_error(message
);
2494 auto c
= begin
!= end
? *begin
: Char();
2495 if ('0' <= c
&& c
<= '9') {
2496 auto precision
= parse_nonnegative_int(begin
, end
, -1);
2497 if (precision
!= -1)
2498 handler
.on_precision(precision
);
2500 handler
.on_error("number is too big");
2501 } else if (c
== '{') {
2504 begin
= parse_arg_id(begin
, end
, precision_adapter
{handler
});
2505 if (begin
== end
|| *begin
++ != '}')
2506 return handler
.on_error("invalid format string"), begin
;
2508 return handler
.on_error("missing precision specifier"), begin
;
2510 handler
.end_precision();
2514 template <typename Char
>
2515 FMT_CONSTEXPR
auto parse_presentation_type(Char type
) -> presentation_type
{
2516 switch (to_ascii(type
)) {
2518 return presentation_type::dec
;
2520 return presentation_type::oct
;
2522 return presentation_type::hex_lower
;
2524 return presentation_type::hex_upper
;
2526 return presentation_type::bin_lower
;
2528 return presentation_type::bin_upper
;
2530 return presentation_type::hexfloat_lower
;
2532 return presentation_type::hexfloat_upper
;
2534 return presentation_type::exp_lower
;
2536 return presentation_type::exp_upper
;
2538 return presentation_type::fixed_lower
;
2540 return presentation_type::fixed_upper
;
2542 return presentation_type::general_lower
;
2544 return presentation_type::general_upper
;
2546 return presentation_type::chr
;
2548 return presentation_type::string
;
2550 return presentation_type::pointer
;
2552 return presentation_type::debug
;
2554 return presentation_type::none
;
2558 // Parses standard format specifiers and sends notifications about parsed
2559 // components to handler.
2560 template <typename Char
, typename SpecHandler
>
2561 FMT_CONSTEXPR FMT_INLINE
auto parse_format_specs(const Char
* begin
,
2563 SpecHandler
&& handler
)
2565 if (1 < end
- begin
&& begin
[1] == '}' && is_ascii_letter(*begin
) &&
2567 presentation_type type
= parse_presentation_type(*begin
++);
2568 if (type
== presentation_type::none
)
2569 handler
.on_error("invalid type specifier");
2570 handler
.on_type(type
);
2574 if (begin
== end
) return begin
;
2576 begin
= parse_align(begin
, end
, handler
);
2577 if (begin
== end
) return begin
;
2580 switch (to_ascii(*begin
)) {
2582 handler
.on_sign(sign::plus
);
2586 handler
.on_sign(sign::minus
);
2590 handler
.on_sign(sign::space
);
2596 if (begin
== end
) return begin
;
2598 if (*begin
== '#') {
2600 if (++begin
== end
) return begin
;
2604 if (*begin
== '0') {
2606 if (++begin
== end
) return begin
;
2609 begin
= parse_width(begin
, end
, handler
);
2610 if (begin
== end
) return begin
;
2613 if (*begin
== '.') {
2614 begin
= parse_precision(begin
, end
, handler
);
2615 if (begin
== end
) return begin
;
2618 if (*begin
== 'L') {
2619 handler
.on_localized();
2624 if (begin
!= end
&& *begin
!= '}') {
2625 presentation_type type
= parse_presentation_type(*begin
++);
2626 if (type
== presentation_type::none
)
2627 handler
.on_error("invalid type specifier");
2628 handler
.on_type(type
);
2633 template <typename Char
, typename Handler
>
2634 FMT_CONSTEXPR
auto parse_replacement_field(const Char
* begin
, const Char
* end
,
2635 Handler
&& handler
) -> const Char
* {
2640 FMT_CONSTEXPR
void operator()() { arg_id
= handler
.on_arg_id(); }
2641 FMT_CONSTEXPR
void operator()(int id
) { arg_id
= handler
.on_arg_id(id
); }
2642 FMT_CONSTEXPR
void operator()(basic_string_view
<Char
> id
) {
2643 arg_id
= handler
.on_arg_id(id
);
2645 FMT_CONSTEXPR
void on_error(const char* message
) {
2646 if (message
) handler
.on_error(message
);
2651 if (begin
== end
) return handler
.on_error("invalid format string"), end
;
2652 if (*begin
== '}') {
2653 handler
.on_replacement_field(handler
.on_arg_id(), begin
);
2654 } else if (*begin
== '{') {
2655 handler
.on_text(begin
, begin
+ 1);
2657 auto adapter
= id_adapter
{handler
, 0};
2658 begin
= parse_arg_id(begin
, end
, adapter
);
2659 Char c
= begin
!= end
? *begin
: Char();
2661 handler
.on_replacement_field(adapter
.arg_id
, begin
);
2662 } else if (c
== ':') {
2663 begin
= handler
.on_format_specs(adapter
.arg_id
, begin
+ 1, end
);
2664 if (begin
== end
|| *begin
!= '}')
2665 return handler
.on_error("unknown format specifier"), end
;
2667 return handler
.on_error("missing '}' in format string"), end
;
2673 template <bool IS_CONSTEXPR
, typename Char
, typename Handler
>
2674 FMT_CONSTEXPR FMT_INLINE
void parse_format_string(
2675 basic_string_view
<Char
> format_str
, Handler
&& handler
) {
2676 // Workaround a name-lookup bug in MSVC's modules implementation.
2679 auto begin
= format_str
.data();
2680 auto end
= begin
+ format_str
.size();
2681 if (end
- begin
< 32) {
2682 // Use a simple loop instead of memchr for small strings.
2683 const Char
* p
= begin
;
2687 handler
.on_text(begin
, p
- 1);
2688 begin
= p
= parse_replacement_field(p
- 1, end
, handler
);
2689 } else if (c
== '}') {
2690 if (p
== end
|| *p
!= '}')
2691 return handler
.on_error("unmatched '}' in format string");
2692 handler
.on_text(begin
, p
);
2696 handler
.on_text(begin
, end
);
2700 FMT_CONSTEXPR
void operator()(const Char
* from
, const Char
* to
) {
2701 if (from
== to
) return;
2703 const Char
* p
= nullptr;
2704 if (!find
<IS_CONSTEXPR
>(from
, to
, Char('}'), p
))
2705 return handler_
.on_text(from
, to
);
2707 if (p
== to
|| *p
!= '}')
2708 return handler_
.on_error("unmatched '}' in format string");
2709 handler_
.on_text(from
, p
);
2714 } write
= {handler
};
2715 while (begin
!= end
) {
2716 // Doing two passes with memchr (one for '{' and another for '}') is up to
2717 // 2.5x faster than the naive one-pass implementation on big format strings.
2718 const Char
* p
= begin
;
2719 if (*begin
!= '{' && !find
<IS_CONSTEXPR
>(begin
+ 1, end
, Char('{'), p
))
2720 return write(begin
, end
);
2722 begin
= parse_replacement_field(p
, end
, handler
);
2726 template <typename T
, bool = is_named_arg
<T
>::value
> struct strip_named_arg
{
2729 template <typename T
> struct strip_named_arg
<T
, true> {
2730 using type
= remove_cvref_t
<decltype(T::value
)>;
2733 template <typename T
, typename ParseContext
>
2734 FMT_CONSTEXPR
auto parse_format_specs(ParseContext
& ctx
)
2735 -> decltype(ctx
.begin()) {
2736 using char_type
= typename
ParseContext::char_type
;
2737 using context
= buffer_context
<char_type
>;
2738 using stripped_type
= typename strip_named_arg
<T
>::type
;
2739 using mapped_type
= conditional_t
<
2740 mapped_type_constant
<T
, context
>::value
!= type::custom_type
,
2741 decltype(arg_mapper
<context
>().map(std::declval
<const T
&>())),
2743 auto f
= conditional_t
<has_formatter
<mapped_type
, context
>::value
,
2744 formatter
<mapped_type
, char_type
>,
2745 fallback_formatter
<stripped_type
, char_type
>>();
2746 return f
.parse(ctx
);
2749 template <typename ErrorHandler
>
2750 FMT_CONSTEXPR
void check_int_type_spec(presentation_type type
,
2751 ErrorHandler
&& eh
) {
2752 if (type
> presentation_type::bin_upper
&& type
!= presentation_type::chr
)
2753 eh
.on_error("invalid type specifier");
2756 // Checks char specs and returns true if the type spec is char (and not int).
2757 template <typename Char
, typename ErrorHandler
= error_handler
>
2758 FMT_CONSTEXPR
auto check_char_specs(const basic_format_specs
<Char
>& specs
,
2759 ErrorHandler
&& eh
= {}) -> bool {
2760 if (specs
.type
!= presentation_type::none
&&
2761 specs
.type
!= presentation_type::chr
&&
2762 specs
.type
!= presentation_type::debug
) {
2763 check_int_type_spec(specs
.type
, eh
);
2766 if (specs
.align
== align::numeric
|| specs
.sign
!= sign::none
|| specs
.alt
)
2767 eh
.on_error("invalid format specifier for char");
2771 // A floating-point presentation format.
2772 enum class float_format
: unsigned char {
2773 general
, // General: exponent notation or fixed point based on magnitude.
2774 exp
, // Exponent notation with the default precision of 6, e.g. 1.2e-3.
2775 fixed
, // Fixed point with the default precision of 6, e.g. 0.0012.
2779 struct float_specs
{
2781 float_format format
: 8;
2789 template <typename ErrorHandler
= error_handler
, typename Char
>
2790 FMT_CONSTEXPR
auto parse_float_type_spec(const basic_format_specs
<Char
>& specs
,
2791 ErrorHandler
&& eh
= {})
2793 auto result
= float_specs();
2794 result
.showpoint
= specs
.alt
;
2795 result
.locale
= specs
.localized
;
2796 switch (specs
.type
) {
2797 case presentation_type::none
:
2798 result
.format
= float_format::general
;
2800 case presentation_type::general_upper
:
2801 result
.upper
= true;
2803 case presentation_type::general_lower
:
2804 result
.format
= float_format::general
;
2806 case presentation_type::exp_upper
:
2807 result
.upper
= true;
2809 case presentation_type::exp_lower
:
2810 result
.format
= float_format::exp
;
2811 result
.showpoint
|= specs
.precision
!= 0;
2813 case presentation_type::fixed_upper
:
2814 result
.upper
= true;
2816 case presentation_type::fixed_lower
:
2817 result
.format
= float_format::fixed
;
2818 result
.showpoint
|= specs
.precision
!= 0;
2820 case presentation_type::hexfloat_upper
:
2821 result
.upper
= true;
2823 case presentation_type::hexfloat_lower
:
2824 result
.format
= float_format::hex
;
2827 eh
.on_error("invalid type specifier");
2833 template <typename ErrorHandler
= error_handler
>
2834 FMT_CONSTEXPR
auto check_cstring_type_spec(presentation_type type
,
2835 ErrorHandler
&& eh
= {}) -> bool {
2836 if (type
== presentation_type::none
|| type
== presentation_type::string
||
2837 type
== presentation_type::debug
)
2839 if (type
!= presentation_type::pointer
) eh
.on_error("invalid type specifier");
2843 template <typename ErrorHandler
= error_handler
>
2844 FMT_CONSTEXPR
void check_string_type_spec(presentation_type type
,
2845 ErrorHandler
&& eh
= {}) {
2846 if (type
!= presentation_type::none
&& type
!= presentation_type::string
&&
2847 type
!= presentation_type::debug
)
2848 eh
.on_error("invalid type specifier");
2851 template <typename ErrorHandler
>
2852 FMT_CONSTEXPR
void check_pointer_type_spec(presentation_type type
,
2853 ErrorHandler
&& eh
) {
2854 if (type
!= presentation_type::none
&& type
!= presentation_type::pointer
)
2855 eh
.on_error("invalid type specifier");
2858 // A parse_format_specs handler that checks if specifiers are consistent with
2859 // the argument type.
2860 template <typename Handler
> class specs_checker
: public Handler
{
2862 detail::type arg_type_
;
2864 FMT_CONSTEXPR
void require_numeric_argument() {
2865 if (!is_arithmetic_type(arg_type_
))
2866 this->on_error("format specifier requires numeric argument");
2870 FMT_CONSTEXPR
specs_checker(const Handler
& handler
, detail::type arg_type
)
2871 : Handler(handler
), arg_type_(arg_type
) {}
2873 FMT_CONSTEXPR
void on_align(align_t align
) {
2874 if (align
== align::numeric
) require_numeric_argument();
2875 Handler::on_align(align
);
2878 FMT_CONSTEXPR
void on_sign(sign_t s
) {
2879 require_numeric_argument();
2880 if (is_integral_type(arg_type_
) && arg_type_
!= type::int_type
&&
2881 arg_type_
!= type::long_long_type
&& arg_type_
!= type::int128_type
&&
2882 arg_type_
!= type::char_type
) {
2883 this->on_error("format specifier requires signed argument");
2885 Handler::on_sign(s
);
2888 FMT_CONSTEXPR
void on_hash() {
2889 require_numeric_argument();
2893 FMT_CONSTEXPR
void on_localized() {
2894 require_numeric_argument();
2895 Handler::on_localized();
2898 FMT_CONSTEXPR
void on_zero() {
2899 require_numeric_argument();
2903 FMT_CONSTEXPR
void end_precision() {
2904 if (is_integral_type(arg_type_
) || arg_type_
== type::pointer_type
)
2905 this->on_error("precision not allowed for this argument type");
2909 constexpr int invalid_arg_index
= -1;
2911 #if FMT_USE_NONTYPE_TEMPLATE_ARGS
2912 template <int N
, typename T
, typename
... Args
, typename Char
>
2913 constexpr auto get_arg_index_by_name(basic_string_view
<Char
> name
) -> int {
2914 if constexpr (detail::is_statically_named_arg
<T
>()) {
2915 if (name
== T::name
) return N
;
2917 if constexpr (sizeof...(Args
) > 0)
2918 return get_arg_index_by_name
<N
+ 1, Args
...>(name
);
2919 (void)name
; // Workaround an MSVC bug about "unused" parameter.
2920 return invalid_arg_index
;
2924 template <typename
... Args
, typename Char
>
2925 FMT_CONSTEXPR
auto get_arg_index_by_name(basic_string_view
<Char
> name
) -> int {
2926 #if FMT_USE_NONTYPE_TEMPLATE_ARGS
2927 if constexpr (sizeof...(Args
) > 0)
2928 return get_arg_index_by_name
<0, Args
...>(name
);
2931 return invalid_arg_index
;
2934 template <typename Char
, typename ErrorHandler
, typename
... Args
>
2935 class format_string_checker
{
2937 // In the future basic_format_parse_context will replace compile_parse_context
2938 // here and will use is_constant_evaluated and downcasting to access the data
2939 // needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1.
2940 using parse_context_type
= compile_parse_context
<Char
, ErrorHandler
>;
2941 static constexpr int num_args
= sizeof...(Args
);
2943 // Format specifier parsing function.
2944 using parse_func
= const Char
* (*)(parse_context_type
&);
2946 parse_context_type context_
;
2947 parse_func parse_funcs_
[num_args
> 0 ? static_cast<size_t>(num_args
) : 1];
2948 type types_
[num_args
> 0 ? static_cast<size_t>(num_args
) : 1];
2951 explicit FMT_CONSTEXPR
format_string_checker(
2952 basic_string_view
<Char
> format_str
, ErrorHandler eh
)
2953 : context_(format_str
, num_args
, types_
, eh
),
2954 parse_funcs_
{&parse_format_specs
<Args
, parse_context_type
>...},
2956 mapped_type_constant
<Args
,
2957 basic_format_context
<Char
*, Char
>>::value
...} {
2960 FMT_CONSTEXPR
void on_text(const Char
*, const Char
*) {}
2962 FMT_CONSTEXPR
auto on_arg_id() -> int { return context_
.next_arg_id(); }
2963 FMT_CONSTEXPR
auto on_arg_id(int id
) -> int {
2964 return context_
.check_arg_id(id
), id
;
2966 FMT_CONSTEXPR
auto on_arg_id(basic_string_view
<Char
> id
) -> int {
2967 #if FMT_USE_NONTYPE_TEMPLATE_ARGS
2968 auto index
= get_arg_index_by_name
<Args
...>(id
);
2969 if (index
== invalid_arg_index
) on_error("named argument is not found");
2970 return context_
.check_arg_id(index
), index
;
2973 on_error("compile-time checks for named arguments require C++20 support");
2978 FMT_CONSTEXPR
void on_replacement_field(int, const Char
*) {}
2980 FMT_CONSTEXPR
auto on_format_specs(int id
, const Char
* begin
, const Char
*)
2982 context_
.advance_to(context_
.begin() + (begin
- &*context_
.begin()));
2983 // id >= 0 check is a workaround for gcc 10 bug (#2065).
2984 return id
>= 0 && id
< num_args
? parse_funcs_
[id
](context_
) : begin
;
2987 FMT_CONSTEXPR
void on_error(const char* message
) {
2988 context_
.on_error(message
);
2992 // Reports a compile-time error if S is not a valid format string.
2993 template <typename
..., typename S
, FMT_ENABLE_IF(!is_compile_string
<S
>::value
)>
2994 FMT_INLINE
void check_format_string(const S
&) {
2995 #ifdef FMT_ENFORCE_COMPILE_STRING
2996 static_assert(is_compile_string
<S
>::value
,
2997 "FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
3001 template <typename
... Args
, typename S
,
3002 FMT_ENABLE_IF(is_compile_string
<S
>::value
)>
3003 void check_format_string(S format_str
) {
3004 FMT_CONSTEXPR
auto s
= basic_string_view
<typename
S::char_type
>(format_str
);
3005 using checker
= format_string_checker
<typename
S::char_type
, error_handler
,
3006 remove_cvref_t
<Args
>...>;
3007 FMT_CONSTEXPR
bool invalid_format
=
3008 (parse_format_string
<true>(s
, checker(s
, {})), true);
3009 ignore_unused(invalid_format
);
3012 template <typename Char
>
3014 buffer
<Char
>& buf
, basic_string_view
<Char
> fmt
,
3015 basic_format_args
<FMT_BUFFER_CONTEXT(type_identity_t
<Char
>)> args
,
3016 locale_ref loc
= {});
3018 FMT_API
void vprint_mojibake(std::FILE*, string_view
, format_args
);
3020 inline void vprint_mojibake(std::FILE*, string_view
, format_args
) {}
3022 FMT_END_DETAIL_NAMESPACE
3024 // A formatter specialization for the core types corresponding to detail::type
3026 template <typename T
, typename Char
>
3027 struct formatter
<T
, Char
,
3028 enable_if_t
<detail::type_constant
<T
, Char
>::value
!=
3029 detail::type::custom_type
>> {
3031 detail::dynamic_format_specs
<Char
> specs_
;
3034 // Parses format specifiers stopping either at the end of the range or at the
3036 template <typename ParseContext
>
3037 FMT_CONSTEXPR
auto parse(ParseContext
& ctx
) -> decltype(ctx
.begin()) {
3038 auto begin
= ctx
.begin(), end
= ctx
.end();
3039 if (begin
== end
) return begin
;
3040 using handler_type
= detail::dynamic_specs_handler
<ParseContext
>;
3041 auto type
= detail::type_constant
<T
, Char
>::value
;
3043 detail::specs_checker
<handler_type
>(handler_type(specs_
, ctx
), type
);
3044 auto it
= detail::parse_format_specs(begin
, end
, checker
);
3045 auto eh
= ctx
.error_handler();
3047 case detail::type::none_type
:
3048 FMT_ASSERT(false, "invalid argument type");
3050 case detail::type::bool_type
:
3051 if (specs_
.type
== presentation_type::none
||
3052 specs_
.type
== presentation_type::string
) {
3056 case detail::type::int_type
:
3057 case detail::type::uint_type
:
3058 case detail::type::long_long_type
:
3059 case detail::type::ulong_long_type
:
3060 case detail::type::int128_type
:
3061 case detail::type::uint128_type
:
3062 detail::check_int_type_spec(specs_
.type
, eh
);
3064 case detail::type::char_type
:
3065 detail::check_char_specs(specs_
, eh
);
3067 case detail::type::float_type
:
3068 if (detail::const_check(FMT_USE_FLOAT
))
3069 detail::parse_float_type_spec(specs_
, eh
);
3071 FMT_ASSERT(false, "float support disabled");
3073 case detail::type::double_type
:
3074 if (detail::const_check(FMT_USE_DOUBLE
))
3075 detail::parse_float_type_spec(specs_
, eh
);
3077 FMT_ASSERT(false, "double support disabled");
3079 case detail::type::long_double_type
:
3080 if (detail::const_check(FMT_USE_LONG_DOUBLE
))
3081 detail::parse_float_type_spec(specs_
, eh
);
3083 FMT_ASSERT(false, "long double support disabled");
3085 case detail::type::cstring_type
:
3086 detail::check_cstring_type_spec(specs_
.type
, eh
);
3088 case detail::type::string_type
:
3089 detail::check_string_type_spec(specs_
.type
, eh
);
3091 case detail::type::pointer_type
:
3092 detail::check_pointer_type_spec(specs_
.type
, eh
);
3094 case detail::type::custom_type
:
3095 // Custom format specifiers are checked in parse functions of
3096 // formatter specializations.
3102 template <detail::type U
= detail::type_constant
<T
, Char
>::value
,
3103 enable_if_t
<(U
== detail::type::string_type
||
3104 U
== detail::type::cstring_type
||
3105 U
== detail::type::char_type
),
3107 FMT_CONSTEXPR
void set_debug_format() {
3108 specs_
.type
= presentation_type::debug
;
3111 template <typename FormatContext
>
3112 FMT_CONSTEXPR
auto format(const T
& val
, FormatContext
& ctx
) const
3113 -> decltype(ctx
.out());
3116 #define FMT_FORMAT_AS(Type, Base) \
3117 template <typename Char> \
3118 struct formatter<Type, Char> : formatter<Base, Char> { \
3119 template <typename FormatContext> \
3120 auto format(Type const& val, FormatContext& ctx) const \
3121 -> decltype(ctx.out()) { \
3122 return formatter<Base, Char>::format(static_cast<Base>(val), ctx); \
3126 FMT_FORMAT_AS(signed char, int);
3127 FMT_FORMAT_AS(unsigned char, unsigned);
3128 FMT_FORMAT_AS(short, int);
3129 FMT_FORMAT_AS(unsigned short, unsigned);
3130 FMT_FORMAT_AS(long, long long);
3131 FMT_FORMAT_AS(unsigned long, unsigned long long);
3132 FMT_FORMAT_AS(Char
*, const Char
*);
3133 FMT_FORMAT_AS(std::basic_string
<Char
>, basic_string_view
<Char
>);
3134 FMT_FORMAT_AS(std::nullptr_t
, const void*);
3135 FMT_FORMAT_AS(detail::std_string_view
<Char
>, basic_string_view
<Char
>);
3137 template <typename Char
> struct basic_runtime
{ basic_string_view
<Char
> str
; };
3139 /** A compile-time format string. */
3140 template <typename Char
, typename
... Args
> class basic_format_string
{
3142 basic_string_view
<Char
> str_
;
3145 template <typename S
,
3147 std::is_convertible
<const S
&, basic_string_view
<Char
>>::value
)>
3148 FMT_CONSTEVAL FMT_INLINE
basic_format_string(const S
& s
) : str_(s
) {
3151 (std::is_base_of
<detail::view
, remove_reference_t
<Args
>>::value
&&
3152 std::is_reference
<Args
>::value
)...>() == 0,
3153 "passing views as lvalues is disallowed");
3154 #ifdef FMT_HAS_CONSTEVAL
3155 if constexpr (detail::count_named_args
<Args
...>() ==
3156 detail::count_statically_named_args
<Args
...>()) {
3157 using checker
= detail::format_string_checker
<Char
, detail::error_handler
,
3158 remove_cvref_t
<Args
>...>;
3159 detail::parse_format_string
<true>(str_
, checker(s
, {}));
3162 detail::check_format_string
<Args
...>(s
);
3165 basic_format_string(basic_runtime
<Char
> r
) : str_(r
.str
) {}
3167 FMT_INLINE
operator basic_string_view
<Char
>() const { return str_
; }
3170 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
3171 // Workaround broken conversion on older gcc.
3172 template <typename
...> using format_string
= string_view
;
3173 inline auto runtime(string_view s
) -> string_view
{ return s
; }
3175 template <typename
... Args
>
3176 using format_string
= basic_format_string
<char, type_identity_t
<Args
>...>;
3179 Creates a runtime format string.
3183 // Check format string at runtime instead of compile-time.
3184 fmt::print(fmt::runtime("{:d}"), "I am not a number");
3187 inline auto runtime(string_view s
) -> basic_runtime
<char> { return {{s
}}; }
3190 FMT_API
auto vformat(string_view fmt
, format_args args
) -> std::string
;
3194 Formats ``args`` according to specifications in ``fmt`` and returns the result
3199 #include <fmt/core.h>
3200 std::string message = fmt::format("The answer is {}.", 42);
3203 template <typename
... T
>
3204 FMT_NODISCARD FMT_INLINE
auto format(format_string
<T
...> fmt
, T
&&... args
)
3206 return vformat(fmt
, fmt::make_format_args(args
...));
3209 /** Formats a string and writes the output to ``out``. */
3210 template <typename OutputIt
,
3211 FMT_ENABLE_IF(detail::is_output_iterator
<OutputIt
, char>::value
)>
3212 auto vformat_to(OutputIt out
, string_view fmt
, format_args args
) -> OutputIt
{
3213 using detail::get_buffer
;
3214 auto&& buf
= get_buffer
<char>(out
);
3215 detail::vformat_to(buf
, fmt
, args
, {});
3216 return detail::get_iterator(buf
);
3221 Formats ``args`` according to specifications in ``fmt``, writes the result to
3222 the output iterator ``out`` and returns the iterator past the end of the output
3223 range. `format_to` does not append a terminating null character.
3227 auto out = std::vector<char>();
3228 fmt::format_to(std::back_inserter(out), "{}", 42);
3231 template <typename OutputIt
, typename
... T
,
3232 FMT_ENABLE_IF(detail::is_output_iterator
<OutputIt
, char>::value
)>
3233 FMT_INLINE
auto format_to(OutputIt out
, format_string
<T
...> fmt
, T
&&... args
)
3235 return vformat_to(out
, fmt
, fmt::make_format_args(args
...));
3238 template <typename OutputIt
> struct format_to_n_result
{
3239 /** Iterator past the end of the output range. */
3241 /** Total (not truncated) output size. */
3245 template <typename OutputIt
, typename
... T
,
3246 FMT_ENABLE_IF(detail::is_output_iterator
<OutputIt
, char>::value
)>
3247 auto vformat_to_n(OutputIt out
, size_t n
, string_view fmt
, format_args args
)
3248 -> format_to_n_result
<OutputIt
> {
3249 using traits
= detail::fixed_buffer_traits
;
3250 auto buf
= detail::iterator_buffer
<OutputIt
, char, traits
>(out
, n
);
3251 detail::vformat_to(buf
, fmt
, args
, {});
3252 return {buf
.out(), buf
.count()};
3257 Formats ``args`` according to specifications in ``fmt``, writes up to ``n``
3258 characters of the result to the output iterator ``out`` and returns the total
3259 (not truncated) output size and the iterator past the end of the output range.
3260 `format_to_n` does not append a terminating null character.
3263 template <typename OutputIt
, typename
... T
,
3264 FMT_ENABLE_IF(detail::is_output_iterator
<OutputIt
, char>::value
)>
3265 FMT_INLINE
auto format_to_n(OutputIt out
, size_t n
, format_string
<T
...> fmt
,
3266 T
&&... args
) -> format_to_n_result
<OutputIt
> {
3267 return vformat_to_n(out
, n
, fmt
, fmt::make_format_args(args
...));
3270 /** Returns the number of chars in the output of ``format(fmt, args...)``. */
3271 template <typename
... T
>
3272 FMT_NODISCARD FMT_INLINE
auto formatted_size(format_string
<T
...> fmt
,
3273 T
&&... args
) -> size_t {
3274 auto buf
= detail::counting_buffer
<>();
3275 detail::vformat_to(buf
, string_view(fmt
), fmt::make_format_args(args
...), {});
3279 FMT_API
void vprint(string_view fmt
, format_args args
);
3280 FMT_API
void vprint(std::FILE* f
, string_view fmt
, format_args args
);
3284 Formats ``args`` according to specifications in ``fmt`` and writes the output
3289 fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
3292 template <typename
... T
>
3293 FMT_INLINE
void print(format_string
<T
...> fmt
, T
&&... args
) {
3294 const auto& vargs
= fmt::make_format_args(args
...);
3295 return detail::is_utf8() ? vprint(fmt
, vargs
)
3296 : detail::vprint_mojibake(stdout
, fmt
, vargs
);
3301 Formats ``args`` according to specifications in ``fmt`` and writes the
3302 output to the file ``f``.
3306 fmt::print(stderr, "Don't {}!", "panic");
3309 template <typename
... T
>
3310 FMT_INLINE
void print(std::FILE* f
, format_string
<T
...> fmt
, T
&&... args
) {
3311 const auto& vargs
= fmt::make_format_args(args
...);
3312 return detail::is_utf8() ? vprint(f
, fmt
, vargs
)
3313 : detail::vprint_mojibake(f
, fmt
, vargs
);
3316 FMT_MODULE_EXPORT_END
3317 FMT_GCC_PRAGMA("GCC pop_options")
3320 #ifdef FMT_HEADER_ONLY
3321 # include "format.h"
3323 #endif // FMT_CORE_H_