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
16 #include <memory> // std::addressof
18 #include <type_traits>
20 // The fmt library version in the form major * 10000 + minor * 100 + patch.
21 #define FMT_VERSION 100200
23 #if defined(__clang__) && !defined(__ibmxl__)
24 # define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
26 # define FMT_CLANG_VERSION 0
29 #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && \
30 !defined(__NVCOMPILER)
31 # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
33 # define FMT_GCC_VERSION 0
36 #ifndef FMT_GCC_PRAGMA
37 // Workaround _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884.
38 # if FMT_GCC_VERSION >= 504
39 # define FMT_GCC_PRAGMA(arg) _Pragma(arg)
41 # define FMT_GCC_PRAGMA(arg)
46 # define FMT_ICC_VERSION __ICL
47 #elif defined(__INTEL_COMPILER)
48 # define FMT_ICC_VERSION __INTEL_COMPILER
50 # define FMT_ICC_VERSION 0
54 # define FMT_MSC_VERSION _MSC_VER
55 # define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__))
57 # define FMT_MSC_VERSION 0
58 # define FMT_MSC_WARNING(...)
62 # define FMT_CPLUSPLUS _MSVC_LANG
64 # define FMT_CPLUSPLUS __cplusplus
68 # define FMT_HAS_FEATURE(x) __has_feature(x)
70 # define FMT_HAS_FEATURE(x) 0
73 #if defined(__has_include) || FMT_ICC_VERSION >= 1600 || FMT_MSC_VERSION > 1900
74 # define FMT_HAS_INCLUDE(x) __has_include(x)
76 # define FMT_HAS_INCLUDE(x) 0
79 #ifdef __has_cpp_attribute
80 # define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
82 # define FMT_HAS_CPP_ATTRIBUTE(x) 0
85 #define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
86 (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
88 #define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
89 (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
91 // Check if relaxed C++14 constexpr is supported.
92 // GCC doesn't allow throw in constexpr until version 6 (bug 67371).
93 #ifndef FMT_USE_CONSTEXPR
94 # if (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912 || \
95 (FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L)) && \
96 !FMT_ICC_VERSION && (!defined(__NVCC__) || FMT_CPLUSPLUS >= 202002L)
97 # define FMT_USE_CONSTEXPR 1
99 # define FMT_USE_CONSTEXPR 0
102 #if FMT_USE_CONSTEXPR
103 # define FMT_CONSTEXPR constexpr
105 # define FMT_CONSTEXPR
108 #if (FMT_CPLUSPLUS >= 202002L || \
109 (FMT_CPLUSPLUS >= 201709L && FMT_GCC_VERSION >= 1002)) && \
110 ((!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 10) && \
111 (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 10000) && \
112 (!FMT_MSC_VERSION || FMT_MSC_VERSION >= 1928)) && \
113 defined(__cpp_lib_is_constant_evaluated)
114 # define FMT_CONSTEXPR20 constexpr
116 # define FMT_CONSTEXPR20
119 // Check if constexpr std::char_traits<>::{compare,length} are supported.
120 #if defined(__GLIBCXX__)
121 # if FMT_CPLUSPLUS >= 201703L && defined(_GLIBCXX_RELEASE) && \
122 _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE.
123 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr
125 #elif defined(_LIBCPP_VERSION) && FMT_CPLUSPLUS >= 201703L && \
126 _LIBCPP_VERSION >= 4000
127 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr
128 #elif FMT_MSC_VERSION >= 1914 && FMT_CPLUSPLUS >= 201703L
129 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr
131 #ifndef FMT_CONSTEXPR_CHAR_TRAITS
132 # define FMT_CONSTEXPR_CHAR_TRAITS
135 // Check if exceptions are disabled.
136 #ifndef FMT_EXCEPTIONS
137 # if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
138 (FMT_MSC_VERSION && !_HAS_EXCEPTIONS)
139 # define FMT_EXCEPTIONS 0
141 # define FMT_EXCEPTIONS 1
145 // Disable [[noreturn]] on MSVC/NVCC because of bogus unreachable code warnings.
146 #if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && \
148 # define FMT_NORETURN [[noreturn]]
150 # define FMT_NORETURN
153 #ifndef FMT_NODISCARD
154 # if FMT_HAS_CPP17_ATTRIBUTE(nodiscard)
155 # define FMT_NODISCARD [[nodiscard]]
157 # define FMT_NODISCARD
162 # if FMT_GCC_VERSION || FMT_CLANG_VERSION
163 # define FMT_INLINE inline __attribute__((always_inline))
165 # define FMT_INLINE inline
170 # define FMT_UNCHECKED_ITERATOR(It) \
171 using _Unchecked_type = It // Mark iterator as checked.
173 # define FMT_UNCHECKED_ITERATOR(It) using unchecked_type = It
176 #ifndef FMT_BEGIN_NAMESPACE
177 # define FMT_BEGIN_NAMESPACE \
179 inline namespace v10 {
180 # define FMT_END_NAMESPACE \
187 # define FMT_BEGIN_EXPORT
188 # define FMT_END_EXPORT
191 #if FMT_GCC_VERSION || FMT_CLANG_VERSION
192 # define FMT_VISIBILITY(value) __attribute__((visibility(value)))
194 # define FMT_VISIBILITY(value)
197 #if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
198 # if defined(FMT_LIB_EXPORT)
199 # define FMT_API __declspec(dllexport)
200 # elif defined(FMT_SHARED)
201 # define FMT_API __declspec(dllimport)
203 #elif defined(FMT_LIB_EXPORT) || defined(FMT_SHARED)
204 # define FMT_API FMT_VISIBILITY("default")
210 // libc++ supports string_view in pre-c++17.
211 #if FMT_HAS_INCLUDE(<string_view>) && \
212 (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION))
213 # include <string_view>
214 # define FMT_USE_STRING_VIEW
215 #elif FMT_HAS_INCLUDE("experimental/string_view") && FMT_CPLUSPLUS >= 201402L
216 # include <experimental/string_view>
217 # define FMT_USE_EXPERIMENTAL_STRING_VIEW
221 # define FMT_UNICODE !FMT_MSC_VERSION
224 #ifndef FMT_CONSTEVAL
225 # if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \
226 (!defined(__apple_build_version__) || \
227 __apple_build_version__ >= 14000029L) && \
228 FMT_CPLUSPLUS >= 202002L) || \
229 (defined(__cpp_consteval) && \
230 (!FMT_MSC_VERSION || FMT_MSC_VERSION >= 1929))
231 // consteval is broken in MSVC before VS2019 version 16.10 and Apple clang
233 # define FMT_CONSTEVAL consteval
234 # define FMT_HAS_CONSTEVAL
236 # define FMT_CONSTEVAL
240 #ifndef FMT_USE_NONTYPE_TEMPLATE_ARGS
241 # if defined(__cpp_nontype_template_args) && \
242 ((FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L) || \
243 __cpp_nontype_template_args >= 201911L) && \
244 !defined(__NVCOMPILER) && !defined(__LCC__)
245 # define FMT_USE_NONTYPE_TEMPLATE_ARGS 1
247 # define FMT_USE_NONTYPE_TEMPLATE_ARGS 0
251 // GCC < 5 requires this-> in decltype
252 #ifndef FMT_DECLTYPE_THIS
253 # if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
254 # define FMT_DECLTYPE_THIS this->
256 # define FMT_DECLTYPE_THIS
260 FMT_GCC_PRAGMA("GCC push_options")
264 // Implementations of enable_if_t and other metafunctions for older systems.
265 template <bool B
, typename T
= void>
266 using enable_if_t
= typename
std::enable_if
<B
, T
>::type
;
267 template <bool B
, typename T
, typename F
>
268 using conditional_t
= typename
std::conditional
<B
, T
, F
>::type
;
269 template <bool B
> using bool_constant
= std::integral_constant
<bool, B
>;
270 template <typename T
>
271 using remove_reference_t
= typename
std::remove_reference
<T
>::type
;
272 template <typename T
>
273 using remove_const_t
= typename
std::remove_const
<T
>::type
;
274 template <typename T
>
275 using remove_cvref_t
= typename
std::remove_cv
<remove_reference_t
<T
>>::type
;
276 template <typename T
> struct type_identity
{
279 template <typename T
> using type_identity_t
= typename type_identity
<T
>::type
;
280 template <typename T
>
281 using underlying_t
= typename
std::underlying_type
<T
>::type
;
283 // Checks whether T is a container with contiguous storage.
284 template <typename T
> struct is_contiguous
: std::false_type
{};
285 template <typename Char
>
286 struct is_contiguous
<std::basic_string
<Char
>> : std::true_type
{};
289 constexpr monostate() {}
292 // An enable_if helper to be used in template parameters which results in much
293 // shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
294 // to workaround a bug in MSVC 2019 (see #1140 and #1186).
296 # define FMT_ENABLE_IF(...)
298 # define FMT_ENABLE_IF(...) fmt::enable_if_t<(__VA_ARGS__), int> = 0
301 // This is defined in core.h instead of format.h to avoid injecting in std.
302 // It is a template to avoid undesirable implicit conversions to std::byte.
303 #ifdef __cpp_lib_byte
304 template <typename T
, FMT_ENABLE_IF(std::is_same
<T
, std::byte
>::value
)>
305 inline auto format_as(T b
) -> unsigned char {
306 return static_cast<unsigned char>(b
);
311 // Suppresses "unused variable" warnings with the method described in
312 // https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/.
313 // (void)var does not work on many Intel compilers.
314 template <typename
... T
> FMT_CONSTEXPR
void ignore_unused(const T
&...) {}
316 constexpr FMT_INLINE
auto is_constant_evaluated(
317 bool default_value
= false) noexcept
-> bool {
318 // Workaround for incompatibility between libstdc++ consteval-based
319 // std::is_constant_evaluated() implementation and clang-14.
320 // https://github.com/fmtlib/fmt/issues/3247
321 #if FMT_CPLUSPLUS >= 202002L && defined(_GLIBCXX_RELEASE) && \
322 _GLIBCXX_RELEASE >= 12 && \
323 (FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500)
324 ignore_unused(default_value
);
325 return __builtin_is_constant_evaluated();
326 #elif defined(__cpp_lib_is_constant_evaluated)
327 ignore_unused(default_value
);
328 return std::is_constant_evaluated();
330 return default_value
;
334 // Suppresses "conditional expression is constant" warnings.
335 template <typename T
> constexpr FMT_INLINE
auto const_check(T value
) -> T
{
339 FMT_NORETURN FMT_API
void assert_fail(const char* file
, int line
,
340 const char* message
);
344 // FMT_ASSERT is not empty to avoid -Wempty-body.
345 # define FMT_ASSERT(condition, message) \
346 fmt::detail::ignore_unused((condition), (message))
348 # define FMT_ASSERT(condition, message) \
349 ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
351 : fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
355 #if defined(FMT_USE_STRING_VIEW)
356 template <typename Char
> using std_string_view
= std::basic_string_view
<Char
>;
357 #elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
358 template <typename Char
>
359 using std_string_view
= std::experimental::basic_string_view
<Char
>;
361 template <typename T
> struct std_string_view
{};
364 #ifdef FMT_USE_INT128
366 #elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \
367 !(FMT_CLANG_VERSION && FMT_MSC_VERSION)
368 # define FMT_USE_INT128 1
369 using int128_opt
= __int128_t
; // An optional native 128-bit integer.
370 using uint128_opt
= __uint128_t
;
371 template <typename T
> inline auto convert_for_visit(T value
) -> T
{
375 # define FMT_USE_INT128 0
378 enum class int128_opt
{};
379 enum class uint128_opt
{};
380 // Reduce template instantiations.
381 template <typename T
> auto convert_for_visit(T
) -> monostate
{ return {}; }
384 // Casts a nonnegative integer to unsigned.
385 template <typename Int
>
386 FMT_CONSTEXPR
auto to_unsigned(Int value
) ->
387 typename
std::make_unsigned
<Int
>::type
{
388 FMT_ASSERT(std::is_unsigned
<Int
>::value
|| value
>= 0, "negative value");
389 return static_cast<typename
std::make_unsigned
<Int
>::type
>(value
);
392 FMT_CONSTEXPR
inline auto is_utf8() -> bool {
393 FMT_MSC_WARNING(suppress
: 4566) constexpr unsigned char section
[] = "\u00A7";
395 // Avoid buggy sign extensions in MSVC's constant evaluation mode (#2297).
396 using uchar
= unsigned char;
397 return FMT_UNICODE
|| (sizeof(section
) == 3 && uchar(section
[0]) == 0xC2 &&
398 uchar(section
[1]) == 0xA7);
400 } // namespace detail
403 An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
404 subset of the API. ``fmt::basic_string_view`` is used for format strings even
405 if ``std::string_view`` is available to prevent issues when a library is
406 compiled with a different ``-std`` option than the client code (which is not
410 template <typename Char
> class basic_string_view
{
416 using value_type
= Char
;
417 using iterator
= const Char
*;
419 constexpr basic_string_view() noexcept
: data_(nullptr), size_(0) {}
421 /** Constructs a string reference object from a C string and a size. */
422 constexpr basic_string_view(const Char
* s
, size_t count
) noexcept
423 : data_(s
), size_(count
) {}
427 Constructs a string reference object from a C string computing
428 the size with ``std::char_traits<Char>::length``.
431 FMT_CONSTEXPR_CHAR_TRAITS
433 basic_string_view(const Char
* s
)
435 size_(detail::const_check(std::is_same
<Char
, char>::value
&&
436 !detail::is_constant_evaluated(true))
437 ? std::strlen(reinterpret_cast<const char*>(s
))
438 : std::char_traits
<Char
>::length(s
)) {}
440 /** Constructs a string reference from a ``std::basic_string`` object. */
441 template <typename Traits
, typename Alloc
>
442 FMT_CONSTEXPR
basic_string_view(
443 const std::basic_string
<Char
, Traits
, Alloc
>& s
) noexcept
444 : data_(s
.data()), size_(s
.size()) {}
446 template <typename S
, FMT_ENABLE_IF(std::is_same
<
447 S
, detail::std_string_view
<Char
>>::value
)>
448 FMT_CONSTEXPR
basic_string_view(S s
) noexcept
449 : data_(s
.data()), size_(s
.size()) {}
451 /** Returns a pointer to the string data. */
452 constexpr auto data() const noexcept
-> const Char
* { return data_
; }
454 /** Returns the string size. */
455 constexpr auto size() const noexcept
-> size_t { return size_
; }
457 constexpr auto begin() const noexcept
-> iterator
{ return data_
; }
458 constexpr auto end() const noexcept
-> iterator
{ return data_
+ size_
; }
460 constexpr auto operator[](size_t pos
) const noexcept
-> const Char
& {
464 FMT_CONSTEXPR
void remove_prefix(size_t n
) noexcept
{
469 FMT_CONSTEXPR_CHAR_TRAITS
auto starts_with(
470 basic_string_view
<Char
> sv
) const noexcept
-> bool {
471 return size_
>= sv
.size_
&&
472 std::char_traits
<Char
>::compare(data_
, sv
.data_
, sv
.size_
) == 0;
474 FMT_CONSTEXPR_CHAR_TRAITS
auto starts_with(Char c
) const noexcept
-> bool {
475 return size_
>= 1 && std::char_traits
<Char
>::eq(*data_
, c
);
477 FMT_CONSTEXPR_CHAR_TRAITS
auto starts_with(const Char
* s
) const -> bool {
478 return starts_with(basic_string_view
<Char
>(s
));
481 // Lexicographically compare this string reference to other.
482 FMT_CONSTEXPR_CHAR_TRAITS
auto compare(basic_string_view other
) const -> int {
483 size_t str_size
= size_
< other
.size_
? size_
: other
.size_
;
484 int result
= std::char_traits
<Char
>::compare(data_
, other
.data_
, str_size
);
486 result
= size_
== other
.size_
? 0 : (size_
< other
.size_
? -1 : 1);
490 FMT_CONSTEXPR_CHAR_TRAITS
friend auto operator==(basic_string_view lhs
,
491 basic_string_view rhs
)
493 return lhs
.compare(rhs
) == 0;
495 friend auto operator!=(basic_string_view lhs
, basic_string_view rhs
) -> bool {
496 return lhs
.compare(rhs
) != 0;
498 friend auto operator<(basic_string_view lhs
, basic_string_view rhs
) -> bool {
499 return lhs
.compare(rhs
) < 0;
501 friend auto operator<=(basic_string_view lhs
, basic_string_view rhs
) -> bool {
502 return lhs
.compare(rhs
) <= 0;
504 friend auto operator>(basic_string_view lhs
, basic_string_view rhs
) -> bool {
505 return lhs
.compare(rhs
) > 0;
507 friend auto operator>=(basic_string_view lhs
, basic_string_view rhs
) -> bool {
508 return lhs
.compare(rhs
) >= 0;
513 using string_view
= basic_string_view
<char>;
515 /** Specifies if ``T`` is a character type. Can be specialized by users. */
517 template <typename T
> struct is_char
: std::false_type
{};
518 template <> struct is_char
<char> : std::true_type
{};
522 // A base class for compile-time strings.
523 struct compile_string
{};
525 template <typename S
>
526 struct is_compile_string
: std::is_base_of
<compile_string
, S
> {};
528 template <typename Char
, FMT_ENABLE_IF(is_char
<Char
>::value
)>
529 FMT_INLINE
auto to_string_view(const Char
* s
) -> basic_string_view
<Char
> {
532 template <typename Char
, typename Traits
, typename Alloc
>
533 inline auto to_string_view(const std::basic_string
<Char
, Traits
, Alloc
>& s
)
534 -> basic_string_view
<Char
> {
537 template <typename Char
>
538 constexpr auto to_string_view(basic_string_view
<Char
> s
)
539 -> basic_string_view
<Char
> {
542 template <typename Char
,
543 FMT_ENABLE_IF(!std::is_empty
<std_string_view
<Char
>>::value
)>
544 inline auto to_string_view(std_string_view
<Char
> s
) -> basic_string_view
<Char
> {
547 template <typename S
, FMT_ENABLE_IF(is_compile_string
<S
>::value
)>
548 constexpr auto to_string_view(const S
& s
)
549 -> basic_string_view
<typename
S::char_type
> {
550 return basic_string_view
<typename
S::char_type
>(s
);
552 void to_string_view(...);
554 // Specifies whether S is a string type convertible to fmt::basic_string_view.
555 // It should be a constexpr function but MSVC 2017 fails to compile it in
556 // enable_if and MSVC 2015 fails to compile it as an alias template.
557 // ADL is intentionally disabled as to_string_view is not an extension point.
558 template <typename S
>
560 : std::is_class
<decltype(detail::to_string_view(std::declval
<S
>()))> {};
562 template <typename S
, typename
= void> struct char_t_impl
{};
563 template <typename S
> struct char_t_impl
<S
, enable_if_t
<is_string
<S
>::value
>> {
564 using result
= decltype(to_string_view(std::declval
<S
>()));
565 using type
= typename
result::value_type
;
570 // Integer types should go first,
579 last_integer_type
= char_type
,
580 // followed by floating-point types.
584 last_numeric_type
= long_double_type
,
591 // Maps core type T to the corresponding type enum constant.
592 template <typename T
, typename Char
>
593 struct type_constant
: std::integral_constant
<type
, type::custom_type
> {};
595 #define FMT_TYPE_CONSTANT(Type, constant) \
596 template <typename Char> \
597 struct type_constant<Type, Char> \
598 : std::integral_constant<type, type::constant> {}
600 FMT_TYPE_CONSTANT(int, int_type
);
601 FMT_TYPE_CONSTANT(unsigned, uint_type
);
602 FMT_TYPE_CONSTANT(long long, long_long_type
);
603 FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type
);
604 FMT_TYPE_CONSTANT(int128_opt
, int128_type
);
605 FMT_TYPE_CONSTANT(uint128_opt
, uint128_type
);
606 FMT_TYPE_CONSTANT(bool, bool_type
);
607 FMT_TYPE_CONSTANT(Char
, char_type
);
608 FMT_TYPE_CONSTANT(float, float_type
);
609 FMT_TYPE_CONSTANT(double, double_type
);
610 FMT_TYPE_CONSTANT(long double, long_double_type
);
611 FMT_TYPE_CONSTANT(const Char
*, cstring_type
);
612 FMT_TYPE_CONSTANT(basic_string_view
<Char
>, string_type
);
613 FMT_TYPE_CONSTANT(const void*, pointer_type
);
615 constexpr auto is_integral_type(type t
) -> bool {
616 return t
> type::none_type
&& t
<= type::last_integer_type
;
618 constexpr auto is_arithmetic_type(type t
) -> bool {
619 return t
> type::none_type
&& t
<= type::last_numeric_type
;
622 constexpr auto set(type rhs
) -> int { return 1 << static_cast<int>(rhs
); }
623 constexpr auto in(type t
, int set
) -> bool {
624 return ((set
>> static_cast<int>(t
)) & 1) != 0;
630 set(type::int_type
) | set(type::long_long_type
) | set(type::int128_type
),
631 uint_set
= set(type::uint_type
) | set(type::ulong_long_type
) |
632 set(type::uint128_type
),
633 bool_set
= set(type::bool_type
),
634 char_set
= set(type::char_type
),
635 float_set
= set(type::float_type
) | set(type::double_type
) |
636 set(type::long_double_type
),
637 string_set
= set(type::string_type
),
638 cstring_set
= set(type::cstring_type
),
639 pointer_set
= set(type::pointer_type
)
643 FMT_NORETURN FMT_API
void throw_format_error(const char* message
);
645 struct error_handler
{
646 constexpr error_handler() = default;
648 // This function is intentionally not constexpr to give a compile-time error.
649 FMT_NORETURN
void on_error(const char* message
) {
650 throw_format_error(message
);
653 } // namespace detail
655 /** Throws ``format_error`` with a given message. */
656 using detail::throw_format_error
;
658 /** String's character type. */
659 template <typename S
> using char_t
= typename
detail::char_t_impl
<S
>::type
;
663 Parsing context consisting of a format string range being parsed and an
664 argument counter for automatic indexing.
665 You can use the ``format_parse_context`` type alias for ``char`` instead.
669 template <typename Char
> class basic_format_parse_context
{
671 basic_string_view
<Char
> format_str_
;
674 FMT_CONSTEXPR
void do_check_arg_id(int id
);
677 using char_type
= Char
;
678 using iterator
= const Char
*;
680 explicit constexpr basic_format_parse_context(
681 basic_string_view
<Char
> format_str
, int next_arg_id
= 0)
682 : format_str_(format_str
), next_arg_id_(next_arg_id
) {}
685 Returns an iterator to the beginning of the format string range being
688 constexpr auto begin() const noexcept
-> iterator
{
689 return format_str_
.begin();
693 Returns an iterator past the end of the format string range being parsed.
695 constexpr auto end() const noexcept
-> iterator
{ return format_str_
.end(); }
697 /** Advances the begin iterator to ``it``. */
698 FMT_CONSTEXPR
void advance_to(iterator it
) {
699 format_str_
.remove_prefix(detail::to_unsigned(it
- begin()));
703 Reports an error if using the manual argument indexing; otherwise returns
704 the next argument index and switches to the automatic indexing.
706 FMT_CONSTEXPR
auto next_arg_id() -> int {
707 if (next_arg_id_
< 0) {
708 detail::throw_format_error(
709 "cannot switch from manual to automatic argument indexing");
712 int id
= next_arg_id_
++;
718 Reports an error if using the automatic argument indexing; otherwise
719 switches to the manual indexing.
721 FMT_CONSTEXPR
void check_arg_id(int id
) {
722 if (next_arg_id_
> 0) {
723 detail::throw_format_error(
724 "cannot switch from automatic to manual argument indexing");
730 FMT_CONSTEXPR
void check_arg_id(basic_string_view
<Char
>) {}
731 FMT_CONSTEXPR
void check_dynamic_spec(int arg_id
);
735 using format_parse_context
= basic_format_parse_context
<char>;
738 // A parse context with extra data used only in compile-time checks.
739 template <typename Char
>
740 class compile_parse_context
: public basic_format_parse_context
<Char
> {
744 using base
= basic_format_parse_context
<Char
>;
747 explicit FMT_CONSTEXPR
compile_parse_context(
748 basic_string_view
<Char
> format_str
, int num_args
, const type
* types
,
750 : base(format_str
, next_arg_id
), num_args_(num_args
), types_(types
) {}
752 constexpr auto num_args() const -> int { return num_args_
; }
753 constexpr auto arg_type(int id
) const -> type
{ return types_
[id
]; }
755 FMT_CONSTEXPR
auto next_arg_id() -> int {
756 int id
= base::next_arg_id();
757 if (id
>= num_args_
) throw_format_error("argument not found");
761 FMT_CONSTEXPR
void check_arg_id(int id
) {
762 base::check_arg_id(id
);
763 if (id
>= num_args_
) throw_format_error("argument not found");
765 using base::check_arg_id
;
767 FMT_CONSTEXPR
void check_dynamic_spec(int arg_id
) {
768 detail::ignore_unused(arg_id
);
769 #if !defined(__LCC__)
770 if (arg_id
< num_args_
&& types_
&& !is_integral_type(types_
[arg_id
]))
771 throw_format_error("width/precision is not integer");
776 // Extracts a reference to the container from back_insert_iterator.
777 template <typename Container
>
778 inline auto get_container(std::back_insert_iterator
<Container
> it
)
780 using base
= std::back_insert_iterator
<Container
>;
781 struct accessor
: base
{
782 accessor(base b
) : base(b
) {}
783 using base::container
;
785 return *accessor(it
).container
;
788 template <typename Char
, typename InputIt
, typename OutputIt
>
789 FMT_CONSTEXPR
auto copy_str(InputIt begin
, InputIt end
, OutputIt out
)
791 while (begin
!= end
) *out
++ = static_cast<Char
>(*begin
++);
795 template <typename Char
, typename T
, typename U
,
797 std::is_same
<remove_const_t
<T
>, U
>::value
&& is_char
<U
>::value
)>
798 FMT_CONSTEXPR
auto copy_str(T
* begin
, T
* end
, U
* out
) -> U
* {
799 if (is_constant_evaluated()) return copy_str
<Char
, T
*, U
*>(begin
, end
, out
);
800 auto size
= to_unsigned(end
- begin
);
801 if (size
> 0) memcpy(out
, begin
, size
* sizeof(U
));
807 A contiguous memory buffer with an optional growing ability. It is an internal
808 class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`.
811 template <typename T
> class buffer
{
818 // Don't initialize ptr_ since it is not accessed to save a few cycles.
819 FMT_MSC_WARNING(suppress
: 26495)
820 FMT_CONSTEXPR
buffer(size_t sz
) noexcept
: size_(sz
), capacity_(sz
) {}
822 FMT_CONSTEXPR20
buffer(T
* p
= nullptr, size_t sz
= 0, size_t cap
= 0) noexcept
823 : ptr_(p
), size_(sz
), capacity_(cap
) {}
825 FMT_CONSTEXPR20
~buffer() = default;
826 buffer(buffer
&&) = default;
828 /** Sets the buffer data and capacity. */
829 FMT_CONSTEXPR
void set(T
* buf_data
, size_t buf_capacity
) noexcept
{
831 capacity_
= buf_capacity
;
834 /** Increases the buffer capacity to hold at least *capacity* elements. */
836 virtual FMT_CONSTEXPR20
void grow(size_t capacity
) = 0;
839 using value_type
= T
;
840 using const_reference
= const T
&;
842 buffer(const buffer
&) = delete;
843 void operator=(const buffer
&) = delete;
845 FMT_INLINE
auto begin() noexcept
-> T
* { return ptr_
; }
846 FMT_INLINE
auto end() noexcept
-> T
* { return ptr_
+ size_
; }
848 FMT_INLINE
auto begin() const noexcept
-> const T
* { return ptr_
; }
849 FMT_INLINE
auto end() const noexcept
-> const T
* { return ptr_
+ size_
; }
851 /** Returns the size of this buffer. */
852 constexpr auto size() const noexcept
-> size_t { return size_
; }
854 /** Returns the capacity of this buffer. */
855 constexpr auto capacity() const noexcept
-> size_t { return capacity_
; }
857 /** Returns a pointer to the buffer data (not null-terminated). */
858 FMT_CONSTEXPR
auto data() noexcept
-> T
* { return ptr_
; }
859 FMT_CONSTEXPR
auto data() const noexcept
-> const T
* { return ptr_
; }
861 /** Clears this buffer. */
862 void clear() { size_
= 0; }
864 // Tries resizing the buffer to contain *count* elements. If T is a POD type
865 // the new elements may not be initialized.
866 FMT_CONSTEXPR20
void try_resize(size_t count
) {
868 size_
= count
<= capacity_
? count
: capacity_
;
871 // Tries increasing the buffer capacity to *new_capacity*. It can increase the
872 // capacity by a smaller amount than requested but guarantees there is space
873 // for at least one additional element either by increasing the capacity or by
874 // flushing the buffer if it is full.
875 FMT_CONSTEXPR20
void try_reserve(size_t new_capacity
) {
876 if (new_capacity
> capacity_
) grow(new_capacity
);
879 FMT_CONSTEXPR20
void push_back(const T
& value
) {
880 try_reserve(size_
+ 1);
881 ptr_
[size_
++] = value
;
884 /** Appends data to the end of the buffer. */
885 template <typename U
> void append(const U
* begin
, const U
* end
);
887 template <typename Idx
> FMT_CONSTEXPR
auto operator[](Idx index
) -> T
& {
890 template <typename Idx
>
891 FMT_CONSTEXPR
auto operator[](Idx index
) const -> const T
& {
896 struct buffer_traits
{
897 explicit buffer_traits(size_t) {}
898 auto count() const -> size_t { return 0; }
899 auto limit(size_t size
) -> size_t { return size
; }
902 class fixed_buffer_traits
{
908 explicit fixed_buffer_traits(size_t limit
) : limit_(limit
) {}
909 auto count() const -> size_t { return count_
; }
910 auto limit(size_t size
) -> size_t {
911 size_t n
= limit_
> count_
? limit_
- count_
: 0;
913 return size
< n
? size
: n
;
917 // A buffer that writes to an output iterator when flushed.
918 template <typename OutputIt
, typename T
, typename Traits
= buffer_traits
>
919 class iterator_buffer final
: public Traits
, public buffer
<T
> {
922 enum { buffer_size
= 256 };
923 T data_
[buffer_size
];
926 FMT_CONSTEXPR20
void grow(size_t) override
{
927 if (this->size() == buffer_size
) flush();
931 auto size
= this->size();
933 out_
= copy_str
<T
>(data_
, data_
+ this->limit(size
), out_
);
937 explicit iterator_buffer(OutputIt out
, size_t n
= buffer_size
)
938 : Traits(n
), buffer
<T
>(data_
, 0, buffer_size
), out_(out
) {}
939 iterator_buffer(iterator_buffer
&& other
)
940 : Traits(other
), buffer
<T
>(data_
, 0, buffer_size
), out_(other
.out_
) {}
941 ~iterator_buffer() { flush(); }
943 auto out() -> OutputIt
{
947 auto count() const -> size_t { return Traits::count() + this->size(); }
950 template <typename T
>
951 class iterator_buffer
<T
*, T
, fixed_buffer_traits
> final
952 : public fixed_buffer_traits
,
956 enum { buffer_size
= 256 };
957 T data_
[buffer_size
];
960 FMT_CONSTEXPR20
void grow(size_t) override
{
961 if (this->size() == this->capacity()) flush();
965 size_t n
= this->limit(this->size());
966 if (this->data() == out_
) {
968 this->set(data_
, buffer_size
);
974 explicit iterator_buffer(T
* out
, size_t n
= buffer_size
)
975 : fixed_buffer_traits(n
), buffer
<T
>(out
, 0, n
), out_(out
) {}
976 iterator_buffer(iterator_buffer
&& other
)
977 : fixed_buffer_traits(other
),
978 buffer
<T
>(std::move(other
)),
980 if (this->data() != out_
) {
981 this->set(data_
, buffer_size
);
985 ~iterator_buffer() { flush(); }
991 auto count() const -> size_t {
992 return fixed_buffer_traits::count() + this->size();
996 template <typename T
> class iterator_buffer
<T
*, T
> final
: public buffer
<T
> {
998 FMT_CONSTEXPR20
void grow(size_t) override
{}
1001 explicit iterator_buffer(T
* out
, size_t = 0) : buffer
<T
>(out
, 0, ~size_t()) {}
1003 auto out() -> T
* { return &*this->end(); }
1006 // A buffer that writes to a container with the contiguous storage.
1007 template <typename Container
>
1008 class iterator_buffer
<std::back_insert_iterator
<Container
>,
1009 enable_if_t
<is_contiguous
<Container
>::value
,
1010 typename
Container::value_type
>>
1011 final
: public buffer
<typename
Container::value_type
> {
1013 Container
& container_
;
1016 FMT_CONSTEXPR20
void grow(size_t capacity
) override
{
1017 container_
.resize(capacity
);
1018 this->set(&container_
[0], capacity
);
1022 explicit iterator_buffer(Container
& c
)
1023 : buffer
<typename
Container::value_type
>(c
.size()), container_(c
) {}
1024 explicit iterator_buffer(std::back_insert_iterator
<Container
> out
, size_t = 0)
1025 : iterator_buffer(get_container(out
)) {}
1027 auto out() -> std::back_insert_iterator
<Container
> {
1028 return std::back_inserter(container_
);
1032 // A buffer that counts the number of code units written discarding the output.
1033 template <typename T
= char> class counting_buffer final
: public buffer
<T
> {
1035 enum { buffer_size
= 256 };
1036 T data_
[buffer_size
];
1040 FMT_CONSTEXPR20
void grow(size_t) override
{
1041 if (this->size() != buffer_size
) return;
1042 count_
+= this->size();
1047 counting_buffer() : buffer
<T
>(data_
, 0, buffer_size
) {}
1049 auto count() -> size_t { return count_
+ this->size(); }
1051 } // namespace detail
1053 template <typename Char
>
1054 FMT_CONSTEXPR
void basic_format_parse_context
<Char
>::do_check_arg_id(int id
) {
1055 // Argument id is only checked at compile-time during parsing because
1056 // formatting has its own validation.
1057 if (detail::is_constant_evaluated() &&
1058 (!FMT_GCC_VERSION
|| FMT_GCC_VERSION
>= 1200)) {
1059 using context
= detail::compile_parse_context
<Char
>;
1060 if (id
>= static_cast<context
*>(this)->num_args())
1061 detail::throw_format_error("argument not found");
1065 template <typename Char
>
1066 FMT_CONSTEXPR
void basic_format_parse_context
<Char
>::check_dynamic_spec(
1068 if (detail::is_constant_evaluated() &&
1069 (!FMT_GCC_VERSION
|| FMT_GCC_VERSION
>= 1200)) {
1070 using context
= detail::compile_parse_context
<Char
>;
1071 static_cast<context
*>(this)->check_dynamic_spec(arg_id
);
1075 FMT_EXPORT
template <typename Context
> class basic_format_arg
;
1076 FMT_EXPORT
template <typename Context
> class basic_format_args
;
1077 FMT_EXPORT
template <typename Context
> class dynamic_format_arg_store
;
1079 // A formatter for objects of type T.
1081 template <typename T
, typename Char
= char, typename Enable
= void>
1083 // A deleted default constructor indicates a disabled formatter.
1084 formatter() = delete;
1087 // Specifies if T has an enabled formatter specialization. A type can be
1088 // formattable even if it doesn't have a formatter e.g. via a conversion.
1089 template <typename T
, typename Context
>
1090 using has_formatter
=
1091 std::is_constructible
<typename
Context::template formatter_type
<T
>>;
1093 // An output iterator that appends to a buffer.
1094 // It is used to reduce symbol sizes for the common case.
1095 class appender
: public std::back_insert_iterator
<detail::buffer
<char>> {
1096 using base
= std::back_insert_iterator
<detail::buffer
<char>>;
1099 using std::back_insert_iterator
<detail::buffer
<char>>::back_insert_iterator
;
1100 appender(base it
) noexcept
: base(it
) {}
1101 FMT_UNCHECKED_ITERATOR(appender
);
1103 auto operator++() noexcept
-> appender
& { return *this; }
1104 auto operator++(int) noexcept
-> appender
{ return *this; }
1109 template <typename Context
, typename T
>
1110 constexpr auto has_const_formatter_impl(T
*)
1111 -> decltype(typename
Context::template formatter_type
<T
>().format(
1112 std::declval
<const T
&>(), std::declval
<Context
&>()),
1116 template <typename Context
>
1117 constexpr auto has_const_formatter_impl(...) -> bool {
1120 template <typename T
, typename Context
>
1121 constexpr auto has_const_formatter() -> bool {
1122 return has_const_formatter_impl
<Context
>(static_cast<T
*>(nullptr));
1125 template <typename T
>
1126 using buffer_appender
= conditional_t
<std::is_same
<T
, char>::value
, appender
,
1127 std::back_insert_iterator
<buffer
<T
>>>;
1129 // Maps an output iterator to a buffer.
1130 template <typename T
, typename OutputIt
>
1131 auto get_buffer(OutputIt out
) -> iterator_buffer
<OutputIt
, T
> {
1132 return iterator_buffer
<OutputIt
, T
>(out
);
1134 template <typename T
, typename Buf
,
1135 FMT_ENABLE_IF(std::is_base_of
<buffer
<char>, Buf
>::value
)>
1136 auto get_buffer(std::back_insert_iterator
<Buf
> out
) -> buffer
<char>& {
1137 return get_container(out
);
1140 template <typename Buf
, typename OutputIt
>
1141 FMT_INLINE
auto get_iterator(Buf
& buf
, OutputIt
) -> decltype(buf
.out()) {
1144 template <typename T
, typename OutputIt
>
1145 auto get_iterator(buffer
<T
>&, OutputIt out
) -> OutputIt
{
1151 template <typename Char
, typename T
> struct named_arg
: view
{
1154 named_arg(const Char
* n
, const T
& v
) : name(n
), value(v
) {}
1157 template <typename Char
> struct named_arg_info
{
1162 template <typename T
, typename Char
, size_t NUM_ARGS
, size_t NUM_NAMED_ARGS
>
1164 // args_[0].named_args points to named_args_ to avoid bloating format_args.
1165 // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
1166 T args_
[1 + (NUM_ARGS
!= 0 ? NUM_ARGS
: +1)];
1167 named_arg_info
<Char
> named_args_
[NUM_NAMED_ARGS
];
1169 template <typename
... U
>
1170 arg_data(const U
&... init
) : args_
{T(named_args_
, NUM_NAMED_ARGS
), init
...} {}
1171 arg_data(const arg_data
& other
) = delete;
1172 auto args() const -> const T
* { return args_
+ 1; }
1173 auto named_args() -> named_arg_info
<Char
>* { return named_args_
; }
1176 template <typename T
, typename Char
, size_t NUM_ARGS
>
1177 struct arg_data
<T
, Char
, NUM_ARGS
, 0> {
1178 // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
1179 T args_
[NUM_ARGS
!= 0 ? NUM_ARGS
: +1];
1181 template <typename
... U
>
1182 FMT_CONSTEXPR FMT_INLINE
arg_data(const U
&... init
) : args_
{init
...} {}
1183 FMT_CONSTEXPR FMT_INLINE
auto args() const -> const T
* { return args_
; }
1184 FMT_CONSTEXPR FMT_INLINE
auto named_args() -> std::nullptr_t
{
1189 template <typename Char
>
1190 inline void init_named_args(named_arg_info
<Char
>*, int, int) {}
1192 template <typename T
> struct is_named_arg
: std::false_type
{};
1193 template <typename T
> struct is_statically_named_arg
: std::false_type
{};
1195 template <typename T
, typename Char
>
1196 struct is_named_arg
<named_arg
<Char
, T
>> : std::true_type
{};
1198 template <typename Char
, typename T
, typename
... Tail
,
1199 FMT_ENABLE_IF(!is_named_arg
<T
>::value
)>
1200 void init_named_args(named_arg_info
<Char
>* named_args
, int arg_count
,
1201 int named_arg_count
, const T
&, const Tail
&... args
) {
1202 init_named_args(named_args
, arg_count
+ 1, named_arg_count
, args
...);
1205 template <typename Char
, typename T
, typename
... Tail
,
1206 FMT_ENABLE_IF(is_named_arg
<T
>::value
)>
1207 void init_named_args(named_arg_info
<Char
>* named_args
, int arg_count
,
1208 int named_arg_count
, const T
& arg
, const Tail
&... args
) {
1209 named_args
[named_arg_count
++] = {arg
.name
, arg_count
};
1210 init_named_args(named_args
, arg_count
+ 1, named_arg_count
, args
...);
1213 template <typename
... Args
>
1214 FMT_CONSTEXPR FMT_INLINE
void init_named_args(std::nullptr_t
, int, int,
1217 template <bool B
= false> constexpr auto count() -> size_t { return B
? 1 : 0; }
1218 template <bool B1
, bool B2
, bool... Tail
> constexpr auto count() -> size_t {
1219 return (B1
? 1 : 0) + count
<B2
, Tail
...>();
1222 template <typename
... Args
> constexpr auto count_named_args() -> size_t {
1223 return count
<is_named_arg
<Args
>::value
...>();
1226 template <typename
... Args
>
1227 constexpr auto count_statically_named_args() -> size_t {
1228 return count
<is_statically_named_arg
<Args
>::value
...>();
1231 struct unformattable
{};
1232 struct unformattable_char
: unformattable
{};
1233 struct unformattable_pointer
: unformattable
{};
1235 template <typename Char
> struct string_value
{
1240 template <typename Char
> struct named_arg_value
{
1241 const named_arg_info
<Char
>* data
;
1245 template <typename Context
> struct custom_value
{
1246 using parse_context
= typename
Context::parse_context_type
;
1248 void (*format
)(void* arg
, parse_context
& parse_ctx
, Context
& ctx
);
1251 // A formatting argument value.
1252 template <typename Context
> class value
{
1254 using char_type
= typename
Context::char_type
;
1259 unsigned uint_value
;
1260 long long long_long_value
;
1261 unsigned long long ulong_long_value
;
1262 int128_opt int128_value
;
1263 uint128_opt uint128_value
;
1265 char_type char_value
;
1267 double double_value
;
1268 long double long_double_value
;
1269 const void* pointer
;
1270 string_value
<char_type
> string
;
1271 custom_value
<Context
> custom
;
1272 named_arg_value
<char_type
> named_args
;
1275 constexpr FMT_INLINE
value() : no_value() {}
1276 constexpr FMT_INLINE
value(int val
) : int_value(val
) {}
1277 constexpr FMT_INLINE
value(unsigned val
) : uint_value(val
) {}
1278 constexpr FMT_INLINE
value(long long val
) : long_long_value(val
) {}
1279 constexpr FMT_INLINE
value(unsigned long long val
) : ulong_long_value(val
) {}
1280 FMT_INLINE
value(int128_opt val
) : int128_value(val
) {}
1281 FMT_INLINE
value(uint128_opt val
) : uint128_value(val
) {}
1282 constexpr FMT_INLINE
value(float val
) : float_value(val
) {}
1283 constexpr FMT_INLINE
value(double val
) : double_value(val
) {}
1284 FMT_INLINE
value(long double val
) : long_double_value(val
) {}
1285 constexpr FMT_INLINE
value(bool val
) : bool_value(val
) {}
1286 constexpr FMT_INLINE
value(char_type val
) : char_value(val
) {}
1287 FMT_CONSTEXPR FMT_INLINE
value(const char_type
* val
) {
1289 if (is_constant_evaluated()) string
.size
= {};
1291 FMT_CONSTEXPR FMT_INLINE
value(basic_string_view
<char_type
> val
) {
1292 string
.data
= val
.data();
1293 string
.size
= val
.size();
1295 FMT_INLINE
value(const void* val
) : pointer(val
) {}
1296 FMT_INLINE
value(const named_arg_info
<char_type
>* args
, size_t size
)
1297 : named_args
{args
, size
} {}
1299 template <typename T
> FMT_CONSTEXPR20 FMT_INLINE
value(T
& val
) {
1300 using value_type
= remove_const_t
<T
>;
1301 custom
.value
= const_cast<value_type
*>(std::addressof(val
));
1302 // Get the formatter type through the context to allow different contexts
1303 // have different extension points, e.g. `formatter<T>` for `format` and
1304 // `printf_formatter<T>` for `printf`.
1305 custom
.format
= format_custom_arg
<
1306 value_type
, typename
Context::template formatter_type
<value_type
>>;
1308 value(unformattable
);
1309 value(unformattable_char
);
1310 value(unformattable_pointer
);
1313 // Formats an argument of a custom type, such as a user-defined class.
1314 template <typename T
, typename Formatter
>
1315 static void format_custom_arg(void* arg
,
1316 typename
Context::parse_context_type
& parse_ctx
,
1318 auto f
= Formatter();
1319 parse_ctx
.advance_to(f
.parse(parse_ctx
));
1320 using qualified_type
=
1321 conditional_t
<has_const_formatter
<T
, Context
>(), const T
, T
>;
1322 // Calling format through a mutable reference is deprecated.
1323 ctx
.advance_to(f
.format(*static_cast<qualified_type
*>(arg
), ctx
));
1327 // To minimize the number of types we need to deal with, long is translated
1328 // either to int or to long long depending on its size.
1329 enum { long_short
= sizeof(long) == sizeof(int) };
1330 using long_type
= conditional_t
<long_short
, int, long long>;
1331 using ulong_type
= conditional_t
<long_short
, unsigned, unsigned long long>;
1333 template <typename T
> struct format_as_result
{
1334 template <typename U
,
1335 FMT_ENABLE_IF(std::is_enum
<U
>::value
|| std::is_class
<U
>::value
)>
1336 static auto map(U
*) -> remove_cvref_t
<decltype(format_as(std::declval
<U
>()))>;
1337 static auto map(...) -> void;
1339 using type
= decltype(map(static_cast<T
*>(nullptr)));
1341 template <typename T
> using format_as_t
= typename format_as_result
<T
>::type
;
1343 template <typename T
>
1344 struct has_format_as
1345 : bool_constant
<!std::is_same
<format_as_t
<T
>, void>::value
> {};
1347 // Maps formatting arguments to core types.
1348 // arg_mapper reports errors by returning unformattable instead of using
1349 // static_assert because it's used in the is_formattable trait.
1350 template <typename Context
> struct arg_mapper
{
1351 using char_type
= typename
Context::char_type
;
1353 FMT_CONSTEXPR FMT_INLINE
auto map(signed char val
) -> int { return val
; }
1354 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned char val
) -> unsigned {
1357 FMT_CONSTEXPR FMT_INLINE
auto map(short val
) -> int { return val
; }
1358 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned short val
) -> unsigned {
1361 FMT_CONSTEXPR FMT_INLINE
auto map(int val
) -> int { return val
; }
1362 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned val
) -> unsigned { return val
; }
1363 FMT_CONSTEXPR FMT_INLINE
auto map(long val
) -> long_type
{ return val
; }
1364 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned long val
) -> ulong_type
{
1367 FMT_CONSTEXPR FMT_INLINE
auto map(long long val
) -> long long { return val
; }
1368 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned long long val
)
1369 -> unsigned long long {
1372 FMT_CONSTEXPR FMT_INLINE
auto map(int128_opt val
) -> int128_opt
{
1375 FMT_CONSTEXPR FMT_INLINE
auto map(uint128_opt val
) -> uint128_opt
{
1378 FMT_CONSTEXPR FMT_INLINE
auto map(bool val
) -> bool { return val
; }
1380 template <typename T
, FMT_ENABLE_IF(std::is_same
<T
, char>::value
||
1381 std::is_same
<T
, char_type
>::value
)>
1382 FMT_CONSTEXPR FMT_INLINE
auto map(T val
) -> char_type
{
1385 template <typename T
, enable_if_t
<(std::is_same
<T
, wchar_t>::value
||
1386 #ifdef __cpp_char8_t
1387 std::is_same
<T
, char8_t
>::value
||
1389 std::is_same
<T
, char16_t
>::value
||
1390 std::is_same
<T
, char32_t
>::value
) &&
1391 !std::is_same
<T
, char_type
>::value
,
1393 FMT_CONSTEXPR FMT_INLINE
auto map(T
) -> unformattable_char
{
1397 FMT_CONSTEXPR FMT_INLINE
auto map(float val
) -> float { return val
; }
1398 FMT_CONSTEXPR FMT_INLINE
auto map(double val
) -> double { return val
; }
1399 FMT_CONSTEXPR FMT_INLINE
auto map(long double val
) -> long double {
1403 FMT_CONSTEXPR FMT_INLINE
auto map(char_type
* val
) -> const char_type
* {
1406 FMT_CONSTEXPR FMT_INLINE
auto map(const char_type
* val
) -> const char_type
* {
1409 template <typename T
,
1410 FMT_ENABLE_IF(is_string
<T
>::value
&& !std::is_pointer
<T
>::value
&&
1411 std::is_same
<char_type
, char_t
<T
>>::value
)>
1412 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& val
)
1413 -> basic_string_view
<char_type
> {
1414 return to_string_view(val
);
1416 template <typename T
,
1417 FMT_ENABLE_IF(is_string
<T
>::value
&& !std::is_pointer
<T
>::value
&&
1418 !std::is_same
<char_type
, char_t
<T
>>::value
)>
1419 FMT_CONSTEXPR FMT_INLINE
auto map(const T
&) -> unformattable_char
{
1423 FMT_CONSTEXPR FMT_INLINE
auto map(void* val
) -> const void* { return val
; }
1424 FMT_CONSTEXPR FMT_INLINE
auto map(const void* val
) -> const void* {
1427 FMT_CONSTEXPR FMT_INLINE
auto map(std::nullptr_t val
) -> const void* {
1431 // Use SFINAE instead of a const T* parameter to avoid a conflict with the
1436 std::is_pointer
<T
>::value
|| std::is_member_pointer
<T
>::value
||
1437 std::is_function
<typename
std::remove_pointer
<T
>::type
>::value
||
1438 (std::is_array
<T
>::value
&&
1439 !std::is_convertible
<T
, const char_type
*>::value
))>
1440 FMT_CONSTEXPR
auto map(const T
&) -> unformattable_pointer
{
1444 template <typename T
, std::size_t N
,
1445 FMT_ENABLE_IF(!std::is_same
<T
, wchar_t>::value
)>
1446 FMT_CONSTEXPR FMT_INLINE
auto map(const T (&values
)[N
]) -> const T (&)[N
] {
1450 // Only map owning types because mapping views can be unsafe.
1451 template <typename T
, typename U
= format_as_t
<T
>,
1452 FMT_ENABLE_IF(std::is_arithmetic
<U
>::value
)>
1453 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& val
)
1454 -> decltype(FMT_DECLTYPE_THIS
map(U())) {
1455 return map(format_as(val
));
1458 template <typename T
, typename U
= remove_const_t
<T
>>
1459 struct formattable
: bool_constant
<has_const_formatter
<U
, Context
>() ||
1460 (has_formatter
<U
, Context
>::value
&&
1461 !std::is_const
<T
>::value
)> {};
1463 template <typename T
, FMT_ENABLE_IF(formattable
<T
>::value
)>
1464 FMT_CONSTEXPR FMT_INLINE
auto do_map(T
& val
) -> T
& {
1467 template <typename T
, FMT_ENABLE_IF(!formattable
<T
>::value
)>
1468 FMT_CONSTEXPR FMT_INLINE
auto do_map(T
&) -> unformattable
{
1472 template <typename T
, typename U
= remove_const_t
<T
>,
1473 FMT_ENABLE_IF((std::is_class
<U
>::value
|| std::is_enum
<U
>::value
||
1474 std::is_union
<U
>::value
) &&
1475 !is_string
<U
>::value
&& !is_char
<U
>::value
&&
1476 !is_named_arg
<U
>::value
&&
1477 !std::is_arithmetic
<format_as_t
<U
>>::value
)>
1478 FMT_CONSTEXPR FMT_INLINE
auto map(T
& val
)
1479 -> decltype(FMT_DECLTYPE_THIS
do_map(val
)) {
1483 template <typename T
, FMT_ENABLE_IF(is_named_arg
<T
>::value
)>
1484 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& named_arg
)
1485 -> decltype(FMT_DECLTYPE_THIS
map(named_arg
.value
)) {
1486 return map(named_arg
.value
);
1489 auto map(...) -> unformattable
{ return {}; }
1492 // A type constant after applying arg_mapper<Context>.
1493 template <typename T
, typename Context
>
1494 using mapped_type_constant
=
1495 type_constant
<decltype(arg_mapper
<Context
>().map(std::declval
<const T
&>())),
1496 typename
Context::char_type
>;
1498 enum { packed_arg_bits
= 4 };
1499 // Maximum number of arguments with packed types.
1500 enum { max_packed_args
= 62 / packed_arg_bits
};
1501 enum : unsigned long long { is_unpacked_bit
= 1ULL << 63 };
1502 enum : unsigned long long { has_named_args_bit
= 1ULL << 62 };
1504 template <typename Char
, typename InputIt
>
1505 auto copy_str(InputIt begin
, InputIt end
, appender out
) -> appender
{
1506 get_container(out
).append(begin
, end
);
1509 template <typename Char
, typename InputIt
>
1510 auto copy_str(InputIt begin
, InputIt end
,
1511 std::back_insert_iterator
<std::string
> out
)
1512 -> std::back_insert_iterator
<std::string
> {
1513 get_container(out
).append(begin
, end
);
1517 template <typename Char
, typename R
, typename OutputIt
>
1518 FMT_CONSTEXPR
auto copy_str(R
&& rng
, OutputIt out
) -> OutputIt
{
1519 return detail::copy_str
<Char
>(rng
.begin(), rng
.end(), out
);
1522 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
1523 // A workaround for gcc 4.8 to make void_t work in a SFINAE context.
1524 template <typename
...> struct void_t_impl
{
1527 template <typename
... T
> using void_t
= typename void_t_impl
<T
...>::type
;
1529 template <typename
...> using void_t
= void;
1532 template <typename It
, typename T
, typename Enable
= void>
1533 struct is_output_iterator
: std::false_type
{};
1535 template <typename It
, typename T
>
1536 struct is_output_iterator
<
1538 void_t
<typename
std::iterator_traits
<It
>::iterator_category
,
1539 decltype(*std::declval
<It
>() = std::declval
<T
>())>>
1540 : std::true_type
{};
1542 template <typename It
> struct is_back_insert_iterator
: std::false_type
{};
1543 template <typename Container
>
1544 struct is_back_insert_iterator
<std::back_insert_iterator
<Container
>>
1545 : std::true_type
{};
1547 // A type-erased reference to an std::locale to avoid a heavy <locale> include.
1550 const void* locale_
; // A type-erased pointer to std::locale.
1553 constexpr FMT_INLINE
locale_ref() : locale_(nullptr) {}
1554 template <typename Locale
> explicit locale_ref(const Locale
& loc
);
1556 explicit operator bool() const noexcept
{ return locale_
!= nullptr; }
1558 template <typename Locale
> auto get() const -> Locale
;
1561 template <typename
> constexpr auto encode_types() -> unsigned long long {
1565 template <typename Context
, typename Arg
, typename
... Args
>
1566 constexpr auto encode_types() -> unsigned long long {
1567 return static_cast<unsigned>(mapped_type_constant
<Arg
, Context
>::value
) |
1568 (encode_types
<Context
, Args
...>() << packed_arg_bits
);
1571 #if defined(__cpp_if_constexpr)
1572 // This type is intentionally undefined, only used for errors
1573 template <typename T
, typename Char
> struct type_is_unformattable_for
;
1576 template <bool PACKED
, typename Context
, typename T
, FMT_ENABLE_IF(PACKED
)>
1577 FMT_CONSTEXPR FMT_INLINE
auto make_arg(T
& val
) -> value
<Context
> {
1578 using arg_type
= remove_cvref_t
<decltype(arg_mapper
<Context
>().map(val
))>;
1580 constexpr bool formattable_char
=
1581 !std::is_same
<arg_type
, unformattable_char
>::value
;
1582 static_assert(formattable_char
, "Mixing character types is disallowed.");
1584 // Formatting of arbitrary pointers is disallowed. If you want to format a
1585 // pointer cast it to `void*` or `const void*`. In particular, this forbids
1586 // formatting of `[const] volatile char*` printed as bool by iostreams.
1587 constexpr bool formattable_pointer
=
1588 !std::is_same
<arg_type
, unformattable_pointer
>::value
;
1589 static_assert(formattable_pointer
,
1590 "Formatting of non-void pointers is disallowed.");
1592 constexpr bool formattable
= !std::is_same
<arg_type
, unformattable
>::value
;
1593 #if defined(__cpp_if_constexpr)
1594 if constexpr (!formattable
) {
1595 type_is_unformattable_for
<T
, typename
Context::char_type
> _
;
1600 "Cannot format an argument. To make type T formattable provide a "
1601 "formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
1602 return {arg_mapper
<Context
>().map(val
)};
1605 template <typename Context
, typename T
>
1606 FMT_CONSTEXPR
auto make_arg(T
& val
) -> basic_format_arg
<Context
> {
1607 auto arg
= basic_format_arg
<Context
>();
1608 arg
.type_
= mapped_type_constant
<T
, Context
>::value
;
1609 arg
.value_
= make_arg
<true, Context
>(val
);
1613 template <bool PACKED
, typename Context
, typename T
, FMT_ENABLE_IF(!PACKED
)>
1614 FMT_CONSTEXPR
inline auto make_arg(T
& val
) -> basic_format_arg
<Context
> {
1615 return make_arg
<Context
>(val
);
1617 } // namespace detail
1620 // A formatting argument. Context is a template parameter for the compiled API
1621 // where output can be unbuffered.
1622 template <typename Context
> class basic_format_arg
{
1624 detail::value
<Context
> value_
;
1627 template <typename ContextType
, typename T
>
1628 friend FMT_CONSTEXPR
auto detail::make_arg(T
& value
)
1629 -> basic_format_arg
<ContextType
>;
1631 template <typename Visitor
, typename Ctx
>
1632 friend FMT_CONSTEXPR
auto visit_format_arg(Visitor
&& vis
,
1633 const basic_format_arg
<Ctx
>& arg
)
1634 -> decltype(vis(0));
1636 friend class basic_format_args
<Context
>;
1637 friend class dynamic_format_arg_store
<Context
>;
1639 using char_type
= typename
Context::char_type
;
1641 template <typename T
, typename Char
, size_t NUM_ARGS
, size_t NUM_NAMED_ARGS
>
1642 friend struct detail::arg_data
;
1644 basic_format_arg(const detail::named_arg_info
<char_type
>* args
, size_t size
)
1645 : value_(args
, size
) {}
1650 explicit handle(detail::custom_value
<Context
> custom
) : custom_(custom
) {}
1652 void format(typename
Context::parse_context_type
& parse_ctx
,
1653 Context
& ctx
) const {
1654 custom_
.format(custom_
.value
, parse_ctx
, ctx
);
1658 detail::custom_value
<Context
> custom_
;
1661 constexpr basic_format_arg() : type_(detail::type::none_type
) {}
1663 constexpr explicit operator bool() const noexcept
{
1664 return type_
!= detail::type::none_type
;
1667 auto type() const -> detail::type
{ return type_
; }
1669 auto is_integral() const -> bool { return detail::is_integral_type(type_
); }
1670 auto is_arithmetic() const -> bool {
1671 return detail::is_arithmetic_type(type_
);
1674 FMT_INLINE
auto format_custom(const char_type
* parse_begin
,
1675 typename
Context::parse_context_type
& parse_ctx
,
1676 Context
& ctx
) -> bool {
1677 if (type_
!= detail::type::custom_type
) return false;
1678 parse_ctx
.advance_to(parse_begin
);
1679 value_
.custom
.format(value_
.custom
.value
, parse_ctx
, ctx
);
1686 Visits an argument dispatching to the appropriate visit method based on
1687 the argument type. For example, if the argument type is ``double`` then
1688 ``vis(value)`` will be called with the value of type ``double``.
1692 template <typename Visitor
, typename Context
>
1693 FMT_CONSTEXPR FMT_INLINE
auto visit_format_arg(
1694 Visitor
&& vis
, const basic_format_arg
<Context
>& arg
) -> decltype(vis(0)) {
1695 switch (arg
.type_
) {
1696 case detail::type::none_type
:
1698 case detail::type::int_type
:
1699 return vis(arg
.value_
.int_value
);
1700 case detail::type::uint_type
:
1701 return vis(arg
.value_
.uint_value
);
1702 case detail::type::long_long_type
:
1703 return vis(arg
.value_
.long_long_value
);
1704 case detail::type::ulong_long_type
:
1705 return vis(arg
.value_
.ulong_long_value
);
1706 case detail::type::int128_type
:
1707 return vis(detail::convert_for_visit(arg
.value_
.int128_value
));
1708 case detail::type::uint128_type
:
1709 return vis(detail::convert_for_visit(arg
.value_
.uint128_value
));
1710 case detail::type::bool_type
:
1711 return vis(arg
.value_
.bool_value
);
1712 case detail::type::char_type
:
1713 return vis(arg
.value_
.char_value
);
1714 case detail::type::float_type
:
1715 return vis(arg
.value_
.float_value
);
1716 case detail::type::double_type
:
1717 return vis(arg
.value_
.double_value
);
1718 case detail::type::long_double_type
:
1719 return vis(arg
.value_
.long_double_value
);
1720 case detail::type::cstring_type
:
1721 return vis(arg
.value_
.string
.data
);
1722 case detail::type::string_type
:
1723 using sv
= basic_string_view
<typename
Context::char_type
>;
1724 return vis(sv(arg
.value_
.string
.data
, arg
.value_
.string
.size
));
1725 case detail::type::pointer_type
:
1726 return vis(arg
.value_
.pointer
);
1727 case detail::type::custom_type
:
1728 return vis(typename basic_format_arg
<Context
>::handle(arg
.value_
.custom
));
1730 return vis(monostate());
1733 // Formatting context.
1734 template <typename OutputIt
, typename Char
> class basic_format_context
{
1737 basic_format_args
<basic_format_context
> args_
;
1738 detail::locale_ref loc_
;
1741 using iterator
= OutputIt
;
1742 using format_arg
= basic_format_arg
<basic_format_context
>;
1743 using format_args
= basic_format_args
<basic_format_context
>;
1744 using parse_context_type
= basic_format_parse_context
<Char
>;
1745 template <typename T
> using formatter_type
= formatter
<T
, Char
>;
1747 /** The character type for the output. */
1748 using char_type
= Char
;
1750 basic_format_context(basic_format_context
&&) = default;
1751 basic_format_context(const basic_format_context
&) = delete;
1752 void operator=(const basic_format_context
&) = delete;
1754 Constructs a ``basic_format_context`` object. References to the arguments
1755 are stored in the object so make sure they have appropriate lifetimes.
1757 constexpr basic_format_context(OutputIt out
, format_args ctx_args
,
1758 detail::locale_ref loc
= {})
1759 : out_(out
), args_(ctx_args
), loc_(loc
) {}
1761 constexpr auto arg(int id
) const -> format_arg
{ return args_
.get(id
); }
1762 FMT_CONSTEXPR
auto arg(basic_string_view
<Char
> name
) -> format_arg
{
1763 return args_
.get(name
);
1765 FMT_CONSTEXPR
auto arg_id(basic_string_view
<Char
> name
) -> int {
1766 return args_
.get_id(name
);
1768 auto args() const -> const format_args
& { return args_
; }
1771 FMT_CONSTEXPR
auto error_handler() -> detail::error_handler
{ return {}; }
1772 void on_error(const char* message
) { error_handler().on_error(message
); }
1774 // Returns an iterator to the beginning of the output range.
1775 FMT_CONSTEXPR
auto out() -> iterator
{ return out_
; }
1777 // Advances the begin iterator to ``it``.
1778 void advance_to(iterator it
) {
1779 if (!detail::is_back_insert_iterator
<iterator
>()) out_
= it
;
1782 FMT_CONSTEXPR
auto locale() -> detail::locale_ref
{ return loc_
; }
1785 template <typename Char
>
1786 using buffer_context
=
1787 basic_format_context
<detail::buffer_appender
<Char
>, Char
>;
1788 using format_context
= buffer_context
<char>;
1790 template <typename T
, typename Char
= char>
1791 using is_formattable
= bool_constant
<!std::is_base_of
<
1792 detail::unformattable
, decltype(detail::arg_mapper
<buffer_context
<Char
>>()
1793 .map(std::declval
<T
&>()))>::value
>;
1797 An array of references to arguments. It can be implicitly converted into
1798 `~fmt::basic_format_args` for passing into type-erased formatting functions
1799 such as `~fmt::vformat`.
1802 template <typename Context
, typename
... Args
>
1803 class format_arg_store
1804 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1805 // Workaround a GCC template argument substitution bug.
1806 : public basic_format_args
<Context
>
1810 static const size_t num_args
= sizeof...(Args
);
1811 static constexpr size_t num_named_args
= detail::count_named_args
<Args
...>();
1812 static const bool is_packed
= num_args
<= detail::max_packed_args
;
1814 using value_type
= conditional_t
<is_packed
, detail::value
<Context
>,
1815 basic_format_arg
<Context
>>;
1817 detail::arg_data
<value_type
, typename
Context::char_type
, num_args
,
1821 friend class basic_format_args
<Context
>;
1823 static constexpr unsigned long long desc
=
1824 (is_packed
? detail::encode_types
<Context
, Args
...>()
1825 : detail::is_unpacked_bit
| num_args
) |
1826 (num_named_args
!= 0
1827 ? static_cast<unsigned long long>(detail::has_named_args_bit
)
1831 template <typename
... T
>
1832 FMT_CONSTEXPR FMT_INLINE
format_arg_store(T
&... args
)
1834 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1835 basic_format_args
<Context
>(*this),
1837 data_
{detail::make_arg
<is_packed
, Context
>(args
)...} {
1838 if (detail::const_check(num_named_args
!= 0))
1839 detail::init_named_args(data_
.named_args(), 0, 0, args
...);
1845 Constructs a `~fmt::format_arg_store` object that contains references to
1846 arguments and can be implicitly converted to `~fmt::format_args`. `Context`
1847 can be omitted in which case it defaults to `~fmt::format_context`.
1848 See `~fmt::arg` for lifetime considerations.
1851 // Arguments are taken by lvalue references to avoid some lifetime issues.
1852 template <typename Context
= format_context
, typename
... T
>
1853 constexpr auto make_format_args(T
&... args
)
1854 -> format_arg_store
<Context
, remove_cvref_t
<T
>...> {
1860 Returns a named argument to be used in a formatting function.
1861 It should only be used in a call to a formatting function or
1862 `dynamic_format_arg_store::push_back`.
1866 fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
1869 template <typename Char
, typename T
>
1870 inline auto arg(const Char
* name
, const T
& arg
) -> detail::named_arg
<Char
, T
> {
1871 static_assert(!detail::is_named_arg
<T
>(), "nested named arguments");
1878 A view of a collection of formatting arguments. To avoid lifetime issues it
1879 should only be used as a parameter type in type-erased functions such as
1882 void vlog(string_view format_str, format_args args); // OK
1883 format_args args = make_format_args(); // Error: dangling reference
1886 template <typename Context
> class basic_format_args
{
1888 using size_type
= int;
1889 using format_arg
= basic_format_arg
<Context
>;
1892 // A descriptor that contains information about formatting arguments.
1893 // If the number of arguments is less or equal to max_packed_args then
1894 // argument types are passed in the descriptor. This reduces binary code size
1895 // per formatting function call.
1896 unsigned long long desc_
;
1898 // If is_packed() returns true then argument values are stored in values_;
1899 // otherwise they are stored in args_. This is done to improve cache
1900 // locality and reduce compiled code size since storing larger objects
1901 // may require more code (at least on x86-64) even if the same amount of
1902 // data is actually copied to stack. It saves ~10% on the bloat test.
1903 const detail::value
<Context
>* values_
;
1904 const format_arg
* args_
;
1907 constexpr auto is_packed() const -> bool {
1908 return (desc_
& detail::is_unpacked_bit
) == 0;
1910 auto has_named_args() const -> bool {
1911 return (desc_
& detail::has_named_args_bit
) != 0;
1914 FMT_CONSTEXPR
auto type(int index
) const -> detail::type
{
1915 int shift
= index
* detail::packed_arg_bits
;
1916 unsigned int mask
= (1 << detail::packed_arg_bits
) - 1;
1917 return static_cast<detail::type
>((desc_
>> shift
) & mask
);
1920 constexpr FMT_INLINE
basic_format_args(unsigned long long desc
,
1921 const detail::value
<Context
>* values
)
1922 : desc_(desc
), values_(values
) {}
1923 constexpr basic_format_args(unsigned long long desc
, const format_arg
* args
)
1924 : desc_(desc
), args_(args
) {}
1927 constexpr basic_format_args() : desc_(0), args_(nullptr) {}
1931 Constructs a `basic_format_args` object from `~fmt::format_arg_store`.
1934 template <typename
... Args
>
1935 constexpr FMT_INLINE
basic_format_args(
1936 const format_arg_store
<Context
, Args
...>& store
)
1937 : basic_format_args(format_arg_store
<Context
, Args
...>::desc
,
1938 store
.data_
.args()) {}
1942 Constructs a `basic_format_args` object from
1943 `~fmt::dynamic_format_arg_store`.
1946 constexpr FMT_INLINE
basic_format_args(
1947 const dynamic_format_arg_store
<Context
>& store
)
1948 : basic_format_args(store
.get_types(), store
.data()) {}
1952 Constructs a `basic_format_args` object from a dynamic set of arguments.
1955 constexpr basic_format_args(const format_arg
* args
, int count
)
1956 : basic_format_args(detail::is_unpacked_bit
| detail::to_unsigned(count
),
1959 /** Returns the argument with the specified id. */
1960 FMT_CONSTEXPR
auto get(int id
) const -> format_arg
{
1963 if (id
< max_size()) arg
= args_
[id
];
1966 if (id
>= detail::max_packed_args
) return arg
;
1967 arg
.type_
= type(id
);
1968 if (arg
.type_
== detail::type::none_type
) return arg
;
1969 arg
.value_
= values_
[id
];
1973 template <typename Char
>
1974 auto get(basic_string_view
<Char
> name
) const -> format_arg
{
1975 int id
= get_id(name
);
1976 return id
>= 0 ? get(id
) : format_arg();
1979 template <typename Char
>
1980 auto get_id(basic_string_view
<Char
> name
) const -> int {
1981 if (!has_named_args()) return -1;
1982 const auto& named_args
=
1983 (is_packed() ? values_
[-1] : args_
[-1].value_
).named_args
;
1984 for (size_t i
= 0; i
< named_args
.size
; ++i
) {
1985 if (named_args
.data
[i
].name
== name
) return named_args
.data
[i
].id
;
1990 auto max_size() const -> int {
1991 unsigned long long max_packed
= detail::max_packed_args
;
1992 return static_cast<int>(is_packed() ? max_packed
1993 : desc_
& ~detail::is_unpacked_bit
);
1997 /** An alias to ``basic_format_args<format_context>``. */
1998 // A separate type would result in shorter symbols but break ABI compatibility
1999 // between clang and gcc on ARM (#1919).
2000 FMT_EXPORT
using format_args
= basic_format_args
<format_context
>;
2002 // We cannot use enum classes as bit fields because of a gcc bug, so we put them
2003 // in namespaces instead (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414).
2004 // Additionally, if an underlying type is specified, older gcc incorrectly warns
2005 // that the type is too small. Both bugs are fixed in gcc 9.3.
2006 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 903
2007 # define FMT_ENUM_UNDERLYING_TYPE(type)
2009 # define FMT_ENUM_UNDERLYING_TYPE(type) : type
2012 enum type
FMT_ENUM_UNDERLYING_TYPE(unsigned char){none
, left
, right
, center
,
2015 using align_t
= align::type
;
2017 enum type
FMT_ENUM_UNDERLYING_TYPE(unsigned char){none
, minus
, plus
, space
};
2019 using sign_t
= sign::type
;
2023 // Workaround an array initialization issue in gcc 4.8.
2024 template <typename Char
> struct fill_t
{
2026 enum { max_size
= 4 };
2027 Char data_
[max_size
] = {Char(' '), Char(0), Char(0), Char(0)};
2028 unsigned char size_
= 1;
2031 FMT_CONSTEXPR
void operator=(basic_string_view
<Char
> s
) {
2032 auto size
= s
.size();
2033 FMT_ASSERT(size
<= max_size
, "invalid fill");
2034 for (size_t i
= 0; i
< size
; ++i
) data_
[i
] = s
[i
];
2035 size_
= static_cast<unsigned char>(size
);
2038 constexpr auto size() const -> size_t { return size_
; }
2039 constexpr auto data() const -> const Char
* { return data_
; }
2041 FMT_CONSTEXPR
auto operator[](size_t index
) -> Char
& { return data_
[index
]; }
2042 FMT_CONSTEXPR
auto operator[](size_t index
) const -> const Char
& {
2043 return data_
[index
];
2046 } // namespace detail
2048 enum class presentation_type
: unsigned char {
2056 hexfloat_lower
, // 'a'
2057 hexfloat_upper
, // 'A'
2062 general_lower
, // 'g'
2063 general_upper
, // 'G'
2070 // Format specifiers for built-in and string types.
2071 template <typename Char
= char> struct format_specs
{
2074 presentation_type type
;
2077 bool alt
: 1; // Alternate form ('#').
2079 detail::fill_t
<Char
> fill
;
2081 constexpr format_specs()
2084 type(presentation_type::none
),
2093 enum class arg_id_kind
{ none
, index
, name
};
2095 // An argument reference.
2096 template <typename Char
> struct arg_ref
{
2097 FMT_CONSTEXPR
arg_ref() : kind(arg_id_kind::none
), val() {}
2099 FMT_CONSTEXPR
explicit arg_ref(int index
)
2100 : kind(arg_id_kind::index
), val(index
) {}
2101 FMT_CONSTEXPR
explicit arg_ref(basic_string_view
<Char
> name
)
2102 : kind(arg_id_kind::name
), val(name
) {}
2104 FMT_CONSTEXPR
auto operator=(int idx
) -> arg_ref
& {
2105 kind
= arg_id_kind::index
;
2112 FMT_CONSTEXPR
value(int idx
= 0) : index(idx
) {}
2113 FMT_CONSTEXPR
value(basic_string_view
<Char
> n
) : name(n
) {}
2116 basic_string_view
<Char
> name
;
2120 // Format specifiers with width and precision resolved at formatting rather
2121 // than parsing time to allow reusing the same parsed specifiers with
2122 // different sets of arguments (precompilation of format strings).
2123 template <typename Char
= char>
2124 struct dynamic_format_specs
: format_specs
<Char
> {
2125 arg_ref
<Char
> width_ref
;
2126 arg_ref
<Char
> precision_ref
;
2129 // Converts a character to ASCII. Returns '\0' on conversion failure.
2130 template <typename Char
, FMT_ENABLE_IF(std::is_integral
<Char
>::value
)>
2131 constexpr auto to_ascii(Char c
) -> char {
2132 return c
<= 0xff ? static_cast<char>(c
) : '\0';
2134 template <typename Char
, FMT_ENABLE_IF(std::is_enum
<Char
>::value
)>
2135 constexpr auto to_ascii(Char c
) -> char {
2136 return c
<= 0xff ? static_cast<char>(c
) : '\0';
2139 // Returns the number of code units in a code point or 1 on error.
2140 template <typename Char
>
2141 FMT_CONSTEXPR
auto code_point_length(const Char
* begin
) -> int {
2142 if (const_check(sizeof(Char
) != 1)) return 1;
2143 auto c
= static_cast<unsigned char>(*begin
);
2144 return static_cast<int>((0x3a55000000000000ull
>> (2 * (c
>> 3))) & 0x3) + 1;
2147 // Return the result via the out param to workaround gcc bug 77539.
2148 template <bool IS_CONSTEXPR
, typename T
, typename Ptr
= const T
*>
2149 FMT_CONSTEXPR
auto find(Ptr first
, Ptr last
, T value
, Ptr
& out
) -> bool {
2150 for (out
= first
; out
!= last
; ++out
) {
2151 if (*out
== value
) return true;
2157 inline auto find
<false, char>(const char* first
, const char* last
, char value
,
2158 const char*& out
) -> bool {
2159 out
= static_cast<const char*>(
2160 std::memchr(first
, value
, to_unsigned(last
- first
)));
2161 return out
!= nullptr;
2164 // Parses the range [begin, end) as an unsigned integer. This function assumes
2165 // that the range is non-empty and the first character is a digit.
2166 template <typename Char
>
2167 FMT_CONSTEXPR
auto parse_nonnegative_int(const Char
*& begin
, const Char
* end
,
2168 int error_value
) noexcept
-> int {
2169 FMT_ASSERT(begin
!= end
&& '0' <= *begin
&& *begin
<= '9', "");
2170 unsigned value
= 0, prev
= 0;
2174 value
= value
* 10 + unsigned(*p
- '0');
2176 } while (p
!= end
&& '0' <= *p
&& *p
<= '9');
2177 auto num_digits
= p
- begin
;
2179 if (num_digits
<= std::numeric_limits
<int>::digits10
)
2180 return static_cast<int>(value
);
2181 // Check for overflow.
2182 const unsigned max
= to_unsigned((std::numeric_limits
<int>::max
)());
2183 return num_digits
== std::numeric_limits
<int>::digits10
+ 1 &&
2184 prev
* 10ull + unsigned(p
[-1] - '0') <= max
2185 ? static_cast<int>(value
)
2189 FMT_CONSTEXPR
inline auto parse_align(char c
) -> align_t
{
2194 return align::right
;
2196 return align::center
;
2201 template <typename Char
> constexpr auto is_name_start(Char c
) -> bool {
2202 return ('a' <= c
&& c
<= 'z') || ('A' <= c
&& c
<= 'Z') || c
== '_';
2205 template <typename Char
, typename Handler
>
2206 FMT_CONSTEXPR
auto do_parse_arg_id(const Char
* begin
, const Char
* end
,
2207 Handler
&& handler
) -> const Char
* {
2209 if (c
>= '0' && c
<= '9') {
2211 constexpr int max
= (std::numeric_limits
<int>::max
)();
2213 index
= parse_nonnegative_int(begin
, end
, max
);
2216 if (begin
== end
|| (*begin
!= '}' && *begin
!= ':'))
2217 throw_format_error("invalid format string");
2219 handler
.on_index(index
);
2222 if (!is_name_start(c
)) {
2223 throw_format_error("invalid format string");
2229 } while (it
!= end
&& (is_name_start(*it
) || ('0' <= *it
&& *it
<= '9')));
2230 handler
.on_name({begin
, to_unsigned(it
- begin
)});
2234 template <typename Char
, typename Handler
>
2235 FMT_CONSTEXPR FMT_INLINE
auto parse_arg_id(const Char
* begin
, const Char
* end
,
2236 Handler
&& handler
) -> const Char
* {
2237 FMT_ASSERT(begin
!= end
, "");
2239 if (c
!= '}' && c
!= ':') return do_parse_arg_id(begin
, end
, handler
);
2244 template <typename Char
> struct dynamic_spec_id_handler
{
2245 basic_format_parse_context
<Char
>& ctx
;
2248 FMT_CONSTEXPR
void on_auto() {
2249 int id
= ctx
.next_arg_id();
2250 ref
= arg_ref
<Char
>(id
);
2251 ctx
.check_dynamic_spec(id
);
2253 FMT_CONSTEXPR
void on_index(int id
) {
2254 ref
= arg_ref
<Char
>(id
);
2255 ctx
.check_arg_id(id
);
2256 ctx
.check_dynamic_spec(id
);
2258 FMT_CONSTEXPR
void on_name(basic_string_view
<Char
> id
) {
2259 ref
= arg_ref
<Char
>(id
);
2260 ctx
.check_arg_id(id
);
2264 // Parses [integer | "{" [arg_id] "}"].
2265 template <typename Char
>
2266 FMT_CONSTEXPR
auto parse_dynamic_spec(const Char
* begin
, const Char
* end
,
2267 int& value
, arg_ref
<Char
>& ref
,
2268 basic_format_parse_context
<Char
>& ctx
)
2270 FMT_ASSERT(begin
!= end
, "");
2271 if ('0' <= *begin
&& *begin
<= '9') {
2272 int val
= parse_nonnegative_int(begin
, end
, -1);
2276 throw_format_error("number is too big");
2277 } else if (*begin
== '{') {
2279 auto handler
= dynamic_spec_id_handler
<Char
>{ctx
, ref
};
2280 if (begin
!= end
) begin
= parse_arg_id(begin
, end
, handler
);
2281 if (begin
!= end
&& *begin
== '}') return ++begin
;
2282 throw_format_error("invalid format string");
2287 template <typename Char
>
2288 FMT_CONSTEXPR
auto parse_precision(const Char
* begin
, const Char
* end
,
2289 int& value
, arg_ref
<Char
>& ref
,
2290 basic_format_parse_context
<Char
>& ctx
)
2293 if (begin
== end
|| *begin
== '}') {
2294 throw_format_error("invalid precision");
2297 return parse_dynamic_spec(begin
, end
, value
, ref
, ctx
);
2300 enum class state
{ start
, align
, sign
, hash
, zero
, width
, precision
, locale
};
2302 // Parses standard format specifiers.
2303 template <typename Char
>
2304 FMT_CONSTEXPR FMT_INLINE
auto parse_format_specs(
2305 const Char
* begin
, const Char
* end
, dynamic_format_specs
<Char
>& specs
,
2306 basic_format_parse_context
<Char
>& ctx
, type arg_type
) -> const Char
* {
2308 if (end
- begin
> 1) {
2309 auto next
= to_ascii(begin
[1]);
2310 c
= parse_align(next
) == align::none
? to_ascii(*begin
) : '\0';
2312 if (begin
== end
) return begin
;
2313 c
= to_ascii(*begin
);
2317 state current_state
= state::start
;
2318 FMT_CONSTEXPR
void operator()(state s
, bool valid
= true) {
2319 if (current_state
>= s
|| !valid
)
2320 throw_format_error("invalid format specifier");
2325 using pres
= presentation_type
;
2326 constexpr auto integral_set
= sint_set
| uint_set
| bool_set
| char_set
;
2329 dynamic_format_specs
<Char
>& specs
;
2332 FMT_CONSTEXPR
auto operator()(pres pres_type
, int set
) -> const Char
* {
2333 if (!in(arg_type
, set
)) {
2334 if (arg_type
== type::none_type
) return begin
;
2335 throw_format_error("invalid format specifier");
2337 specs
.type
= pres_type
;
2340 } parse_presentation_type
{begin
, specs
, arg_type
};
2347 enter_state(state::align
);
2348 specs
.align
= parse_align(c
);
2354 if (arg_type
== type::none_type
) return begin
;
2355 enter_state(state::sign
, in(arg_type
, sint_set
| float_set
));
2358 specs
.sign
= sign::plus
;
2361 specs
.sign
= sign::minus
;
2364 specs
.sign
= sign::space
;
2370 if (arg_type
== type::none_type
) return begin
;
2371 enter_state(state::hash
, is_arithmetic_type(arg_type
));
2376 enter_state(state::zero
);
2377 if (!is_arithmetic_type(arg_type
)) {
2378 if (arg_type
== type::none_type
) return begin
;
2379 throw_format_error("format specifier requires numeric argument");
2381 if (specs
.align
== align::none
) {
2382 // Ignore 0 if align is specified for compatibility with std::format.
2383 specs
.align
= align::numeric
;
2384 specs
.fill
[0] = Char('0');
2398 enter_state(state::width
);
2399 begin
= parse_dynamic_spec(begin
, end
, specs
.width
, specs
.width_ref
, ctx
);
2402 if (arg_type
== type::none_type
) return begin
;
2403 enter_state(state::precision
,
2404 in(arg_type
, float_set
| string_set
| cstring_set
));
2405 begin
= parse_precision(begin
, end
, specs
.precision
, specs
.precision_ref
,
2409 if (arg_type
== type::none_type
) return begin
;
2410 enter_state(state::locale
, is_arithmetic_type(arg_type
));
2411 specs
.localized
= true;
2415 return parse_presentation_type(pres::dec
, integral_set
);
2417 return parse_presentation_type(pres::oct
, integral_set
);
2419 return parse_presentation_type(pres::hex_lower
, integral_set
);
2421 return parse_presentation_type(pres::hex_upper
, integral_set
);
2423 return parse_presentation_type(pres::bin_lower
, integral_set
);
2425 return parse_presentation_type(pres::bin_upper
, integral_set
);
2427 return parse_presentation_type(pres::hexfloat_lower
, float_set
);
2429 return parse_presentation_type(pres::hexfloat_upper
, float_set
);
2431 return parse_presentation_type(pres::exp_lower
, float_set
);
2433 return parse_presentation_type(pres::exp_upper
, float_set
);
2435 return parse_presentation_type(pres::fixed_lower
, float_set
);
2437 return parse_presentation_type(pres::fixed_upper
, float_set
);
2439 return parse_presentation_type(pres::general_lower
, float_set
);
2441 return parse_presentation_type(pres::general_upper
, float_set
);
2443 if (arg_type
== type::bool_type
)
2444 throw_format_error("invalid format specifier");
2445 return parse_presentation_type(pres::chr
, integral_set
);
2447 return parse_presentation_type(pres::string
,
2448 bool_set
| string_set
| cstring_set
);
2450 return parse_presentation_type(pres::pointer
, pointer_set
| cstring_set
);
2452 return parse_presentation_type(pres::debug
,
2453 char_set
| string_set
| cstring_set
);
2457 if (*begin
== '}') return begin
;
2458 // Parse fill and alignment.
2459 auto fill_end
= begin
+ code_point_length(begin
);
2460 if (end
- fill_end
<= 0) {
2461 throw_format_error("invalid format specifier");
2464 if (*begin
== '{') {
2465 throw_format_error("invalid fill character '{'");
2468 auto align
= parse_align(to_ascii(*fill_end
));
2469 enter_state(state::align
, align
!= align::none
);
2470 specs
.fill
= {begin
, to_unsigned(fill_end
- begin
)};
2471 specs
.align
= align
;
2472 begin
= fill_end
+ 1;
2475 if (begin
== end
) return begin
;
2476 c
= to_ascii(*begin
);
2480 template <typename Char
, typename Handler
>
2481 FMT_CONSTEXPR
auto parse_replacement_field(const Char
* begin
, const Char
* end
,
2482 Handler
&& handler
) -> const Char
* {
2487 FMT_CONSTEXPR
void on_auto() { arg_id
= handler
.on_arg_id(); }
2488 FMT_CONSTEXPR
void on_index(int id
) { arg_id
= handler
.on_arg_id(id
); }
2489 FMT_CONSTEXPR
void on_name(basic_string_view
<Char
> id
) {
2490 arg_id
= handler
.on_arg_id(id
);
2495 if (begin
== end
) return handler
.on_error("invalid format string"), end
;
2496 if (*begin
== '}') {
2497 handler
.on_replacement_field(handler
.on_arg_id(), begin
);
2498 } else if (*begin
== '{') {
2499 handler
.on_text(begin
, begin
+ 1);
2501 auto adapter
= id_adapter
{handler
, 0};
2502 begin
= parse_arg_id(begin
, end
, adapter
);
2503 Char c
= begin
!= end
? *begin
: Char();
2505 handler
.on_replacement_field(adapter
.arg_id
, begin
);
2506 } else if (c
== ':') {
2507 begin
= handler
.on_format_specs(adapter
.arg_id
, begin
+ 1, end
);
2508 if (begin
== end
|| *begin
!= '}')
2509 return handler
.on_error("unknown format specifier"), end
;
2511 return handler
.on_error("missing '}' in format string"), end
;
2517 template <bool IS_CONSTEXPR
, typename Char
, typename Handler
>
2518 FMT_CONSTEXPR FMT_INLINE
void parse_format_string(
2519 basic_string_view
<Char
> format_str
, Handler
&& handler
) {
2520 auto begin
= format_str
.data();
2521 auto end
= begin
+ format_str
.size();
2522 if (end
- begin
< 32) {
2523 // Use a simple loop instead of memchr for small strings.
2524 const Char
* p
= begin
;
2528 handler
.on_text(begin
, p
- 1);
2529 begin
= p
= parse_replacement_field(p
- 1, end
, handler
);
2530 } else if (c
== '}') {
2531 if (p
== end
|| *p
!= '}')
2532 return handler
.on_error("unmatched '}' in format string");
2533 handler
.on_text(begin
, p
);
2537 handler
.on_text(begin
, end
);
2541 FMT_CONSTEXPR
void operator()(const Char
* from
, const Char
* to
) {
2542 if (from
== to
) return;
2544 const Char
* p
= nullptr;
2545 if (!find
<IS_CONSTEXPR
>(from
, to
, Char('}'), p
))
2546 return handler_
.on_text(from
, to
);
2548 if (p
== to
|| *p
!= '}')
2549 return handler_
.on_error("unmatched '}' in format string");
2550 handler_
.on_text(from
, p
);
2555 } write
= {handler
};
2556 while (begin
!= end
) {
2557 // Doing two passes with memchr (one for '{' and another for '}') is up to
2558 // 2.5x faster than the naive one-pass implementation on big format strings.
2559 const Char
* p
= begin
;
2560 if (*begin
!= '{' && !find
<IS_CONSTEXPR
>(begin
+ 1, end
, Char('{'), p
))
2561 return write(begin
, end
);
2563 begin
= parse_replacement_field(p
, end
, handler
);
2567 template <typename T
, bool = is_named_arg
<T
>::value
> struct strip_named_arg
{
2570 template <typename T
> struct strip_named_arg
<T
, true> {
2571 using type
= remove_cvref_t
<decltype(T::value
)>;
2574 template <typename T
, typename ParseContext
>
2575 FMT_CONSTEXPR
auto parse_format_specs(ParseContext
& ctx
)
2576 -> decltype(ctx
.begin()) {
2577 using char_type
= typename
ParseContext::char_type
;
2578 using context
= buffer_context
<char_type
>;
2579 using mapped_type
= conditional_t
<
2580 mapped_type_constant
<T
, context
>::value
!= type::custom_type
,
2581 decltype(arg_mapper
<context
>().map(std::declval
<const T
&>())),
2582 typename strip_named_arg
<T
>::type
>;
2583 #if defined(__cpp_if_constexpr)
2584 if constexpr (std::is_default_constructible
<
2585 formatter
<mapped_type
, char_type
>>::value
) {
2586 return formatter
<mapped_type
, char_type
>().parse(ctx
);
2588 type_is_unformattable_for
<T
, char_type
> _
;
2592 return formatter
<mapped_type
, char_type
>().parse(ctx
);
2596 // Checks char specs and returns true iff the presentation type is char-like.
2597 template <typename Char
>
2598 FMT_CONSTEXPR
auto check_char_specs(const format_specs
<Char
>& specs
) -> bool {
2599 if (specs
.type
!= presentation_type::none
&&
2600 specs
.type
!= presentation_type::chr
&&
2601 specs
.type
!= presentation_type::debug
) {
2604 if (specs
.align
== align::numeric
|| specs
.sign
!= sign::none
|| specs
.alt
)
2605 throw_format_error("invalid format specifier for char");
2609 #if FMT_USE_NONTYPE_TEMPLATE_ARGS
2610 template <int N
, typename T
, typename
... Args
, typename Char
>
2611 constexpr auto get_arg_index_by_name(basic_string_view
<Char
> name
) -> int {
2612 if constexpr (is_statically_named_arg
<T
>()) {
2613 if (name
== T::name
) return N
;
2615 if constexpr (sizeof...(Args
) > 0)
2616 return get_arg_index_by_name
<N
+ 1, Args
...>(name
);
2617 (void)name
; // Workaround an MSVC bug about "unused" parameter.
2622 template <typename
... Args
, typename Char
>
2623 FMT_CONSTEXPR
auto get_arg_index_by_name(basic_string_view
<Char
> name
) -> int {
2624 #if FMT_USE_NONTYPE_TEMPLATE_ARGS
2625 if constexpr (sizeof...(Args
) > 0)
2626 return get_arg_index_by_name
<0, Args
...>(name
);
2632 template <typename Char
, typename
... Args
> class format_string_checker
{
2634 using parse_context_type
= compile_parse_context
<Char
>;
2635 static constexpr int num_args
= sizeof...(Args
);
2637 // Format specifier parsing function.
2638 // In the future basic_format_parse_context will replace compile_parse_context
2639 // here and will use is_constant_evaluated and downcasting to access the data
2640 // needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1.
2641 using parse_func
= const Char
* (*)(parse_context_type
&);
2643 type types_
[num_args
> 0 ? static_cast<size_t>(num_args
) : 1];
2644 parse_context_type context_
;
2645 parse_func parse_funcs_
[num_args
> 0 ? static_cast<size_t>(num_args
) : 1];
2648 explicit FMT_CONSTEXPR
format_string_checker(basic_string_view
<Char
> fmt
)
2649 : types_
{mapped_type_constant
<Args
, buffer_context
<Char
>>::value
...},
2650 context_(fmt
, num_args
, types_
),
2651 parse_funcs_
{&parse_format_specs
<Args
, parse_context_type
>...} {}
2653 FMT_CONSTEXPR
void on_text(const Char
*, const Char
*) {}
2655 FMT_CONSTEXPR
auto on_arg_id() -> int { return context_
.next_arg_id(); }
2656 FMT_CONSTEXPR
auto on_arg_id(int id
) -> int {
2657 return context_
.check_arg_id(id
), id
;
2659 FMT_CONSTEXPR
auto on_arg_id(basic_string_view
<Char
> id
) -> int {
2660 #if FMT_USE_NONTYPE_TEMPLATE_ARGS
2661 auto index
= get_arg_index_by_name
<Args
...>(id
);
2662 if (index
< 0) on_error("named argument is not found");
2666 on_error("compile-time checks for named arguments require C++20 support");
2671 FMT_CONSTEXPR
void on_replacement_field(int id
, const Char
* begin
) {
2672 on_format_specs(id
, begin
, begin
); // Call parse() on empty specs.
2675 FMT_CONSTEXPR
auto on_format_specs(int id
, const Char
* begin
, const Char
*)
2677 context_
.advance_to(begin
);
2678 // id >= 0 check is a workaround for gcc 10 bug (#2065).
2679 return id
>= 0 && id
< num_args
? parse_funcs_
[id
](context_
) : begin
;
2682 FMT_CONSTEXPR
void on_error(const char* message
) {
2683 throw_format_error(message
);
2687 // Reports a compile-time error if S is not a valid format string.
2688 template <typename
..., typename S
, FMT_ENABLE_IF(!is_compile_string
<S
>::value
)>
2689 FMT_INLINE
void check_format_string(const S
&) {
2690 #ifdef FMT_ENFORCE_COMPILE_STRING
2691 static_assert(is_compile_string
<S
>::value
,
2692 "FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
2696 template <typename
... Args
, typename S
,
2697 FMT_ENABLE_IF(is_compile_string
<S
>::value
)>
2698 void check_format_string(S format_str
) {
2699 using char_t
= typename
S::char_type
;
2700 FMT_CONSTEXPR
auto s
= basic_string_view
<char_t
>(format_str
);
2701 using checker
= format_string_checker
<char_t
, remove_cvref_t
<Args
>...>;
2702 FMT_CONSTEXPR
bool error
= (parse_format_string
<true>(s
, checker(s
)), true);
2703 ignore_unused(error
);
2706 template <typename Char
= char> struct vformat_args
{
2707 using type
= basic_format_args
<
2708 basic_format_context
<std::back_insert_iterator
<buffer
<Char
>>, Char
>>;
2710 template <> struct vformat_args
<char> {
2711 using type
= format_args
;
2714 // Use vformat_args and avoid type_identity to keep symbols short.
2715 template <typename Char
>
2716 void vformat_to(buffer
<Char
>& buf
, basic_string_view
<Char
> fmt
,
2717 typename vformat_args
<Char
>::type args
, locale_ref loc
= {});
2719 FMT_API
void vprint_mojibake(std::FILE*, string_view
, format_args
);
2721 inline void vprint_mojibake(std::FILE*, string_view
, format_args
) {}
2723 } // namespace detail
2727 // A formatter specialization for natively supported types.
2728 template <typename T
, typename Char
>
2729 struct formatter
<T
, Char
,
2730 enable_if_t
<detail::type_constant
<T
, Char
>::value
!=
2731 detail::type::custom_type
>> {
2733 detail::dynamic_format_specs
<Char
> specs_
;
2736 template <typename ParseContext
>
2737 FMT_CONSTEXPR
auto parse(ParseContext
& ctx
) -> const Char
* {
2738 auto type
= detail::type_constant
<T
, Char
>::value
;
2740 detail::parse_format_specs(ctx
.begin(), ctx
.end(), specs_
, ctx
, type
);
2741 if (type
== detail::type::char_type
) detail::check_char_specs(specs_
);
2745 template <detail::type U
= detail::type_constant
<T
, Char
>::value
,
2746 FMT_ENABLE_IF(U
== detail::type::string_type
||
2747 U
== detail::type::cstring_type
||
2748 U
== detail::type::char_type
)>
2749 FMT_CONSTEXPR
void set_debug_format(bool set
= true) {
2750 specs_
.type
= set
? presentation_type::debug
: presentation_type::none
;
2753 template <typename FormatContext
>
2754 FMT_CONSTEXPR
auto format(const T
& val
, FormatContext
& ctx
) const
2755 -> decltype(ctx
.out());
2758 template <typename Char
= char> struct runtime_format_string
{
2759 basic_string_view
<Char
> str
;
2762 /** A compile-time format string. */
2763 template <typename Char
, typename
... Args
> class basic_format_string
{
2765 basic_string_view
<Char
> str_
;
2768 template <typename S
,
2770 std::is_convertible
<const S
&, basic_string_view
<Char
>>::value
)>
2771 FMT_CONSTEVAL FMT_INLINE
basic_format_string(const S
& s
) : str_(s
) {
2774 (std::is_base_of
<detail::view
, remove_reference_t
<Args
>>::value
&&
2775 std::is_reference
<Args
>::value
)...>() == 0,
2776 "passing views as lvalues is disallowed");
2777 #ifdef FMT_HAS_CONSTEVAL
2778 if constexpr (detail::count_named_args
<Args
...>() ==
2779 detail::count_statically_named_args
<Args
...>()) {
2781 detail::format_string_checker
<Char
, remove_cvref_t
<Args
>...>;
2782 detail::parse_format_string
<true>(str_
, checker(s
));
2785 detail::check_format_string
<Args
...>(s
);
2788 basic_format_string(runtime_format_string
<Char
> fmt
) : str_(fmt
.str
) {}
2790 FMT_INLINE
operator basic_string_view
<Char
>() const { return str_
; }
2791 FMT_INLINE
auto get() const -> basic_string_view
<Char
> { return str_
; }
2794 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
2795 // Workaround broken conversion on older gcc.
2796 template <typename
...> using format_string
= string_view
;
2797 inline auto runtime(string_view s
) -> string_view
{ return s
; }
2799 template <typename
... Args
>
2800 using format_string
= basic_format_string
<char, type_identity_t
<Args
>...>;
2803 Creates a runtime format string.
2807 // Check format string at runtime instead of compile-time.
2808 fmt::print(fmt::runtime("{:d}"), "I am not a number");
2811 inline auto runtime(string_view s
) -> runtime_format_string
<> { return {{s
}}; }
2814 FMT_API
auto vformat(string_view fmt
, format_args args
) -> std::string
;
2818 Formats ``args`` according to specifications in ``fmt`` and returns the result
2823 #include <fmt/core.h>
2824 std::string message = fmt::format("The answer is {}.", 42);
2827 template <typename
... T
>
2828 FMT_NODISCARD FMT_INLINE
auto format(format_string
<T
...> fmt
, T
&&... args
)
2830 return vformat(fmt
, fmt::make_format_args(args
...));
2833 /** Formats a string and writes the output to ``out``. */
2834 template <typename OutputIt
,
2835 FMT_ENABLE_IF(detail::is_output_iterator
<OutputIt
, char>::value
)>
2836 auto vformat_to(OutputIt out
, string_view fmt
, format_args args
) -> OutputIt
{
2837 auto&& buf
= detail::get_buffer
<char>(out
);
2838 detail::vformat_to(buf
, fmt
, args
, {});
2839 return detail::get_iterator(buf
, out
);
2844 Formats ``args`` according to specifications in ``fmt``, writes the result to
2845 the output iterator ``out`` and returns the iterator past the end of the output
2846 range. `format_to` does not append a terminating null character.
2850 auto out = std::vector<char>();
2851 fmt::format_to(std::back_inserter(out), "{}", 42);
2854 template <typename OutputIt
, typename
... T
,
2855 FMT_ENABLE_IF(detail::is_output_iterator
<OutputIt
, char>::value
)>
2856 FMT_INLINE
auto format_to(OutputIt out
, format_string
<T
...> fmt
, T
&&... args
)
2858 return vformat_to(out
, fmt
, fmt::make_format_args(args
...));
2861 template <typename OutputIt
> struct format_to_n_result
{
2862 /** Iterator past the end of the output range. */
2864 /** Total (not truncated) output size. */
2868 template <typename OutputIt
, typename
... T
,
2869 FMT_ENABLE_IF(detail::is_output_iterator
<OutputIt
, char>::value
)>
2870 auto vformat_to_n(OutputIt out
, size_t n
, string_view fmt
, format_args args
)
2871 -> format_to_n_result
<OutputIt
> {
2872 using traits
= detail::fixed_buffer_traits
;
2873 auto buf
= detail::iterator_buffer
<OutputIt
, char, traits
>(out
, n
);
2874 detail::vformat_to(buf
, fmt
, args
, {});
2875 return {buf
.out(), buf
.count()};
2880 Formats ``args`` according to specifications in ``fmt``, writes up to ``n``
2881 characters of the result to the output iterator ``out`` and returns the total
2882 (not truncated) output size and the iterator past the end of the output range.
2883 `format_to_n` does not append a terminating null character.
2886 template <typename OutputIt
, typename
... T
,
2887 FMT_ENABLE_IF(detail::is_output_iterator
<OutputIt
, char>::value
)>
2888 FMT_INLINE
auto format_to_n(OutputIt out
, size_t n
, format_string
<T
...> fmt
,
2889 T
&&... args
) -> format_to_n_result
<OutputIt
> {
2890 return vformat_to_n(out
, n
, fmt
, fmt::make_format_args(args
...));
2893 /** Returns the number of chars in the output of ``format(fmt, args...)``. */
2894 template <typename
... T
>
2895 FMT_NODISCARD FMT_INLINE
auto formatted_size(format_string
<T
...> fmt
,
2896 T
&&... args
) -> size_t {
2897 auto buf
= detail::counting_buffer
<>();
2898 detail::vformat_to
<char>(buf
, fmt
, fmt::make_format_args(args
...), {});
2902 FMT_API
void vprint(string_view fmt
, format_args args
);
2903 FMT_API
void vprint(std::FILE* f
, string_view fmt
, format_args args
);
2907 Formats ``args`` according to specifications in ``fmt`` and writes the output
2912 fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
2915 template <typename
... T
>
2916 FMT_INLINE
void print(format_string
<T
...> fmt
, T
&&... args
) {
2917 const auto& vargs
= fmt::make_format_args(args
...);
2918 return detail::is_utf8() ? vprint(fmt
, vargs
)
2919 : detail::vprint_mojibake(stdout
, fmt
, vargs
);
2924 Formats ``args`` according to specifications in ``fmt`` and writes the
2925 output to the file ``f``.
2929 fmt::print(stderr, "Don't {}!", "panic");
2932 template <typename
... T
>
2933 FMT_INLINE
void print(std::FILE* f
, format_string
<T
...> fmt
, T
&&... args
) {
2934 const auto& vargs
= fmt::make_format_args(args
...);
2935 return detail::is_utf8() ? vprint(f
, fmt
, vargs
)
2936 : detail::vprint_mojibake(f
, fmt
, vargs
);
2940 Formats ``args`` according to specifications in ``fmt`` and writes the
2941 output to the file ``f`` followed by a newline.
2943 template <typename
... T
>
2944 FMT_INLINE
void println(std::FILE* f
, format_string
<T
...> fmt
, T
&&... args
) {
2945 return fmt::print(f
, "{}\n", fmt::format(fmt
, std::forward
<T
>(args
)...));
2949 Formats ``args`` according to specifications in ``fmt`` and writes the output
2950 to ``stdout`` followed by a newline.
2952 template <typename
... T
>
2953 FMT_INLINE
void println(format_string
<T
...> fmt
, T
&&... args
) {
2954 return fmt::println(stdout
, fmt
, std::forward
<T
>(args
)...);
2958 FMT_GCC_PRAGMA("GCC pop_options")
2961 #ifdef FMT_HEADER_ONLY
2962 # include "format.h"
2964 #endif // FMT_CORE_H_