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
17 #include <type_traits>
19 // The fmt library version in the form major * 10000 + minor * 100 + patch.
20 #define FMT_VERSION 80101
22 #if defined(__clang__) && !defined(__ibmxl__)
23 # define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
25 # define FMT_CLANG_VERSION 0
28 #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && \
29 !defined(__NVCOMPILER)
30 # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
32 # define FMT_GCC_VERSION 0
35 #ifndef FMT_GCC_PRAGMA
36 // Workaround _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884.
37 # if FMT_GCC_VERSION >= 504
38 # define FMT_GCC_PRAGMA(arg) _Pragma(arg)
40 # define FMT_GCC_PRAGMA(arg)
45 # define FMT_ICC_VERSION __ICL
46 #elif defined(__INTEL_COMPILER)
47 # define FMT_ICC_VERSION __INTEL_COMPILER
49 # define FMT_ICC_VERSION 0
53 # define FMT_NVCC __NVCC__
59 # define FMT_MSC_VER _MSC_VER
60 # define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__))
62 # define FMT_MSC_VER 0
63 # define FMT_MSC_WARNING(...)
67 # define FMT_HAS_FEATURE(x) __has_feature(x)
69 # define FMT_HAS_FEATURE(x) 0
72 #if defined(__has_include) && \
73 (!defined(__INTELLISENSE__) || FMT_MSC_VER > 1900) && \
74 (!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600)
75 # define FMT_HAS_INCLUDE(x) __has_include(x)
77 # define FMT_HAS_INCLUDE(x) 0
80 #ifdef __has_cpp_attribute
81 # define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
83 # define FMT_HAS_CPP_ATTRIBUTE(x) 0
87 # define FMT_CPLUSPLUS _MSVC_LANG
89 # define FMT_CPLUSPLUS __cplusplus
92 #define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
93 (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
95 #define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
96 (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
98 // Check if relaxed C++14 constexpr is supported.
99 // GCC doesn't allow throw in constexpr until version 6 (bug 67371).
100 #ifndef FMT_USE_CONSTEXPR
101 # define FMT_USE_CONSTEXPR \
102 (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1912 || \
103 (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \
104 !FMT_NVCC && !FMT_ICC_VERSION
106 #if FMT_USE_CONSTEXPR
107 # define FMT_CONSTEXPR constexpr
108 # define FMT_CONSTEXPR_DECL constexpr
110 # define FMT_CONSTEXPR
111 # define FMT_CONSTEXPR_DECL
114 #if ((__cplusplus >= 202002L) && \
115 (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 9)) || \
116 (__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002)
117 # define FMT_CONSTEXPR20 constexpr
119 # define FMT_CONSTEXPR20
122 // Check if constexpr std::char_traits<>::compare,length is supported.
123 #if defined(__GLIBCXX__)
124 # if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \
125 _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE.
126 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr
128 #elif defined(_LIBCPP_VERSION) && __cplusplus >= 201703L && \
129 _LIBCPP_VERSION >= 4000
130 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr
131 #elif FMT_MSC_VER >= 1914 && _MSVC_LANG >= 201703L
132 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr
134 #ifndef FMT_CONSTEXPR_CHAR_TRAITS
135 # define FMT_CONSTEXPR_CHAR_TRAITS
138 // Check if exceptions are disabled.
139 #ifndef FMT_EXCEPTIONS
140 # if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
141 FMT_MSC_VER && !_HAS_EXCEPTIONS
142 # define FMT_EXCEPTIONS 0
144 # define FMT_EXCEPTIONS 1
148 // Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature).
149 #ifndef FMT_USE_NOEXCEPT
150 # define FMT_USE_NOEXCEPT 0
153 #if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
154 FMT_GCC_VERSION >= 408 || FMT_MSC_VER >= 1900
155 # define FMT_DETECTED_NOEXCEPT noexcept
156 # define FMT_HAS_CXX11_NOEXCEPT 1
158 # define FMT_DETECTED_NOEXCEPT throw()
159 # define FMT_HAS_CXX11_NOEXCEPT 0
163 # if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT
164 # define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT
166 # define FMT_NOEXCEPT
170 // [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code
172 #if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \
174 # define FMT_NORETURN [[noreturn]]
176 # define FMT_NORETURN
179 #if __cplusplus == 201103L || __cplusplus == 201402L
180 # if defined(__INTEL_COMPILER) || defined(__PGI)
181 # define FMT_FALLTHROUGH
182 # elif defined(__clang__)
183 # define FMT_FALLTHROUGH [[clang::fallthrough]]
184 # elif FMT_GCC_VERSION >= 700 && \
185 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
186 # define FMT_FALLTHROUGH [[gnu::fallthrough]]
188 # define FMT_FALLTHROUGH
190 #elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough)
191 # define FMT_FALLTHROUGH [[fallthrough]]
193 # define FMT_FALLTHROUGH
196 #ifndef FMT_NODISCARD
197 # if FMT_HAS_CPP17_ATTRIBUTE(nodiscard)
198 # define FMT_NODISCARD [[nodiscard]]
200 # define FMT_NODISCARD
204 #ifndef FMT_USE_FLOAT
205 # define FMT_USE_FLOAT 1
207 #ifndef FMT_USE_DOUBLE
208 # define FMT_USE_DOUBLE 1
210 #ifndef FMT_USE_LONG_DOUBLE
211 # define FMT_USE_LONG_DOUBLE 1
215 # if FMT_GCC_VERSION || FMT_CLANG_VERSION
216 # define FMT_INLINE inline __attribute__((always_inline))
218 # define FMT_INLINE inline
222 #ifndef FMT_DEPRECATED
223 # if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900
224 # define FMT_DEPRECATED [[deprecated]]
226 # if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
227 # define FMT_DEPRECATED __attribute__((deprecated))
229 # define FMT_DEPRECATED __declspec(deprecated)
231 # define FMT_DEPRECATED /* deprecated */
236 #ifndef FMT_BEGIN_NAMESPACE
237 # define FMT_BEGIN_NAMESPACE \
239 inline namespace v8 {
240 # define FMT_END_NAMESPACE \
245 #ifndef FMT_MODULE_EXPORT
246 # define FMT_MODULE_EXPORT
247 # define FMT_MODULE_EXPORT_BEGIN
248 # define FMT_MODULE_EXPORT_END
249 # define FMT_BEGIN_DETAIL_NAMESPACE namespace detail {
250 # define FMT_END_DETAIL_NAMESPACE }
253 #if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
254 # define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275)
256 # define FMT_API __declspec(dllexport)
257 # elif defined(FMT_SHARED)
258 # define FMT_API __declspec(dllimport)
261 # define FMT_CLASS_API
262 # if defined(FMT_EXPORT) || defined(FMT_SHARED)
263 # if defined(__GNUC__) || defined(__clang__)
264 # define FMT_API __attribute__((visibility("default")))
272 // libc++ supports string_view in pre-c++17.
273 #if (FMT_HAS_INCLUDE(<string_view>) && \
274 (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
275 (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
276 # include <string_view>
277 # define FMT_USE_STRING_VIEW
278 #elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L
279 # include <experimental/string_view>
280 # define FMT_USE_EXPERIMENTAL_STRING_VIEW
284 # define FMT_UNICODE !FMT_MSC_VER
287 #ifndef FMT_CONSTEVAL
288 # if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \
289 __cplusplus > 201703L && !defined(__apple_build_version__)) || \
290 (defined(__cpp_consteval) && \
291 (!FMT_MSC_VER || _MSC_FULL_VER >= 193030704))
292 // consteval is broken in MSVC before VS2022 and Apple clang 13.
293 # define FMT_CONSTEVAL consteval
294 # define FMT_HAS_CONSTEVAL
296 # define FMT_CONSTEVAL
300 #ifndef FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
301 # if defined(__cpp_nontype_template_args) && \
302 ((FMT_GCC_VERSION >= 903 && __cplusplus >= 201709L) || \
303 __cpp_nontype_template_args >= 201911L)
304 # define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 1
306 # define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0
310 // Enable minimal optimizations for more compact code in debug mode.
311 FMT_GCC_PRAGMA("GCC push_options")
313 FMT_GCC_PRAGMA("GCC optimize(\"Og\")")
317 FMT_MODULE_EXPORT_BEGIN
319 // Implementations of enable_if_t and other metafunctions for older systems.
320 template <bool B
, typename T
= void>
321 using enable_if_t
= typename
std::enable_if
<B
, T
>::type
;
322 template <bool B
, typename T
, typename F
>
323 using conditional_t
= typename
std::conditional
<B
, T
, F
>::type
;
324 template <bool B
> using bool_constant
= std::integral_constant
<bool, B
>;
325 template <typename T
>
326 using remove_reference_t
= typename
std::remove_reference
<T
>::type
;
327 template <typename T
>
328 using remove_const_t
= typename
std::remove_const
<T
>::type
;
329 template <typename T
>
330 using remove_cvref_t
= typename
std::remove_cv
<remove_reference_t
<T
>>::type
;
331 template <typename T
> struct type_identity
{ using type
= T
; };
332 template <typename T
> using type_identity_t
= typename type_identity
<T
>::type
;
335 constexpr monostate() {}
338 // An enable_if helper to be used in template parameters which results in much
339 // shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
340 // to workaround a bug in MSVC 2019 (see #1140 and #1186).
342 # define FMT_ENABLE_IF(...)
344 # define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0
347 FMT_BEGIN_DETAIL_NAMESPACE
349 // Suppress "unused variable" warnings with the method described in
350 // https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/.
351 // (void)var does not work on many Intel compilers.
352 template <typename
... T
> FMT_CONSTEXPR
void ignore_unused(const T
&...) {}
354 constexpr FMT_INLINE
auto is_constant_evaluated(bool default_value
= false)
355 FMT_NOEXCEPT
-> bool {
356 #ifdef __cpp_lib_is_constant_evaluated
357 ignore_unused(default_value
);
358 return std::is_constant_evaluated();
360 return default_value
;
364 // A function to suppress "conditional expression is constant" warnings.
365 template <typename T
> constexpr FMT_INLINE
auto const_check(T value
) -> T
{
369 FMT_NORETURN FMT_API
void assert_fail(const char* file
, int line
,
370 const char* message
);
374 // FMT_ASSERT is not empty to avoid -Werror=empty-body.
375 # define FMT_ASSERT(condition, message) \
376 ::fmt::detail::ignore_unused((condition), (message))
378 # define FMT_ASSERT(condition, message) \
379 ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
381 : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
385 #ifdef __cpp_lib_byte
386 using byte
= std::byte
;
388 enum class byte
: unsigned char {};
391 #if defined(FMT_USE_STRING_VIEW)
392 template <typename Char
> using std_string_view
= std::basic_string_view
<Char
>;
393 #elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
394 template <typename Char
>
395 using std_string_view
= std::experimental::basic_string_view
<Char
>;
397 template <typename T
> struct std_string_view
{};
400 #ifdef FMT_USE_INT128
402 #elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \
403 !(FMT_CLANG_VERSION && FMT_MSC_VER)
404 # define FMT_USE_INT128 1
405 using int128_t
= __int128_t
;
406 using uint128_t
= __uint128_t
;
407 template <typename T
> inline auto convert_for_visit(T value
) -> T
{
411 # define FMT_USE_INT128 0
414 enum class int128_t
{};
415 enum class uint128_t
{};
416 // Reduce template instantiations.
417 template <typename T
> inline auto convert_for_visit(T
) -> monostate
{
422 // Casts a nonnegative integer to unsigned.
423 template <typename Int
>
424 FMT_CONSTEXPR
auto to_unsigned(Int value
) ->
425 typename
std::make_unsigned
<Int
>::type
{
426 FMT_ASSERT(value
>= 0, "negative value");
427 return static_cast<typename
std::make_unsigned
<Int
>::type
>(value
);
430 FMT_MSC_WARNING(suppress
: 4566) constexpr unsigned char micro
[] = "\u00B5";
432 constexpr auto is_utf8() -> bool {
433 // Avoid buggy sign extensions in MSVC's constant evaluation mode.
434 // https://developercommunity.visualstudio.com/t/C-difference-in-behavior-for-unsigned/1233612
435 using uchar
= unsigned char;
436 return FMT_UNICODE
|| (sizeof(micro
) == 3 && uchar(micro
[0]) == 0xC2 &&
437 uchar(micro
[1]) == 0xB5);
439 FMT_END_DETAIL_NAMESPACE
442 An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
443 subset of the API. ``fmt::basic_string_view`` is used for format strings even
444 if ``std::string_view`` is available to prevent issues when a library is
445 compiled with a different ``-std`` option than the client code (which is not
448 template <typename Char
> class basic_string_view
{
454 using value_type
= Char
;
455 using iterator
= const Char
*;
457 constexpr basic_string_view() FMT_NOEXCEPT
: data_(nullptr), size_(0) {}
459 /** Constructs a string reference object from a C string and a size. */
460 constexpr basic_string_view(const Char
* s
, size_t count
) FMT_NOEXCEPT
466 Constructs a string reference object from a C string computing
467 the size with ``std::char_traits<Char>::length``.
470 FMT_CONSTEXPR_CHAR_TRAITS
472 basic_string_view(const Char
* s
)
474 size_(detail::const_check(std::is_same
<Char
, char>::value
&&
475 !detail::is_constant_evaluated(true))
476 ? std::strlen(reinterpret_cast<const char*>(s
))
477 : std::char_traits
<Char
>::length(s
)) {}
479 /** Constructs a string reference from a ``std::basic_string`` object. */
480 template <typename Traits
, typename Alloc
>
481 FMT_CONSTEXPR
basic_string_view(
482 const std::basic_string
<Char
, Traits
, Alloc
>& s
) FMT_NOEXCEPT
486 template <typename S
, FMT_ENABLE_IF(std::is_same
<
487 S
, detail::std_string_view
<Char
>>::value
)>
488 FMT_CONSTEXPR
basic_string_view(S s
) FMT_NOEXCEPT
: data_(s
.data()),
491 /** Returns a pointer to the string data. */
492 constexpr auto data() const FMT_NOEXCEPT
-> const Char
* { return data_
; }
494 /** Returns the string size. */
495 constexpr auto size() const FMT_NOEXCEPT
-> size_t { return size_
; }
497 constexpr auto begin() const FMT_NOEXCEPT
-> iterator
{ return data_
; }
498 constexpr auto end() const FMT_NOEXCEPT
-> iterator
{ return data_
+ size_
; }
500 constexpr auto operator[](size_t pos
) const FMT_NOEXCEPT
-> const Char
& {
504 FMT_CONSTEXPR
void remove_prefix(size_t n
) FMT_NOEXCEPT
{
509 // Lexicographically compare this string reference to other.
510 FMT_CONSTEXPR_CHAR_TRAITS
auto compare(basic_string_view other
) const -> int {
511 size_t str_size
= size_
< other
.size_
? size_
: other
.size_
;
512 int result
= std::char_traits
<Char
>::compare(data_
, other
.data_
, str_size
);
514 result
= size_
== other
.size_
? 0 : (size_
< other
.size_
? -1 : 1);
518 FMT_CONSTEXPR_CHAR_TRAITS
friend auto operator==(basic_string_view lhs
,
519 basic_string_view rhs
)
521 return lhs
.compare(rhs
) == 0;
523 friend auto operator!=(basic_string_view lhs
, basic_string_view rhs
) -> bool {
524 return lhs
.compare(rhs
) != 0;
526 friend auto operator<(basic_string_view lhs
, basic_string_view rhs
) -> bool {
527 return lhs
.compare(rhs
) < 0;
529 friend auto operator<=(basic_string_view lhs
, basic_string_view rhs
) -> bool {
530 return lhs
.compare(rhs
) <= 0;
532 friend auto operator>(basic_string_view lhs
, basic_string_view rhs
) -> bool {
533 return lhs
.compare(rhs
) > 0;
535 friend auto operator>=(basic_string_view lhs
, basic_string_view rhs
) -> bool {
536 return lhs
.compare(rhs
) >= 0;
540 using string_view
= basic_string_view
<char>;
542 /** Specifies if ``T`` is a character type. Can be specialized by users. */
543 template <typename T
> struct is_char
: std::false_type
{};
544 template <> struct is_char
<char> : std::true_type
{};
546 // Returns a string view of `s`.
547 template <typename Char
, FMT_ENABLE_IF(is_char
<Char
>::value
)>
548 FMT_INLINE
auto to_string_view(const Char
* s
) -> basic_string_view
<Char
> {
551 template <typename Char
, typename Traits
, typename Alloc
>
552 inline auto to_string_view(const std::basic_string
<Char
, Traits
, Alloc
>& s
)
553 -> basic_string_view
<Char
> {
556 template <typename Char
>
557 constexpr auto to_string_view(basic_string_view
<Char
> s
)
558 -> basic_string_view
<Char
> {
561 template <typename Char
,
562 FMT_ENABLE_IF(!std::is_empty
<detail::std_string_view
<Char
>>::value
)>
563 inline auto to_string_view(detail::std_string_view
<Char
> s
)
564 -> basic_string_view
<Char
> {
568 // A base class for compile-time strings. It is defined in the fmt namespace to
569 // make formatting functions visible via ADL, e.g. format(FMT_STRING("{}"), 42).
570 struct compile_string
{};
572 template <typename S
>
573 struct is_compile_string
: std::is_base_of
<compile_string
, S
> {};
575 template <typename S
, FMT_ENABLE_IF(is_compile_string
<S
>::value
)>
576 constexpr auto to_string_view(const S
& s
)
577 -> basic_string_view
<typename
S::char_type
> {
578 return basic_string_view
<typename
S::char_type
>(s
);
581 FMT_BEGIN_DETAIL_NAMESPACE
583 void to_string_view(...);
584 using fmt::to_string_view
;
586 // Specifies whether S is a string type convertible to fmt::basic_string_view.
587 // It should be a constexpr function but MSVC 2017 fails to compile it in
588 // enable_if and MSVC 2015 fails to compile it as an alias template.
589 template <typename S
>
590 struct is_string
: std::is_class
<decltype(to_string_view(std::declval
<S
>()))> {
593 template <typename S
, typename
= void> struct char_t_impl
{};
594 template <typename S
> struct char_t_impl
<S
, enable_if_t
<is_string
<S
>::value
>> {
595 using result
= decltype(to_string_view(std::declval
<S
>()));
596 using type
= typename
result::value_type
;
599 // Reports a compile-time error if S is not a valid format string.
600 template <typename
..., typename S
, FMT_ENABLE_IF(!is_compile_string
<S
>::value
)>
601 FMT_INLINE
void check_format_string(const S
&) {
602 #ifdef FMT_ENFORCE_COMPILE_STRING
603 static_assert(is_compile_string
<S
>::value
,
604 "FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
608 template <typename
..., typename S
, FMT_ENABLE_IF(is_compile_string
<S
>::value
)>
609 void check_format_string(S
);
611 FMT_NORETURN FMT_API
void throw_format_error(const char* message
);
613 struct error_handler
{
614 constexpr error_handler() = default;
615 constexpr error_handler(const error_handler
&) = default;
617 // This function is intentionally not constexpr to give a compile-time error.
618 FMT_NORETURN FMT_API
void on_error(const char* message
);
620 FMT_END_DETAIL_NAMESPACE
622 /** String's character type. */
623 template <typename S
> using char_t
= typename
detail::char_t_impl
<S
>::type
;
627 Parsing context consisting of a format string range being parsed and an
628 argument counter for automatic indexing.
629 You can use the ``format_parse_context`` type alias for ``char`` instead.
632 template <typename Char
, typename ErrorHandler
= detail::error_handler
>
633 class basic_format_parse_context
: private ErrorHandler
{
635 basic_string_view
<Char
> format_str_
;
639 using char_type
= Char
;
640 using iterator
= typename basic_string_view
<Char
>::iterator
;
642 explicit constexpr basic_format_parse_context(
643 basic_string_view
<Char
> format_str
, ErrorHandler eh
= {},
645 : ErrorHandler(eh
), format_str_(format_str
), next_arg_id_(next_arg_id
) {}
648 Returns an iterator to the beginning of the format string range being
651 constexpr auto begin() const FMT_NOEXCEPT
-> iterator
{
652 return format_str_
.begin();
656 Returns an iterator past the end of the format string range being parsed.
658 constexpr auto end() const FMT_NOEXCEPT
-> iterator
{
659 return format_str_
.end();
662 /** Advances the begin iterator to ``it``. */
663 FMT_CONSTEXPR
void advance_to(iterator it
) {
664 format_str_
.remove_prefix(detail::to_unsigned(it
- begin()));
668 Reports an error if using the manual argument indexing; otherwise returns
669 the next argument index and switches to the automatic indexing.
671 FMT_CONSTEXPR
auto next_arg_id() -> int {
672 // Don't check if the argument id is valid to avoid overhead and because it
673 // will be checked during formatting anyway.
674 if (next_arg_id_
>= 0) return next_arg_id_
++;
675 on_error("cannot switch from manual to automatic argument indexing");
680 Reports an error if using the automatic argument indexing; otherwise
681 switches to the manual indexing.
683 FMT_CONSTEXPR
void check_arg_id(int) {
684 if (next_arg_id_
> 0)
685 on_error("cannot switch from automatic to manual argument indexing");
690 FMT_CONSTEXPR
void check_arg_id(basic_string_view
<Char
>) {}
692 FMT_CONSTEXPR
void on_error(const char* message
) {
693 ErrorHandler::on_error(message
);
696 constexpr auto error_handler() const -> ErrorHandler
{ return *this; }
699 using format_parse_context
= basic_format_parse_context
<char>;
701 template <typename Context
> class basic_format_arg
;
702 template <typename Context
> class basic_format_args
;
703 template <typename Context
> class dynamic_format_arg_store
;
705 // A formatter for objects of type T.
706 template <typename T
, typename Char
= char, typename Enable
= void>
708 // A deleted default constructor indicates a disabled formatter.
709 formatter() = delete;
712 // Specifies if T has an enabled formatter specialization. A type can be
713 // formattable even if it doesn't have a formatter e.g. via a conversion.
714 template <typename T
, typename Context
>
715 using has_formatter
=
716 std::is_constructible
<typename
Context::template formatter_type
<T
>>;
718 // Checks whether T is a container with contiguous storage.
719 template <typename T
> struct is_contiguous
: std::false_type
{};
720 template <typename Char
>
721 struct is_contiguous
<std::basic_string
<Char
>> : std::true_type
{};
725 FMT_BEGIN_DETAIL_NAMESPACE
727 template <typename Context
, typename T
>
728 constexpr auto has_const_formatter_impl(T
*)
729 -> decltype(typename
Context::template formatter_type
<T
>().format(
730 std::declval
<const T
&>(), std::declval
<Context
&>()),
734 template <typename Context
>
735 constexpr auto has_const_formatter_impl(...) -> bool {
738 template <typename T
, typename Context
>
739 constexpr auto has_const_formatter() -> bool {
740 return has_const_formatter_impl
<Context
>(static_cast<T
*>(nullptr));
743 // Extracts a reference to the container from back_insert_iterator.
744 template <typename Container
>
745 inline auto get_container(std::back_insert_iterator
<Container
> it
)
747 using bi_iterator
= std::back_insert_iterator
<Container
>;
748 struct accessor
: bi_iterator
{
749 accessor(bi_iterator iter
) : bi_iterator(iter
) {}
750 using bi_iterator::container
;
752 return *accessor(it
).container
;
755 template <typename Char
, typename InputIt
, typename OutputIt
>
756 FMT_CONSTEXPR
auto copy_str(InputIt begin
, InputIt end
, OutputIt out
)
758 while (begin
!= end
) *out
++ = static_cast<Char
>(*begin
++);
762 template <typename Char
, typename T
, typename U
,
764 std::is_same
<remove_const_t
<T
>, U
>::value
&& is_char
<U
>::value
)>
765 FMT_CONSTEXPR
auto copy_str(T
* begin
, T
* end
, U
* out
) -> U
* {
766 if (is_constant_evaluated()) return copy_str
<Char
, T
*, U
*>(begin
, end
, out
);
767 auto size
= to_unsigned(end
- begin
);
768 memcpy(out
, begin
, size
* sizeof(U
));
774 A contiguous memory buffer with an optional growing ability. It is an internal
775 class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`.
778 template <typename T
> class buffer
{
785 // Don't initialize ptr_ since it is not accessed to save a few cycles.
786 FMT_MSC_WARNING(suppress
: 26495)
787 buffer(size_t sz
) FMT_NOEXCEPT
: size_(sz
), capacity_(sz
) {}
789 FMT_CONSTEXPR20
buffer(T
* p
= nullptr, size_t sz
= 0,
790 size_t cap
= 0) FMT_NOEXCEPT
: ptr_(p
),
794 FMT_CONSTEXPR20
~buffer() = default;
795 buffer(buffer
&&) = default;
797 /** Sets the buffer data and capacity. */
798 FMT_CONSTEXPR
void set(T
* buf_data
, size_t buf_capacity
) FMT_NOEXCEPT
{
800 capacity_
= buf_capacity
;
803 /** Increases the buffer capacity to hold at least *capacity* elements. */
804 virtual FMT_CONSTEXPR20
void grow(size_t capacity
) = 0;
807 using value_type
= T
;
808 using const_reference
= const T
&;
810 buffer(const buffer
&) = delete;
811 void operator=(const buffer
&) = delete;
813 auto begin() FMT_NOEXCEPT
-> T
* { return ptr_
; }
814 auto end() FMT_NOEXCEPT
-> T
* { return ptr_
+ size_
; }
816 auto begin() const FMT_NOEXCEPT
-> const T
* { return ptr_
; }
817 auto end() const FMT_NOEXCEPT
-> const T
* { return ptr_
+ size_
; }
819 /** Returns the size of this buffer. */
820 constexpr auto size() const FMT_NOEXCEPT
-> size_t { return size_
; }
822 /** Returns the capacity of this buffer. */
823 constexpr auto capacity() const FMT_NOEXCEPT
-> size_t { return capacity_
; }
825 /** Returns a pointer to the buffer data. */
826 FMT_CONSTEXPR
auto data() FMT_NOEXCEPT
-> T
* { return ptr_
; }
828 /** Returns a pointer to the buffer data. */
829 FMT_CONSTEXPR
auto data() const FMT_NOEXCEPT
-> const T
* { return ptr_
; }
831 /** Clears this buffer. */
832 void clear() { size_
= 0; }
834 // Tries resizing the buffer to contain *count* elements. If T is a POD type
835 // the new elements may not be initialized.
836 FMT_CONSTEXPR20
void try_resize(size_t count
) {
838 size_
= count
<= capacity_
? count
: capacity_
;
841 // Tries increasing the buffer capacity to *new_capacity*. It can increase the
842 // capacity by a smaller amount than requested but guarantees there is space
843 // for at least one additional element either by increasing the capacity or by
844 // flushing the buffer if it is full.
845 FMT_CONSTEXPR20
void try_reserve(size_t new_capacity
) {
846 if (new_capacity
> capacity_
) grow(new_capacity
);
849 FMT_CONSTEXPR20
void push_back(const T
& value
) {
850 try_reserve(size_
+ 1);
851 ptr_
[size_
++] = value
;
854 /** Appends data to the end of the buffer. */
855 template <typename U
> void append(const U
* begin
, const U
* end
);
857 template <typename I
> FMT_CONSTEXPR
auto operator[](I index
) -> T
& {
860 template <typename I
>
861 FMT_CONSTEXPR
auto operator[](I index
) const -> const T
& {
866 struct buffer_traits
{
867 explicit buffer_traits(size_t) {}
868 auto count() const -> size_t { return 0; }
869 auto limit(size_t size
) -> size_t { return size
; }
872 class fixed_buffer_traits
{
878 explicit fixed_buffer_traits(size_t limit
) : limit_(limit
) {}
879 auto count() const -> size_t { return count_
; }
880 auto limit(size_t size
) -> size_t {
881 size_t n
= limit_
> count_
? limit_
- count_
: 0;
883 return size
< n
? size
: n
;
887 // A buffer that writes to an output iterator when flushed.
888 template <typename OutputIt
, typename T
, typename Traits
= buffer_traits
>
889 class iterator_buffer final
: public Traits
, public buffer
<T
> {
892 enum { buffer_size
= 256 };
893 T data_
[buffer_size
];
896 FMT_CONSTEXPR20
void grow(size_t) override
{
897 if (this->size() == buffer_size
) flush();
901 auto size
= this->size();
903 out_
= copy_str
<T
>(data_
, data_
+ this->limit(size
), out_
);
907 explicit iterator_buffer(OutputIt out
, size_t n
= buffer_size
)
908 : Traits(n
), buffer
<T
>(data_
, 0, buffer_size
), out_(out
) {}
909 iterator_buffer(iterator_buffer
&& other
)
910 : Traits(other
), buffer
<T
>(data_
, 0, buffer_size
), out_(other
.out_
) {}
911 ~iterator_buffer() { flush(); }
913 auto out() -> OutputIt
{
917 auto count() const -> size_t { return Traits::count() + this->size(); }
920 template <typename T
>
921 class iterator_buffer
<T
*, T
, fixed_buffer_traits
> final
922 : public fixed_buffer_traits
,
926 enum { buffer_size
= 256 };
927 T data_
[buffer_size
];
930 FMT_CONSTEXPR20
void grow(size_t) override
{
931 if (this->size() == this->capacity()) flush();
935 size_t n
= this->limit(this->size());
936 if (this->data() == out_
) {
938 this->set(data_
, buffer_size
);
944 explicit iterator_buffer(T
* out
, size_t n
= buffer_size
)
945 : fixed_buffer_traits(n
), buffer
<T
>(out
, 0, n
), out_(out
) {}
946 iterator_buffer(iterator_buffer
&& other
)
947 : fixed_buffer_traits(other
),
948 buffer
<T
>(std::move(other
)),
950 if (this->data() != out_
) {
951 this->set(data_
, buffer_size
);
955 ~iterator_buffer() { flush(); }
961 auto count() const -> size_t {
962 return fixed_buffer_traits::count() + this->size();
966 template <typename T
> class iterator_buffer
<T
*, T
> final
: public buffer
<T
> {
968 FMT_CONSTEXPR20
void grow(size_t) override
{}
971 explicit iterator_buffer(T
* out
, size_t = 0) : buffer
<T
>(out
, 0, ~size_t()) {}
973 auto out() -> T
* { return &*this->end(); }
976 // A buffer that writes to a container with the contiguous storage.
977 template <typename Container
>
978 class iterator_buffer
<std::back_insert_iterator
<Container
>,
979 enable_if_t
<is_contiguous
<Container
>::value
,
980 typename
Container::value_type
>>
981 final
: public buffer
<typename
Container::value_type
> {
983 Container
& container_
;
986 FMT_CONSTEXPR20
void grow(size_t capacity
) override
{
987 container_
.resize(capacity
);
988 this->set(&container_
[0], capacity
);
992 explicit iterator_buffer(Container
& c
)
993 : buffer
<typename
Container::value_type
>(c
.size()), container_(c
) {}
994 explicit iterator_buffer(std::back_insert_iterator
<Container
> out
, size_t = 0)
995 : iterator_buffer(get_container(out
)) {}
996 auto out() -> std::back_insert_iterator
<Container
> {
997 return std::back_inserter(container_
);
1001 // A buffer that counts the number of code units written discarding the output.
1002 template <typename T
= char> class counting_buffer final
: public buffer
<T
> {
1004 enum { buffer_size
= 256 };
1005 T data_
[buffer_size
];
1009 FMT_CONSTEXPR20
void grow(size_t) override
{
1010 if (this->size() != buffer_size
) return;
1011 count_
+= this->size();
1016 counting_buffer() : buffer
<T
>(data_
, 0, buffer_size
) {}
1018 auto count() -> size_t { return count_
+ this->size(); }
1021 template <typename T
>
1022 using buffer_appender
= conditional_t
<std::is_same
<T
, char>::value
, appender
,
1023 std::back_insert_iterator
<buffer
<T
>>>;
1025 // Maps an output iterator to a buffer.
1026 template <typename T
, typename OutputIt
>
1027 auto get_buffer(OutputIt out
) -> iterator_buffer
<OutputIt
, T
> {
1028 return iterator_buffer
<OutputIt
, T
>(out
);
1031 template <typename Buffer
>
1032 auto get_iterator(Buffer
& buf
) -> decltype(buf
.out()) {
1035 template <typename T
> auto get_iterator(buffer
<T
>& buf
) -> buffer_appender
<T
> {
1036 return buffer_appender
<T
>(buf
);
1039 template <typename T
, typename Char
= char, typename Enable
= void>
1040 struct fallback_formatter
{
1041 fallback_formatter() = delete;
1044 // Specifies if T has an enabled fallback_formatter specialization.
1045 template <typename T
, typename Char
>
1046 using has_fallback_formatter
=
1047 std::is_constructible
<fallback_formatter
<T
, Char
>>;
1051 template <typename Char
, typename T
> struct named_arg
: view
{
1054 named_arg(const Char
* n
, const T
& v
) : name(n
), value(v
) {}
1057 template <typename Char
> struct named_arg_info
{
1062 template <typename T
, typename Char
, size_t NUM_ARGS
, size_t NUM_NAMED_ARGS
>
1064 // args_[0].named_args points to named_args_ to avoid bloating format_args.
1065 // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
1066 T args_
[1 + (NUM_ARGS
!= 0 ? NUM_ARGS
: +1)];
1067 named_arg_info
<Char
> named_args_
[NUM_NAMED_ARGS
];
1069 template <typename
... U
>
1070 arg_data(const U
&... init
) : args_
{T(named_args_
, NUM_NAMED_ARGS
), init
...} {}
1071 arg_data(const arg_data
& other
) = delete;
1072 auto args() const -> const T
* { return args_
+ 1; }
1073 auto named_args() -> named_arg_info
<Char
>* { return named_args_
; }
1076 template <typename T
, typename Char
, size_t NUM_ARGS
>
1077 struct arg_data
<T
, Char
, NUM_ARGS
, 0> {
1078 // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
1079 T args_
[NUM_ARGS
!= 0 ? NUM_ARGS
: +1];
1081 template <typename
... U
>
1082 FMT_CONSTEXPR FMT_INLINE
arg_data(const U
&... init
) : args_
{init
...} {}
1083 FMT_CONSTEXPR FMT_INLINE
auto args() const -> const T
* { return args_
; }
1084 FMT_CONSTEXPR FMT_INLINE
auto named_args() -> std::nullptr_t
{
1089 template <typename Char
>
1090 inline void init_named_args(named_arg_info
<Char
>*, int, int) {}
1092 template <typename T
> struct is_named_arg
: std::false_type
{};
1093 template <typename T
> struct is_statically_named_arg
: std::false_type
{};
1095 template <typename T
, typename Char
>
1096 struct is_named_arg
<named_arg
<Char
, T
>> : std::true_type
{};
1098 template <typename Char
, typename T
, typename
... Tail
,
1099 FMT_ENABLE_IF(!is_named_arg
<T
>::value
)>
1100 void init_named_args(named_arg_info
<Char
>* named_args
, int arg_count
,
1101 int named_arg_count
, const T
&, const Tail
&... args
) {
1102 init_named_args(named_args
, arg_count
+ 1, named_arg_count
, args
...);
1105 template <typename Char
, typename T
, typename
... Tail
,
1106 FMT_ENABLE_IF(is_named_arg
<T
>::value
)>
1107 void init_named_args(named_arg_info
<Char
>* named_args
, int arg_count
,
1108 int named_arg_count
, const T
& arg
, const Tail
&... args
) {
1109 named_args
[named_arg_count
++] = {arg
.name
, arg_count
};
1110 init_named_args(named_args
, arg_count
+ 1, named_arg_count
, args
...);
1113 template <typename
... Args
>
1114 FMT_CONSTEXPR FMT_INLINE
void init_named_args(std::nullptr_t
, int, int,
1117 template <bool B
= false> constexpr auto count() -> size_t { return B
? 1 : 0; }
1118 template <bool B1
, bool B2
, bool... Tail
> constexpr auto count() -> size_t {
1119 return (B1
? 1 : 0) + count
<B2
, Tail
...>();
1122 template <typename
... Args
> constexpr auto count_named_args() -> size_t {
1123 return count
<is_named_arg
<Args
>::value
...>();
1126 template <typename
... Args
>
1127 constexpr auto count_statically_named_args() -> size_t {
1128 return count
<is_statically_named_arg
<Args
>::value
...>();
1133 // Integer types should go first,
1142 last_integer_type
= char_type
,
1143 // followed by floating-point types.
1147 last_numeric_type
= long_double_type
,
1154 // Maps core type T to the corresponding type enum constant.
1155 template <typename T
, typename Char
>
1156 struct type_constant
: std::integral_constant
<type
, type::custom_type
> {};
1158 #define FMT_TYPE_CONSTANT(Type, constant) \
1159 template <typename Char> \
1160 struct type_constant<Type, Char> \
1161 : std::integral_constant<type, type::constant> {}
1163 FMT_TYPE_CONSTANT(int, int_type
);
1164 FMT_TYPE_CONSTANT(unsigned, uint_type
);
1165 FMT_TYPE_CONSTANT(long long, long_long_type
);
1166 FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type
);
1167 FMT_TYPE_CONSTANT(int128_t
, int128_type
);
1168 FMT_TYPE_CONSTANT(uint128_t
, uint128_type
);
1169 FMT_TYPE_CONSTANT(bool, bool_type
);
1170 FMT_TYPE_CONSTANT(Char
, char_type
);
1171 FMT_TYPE_CONSTANT(float, float_type
);
1172 FMT_TYPE_CONSTANT(double, double_type
);
1173 FMT_TYPE_CONSTANT(long double, long_double_type
);
1174 FMT_TYPE_CONSTANT(const Char
*, cstring_type
);
1175 FMT_TYPE_CONSTANT(basic_string_view
<Char
>, string_type
);
1176 FMT_TYPE_CONSTANT(const void*, pointer_type
);
1178 constexpr bool is_integral_type(type t
) {
1179 return t
> type::none_type
&& t
<= type::last_integer_type
;
1182 constexpr bool is_arithmetic_type(type t
) {
1183 return t
> type::none_type
&& t
<= type::last_numeric_type
;
1186 struct unformattable
{};
1187 struct unformattable_char
: unformattable
{};
1188 struct unformattable_const
: unformattable
{};
1189 struct unformattable_pointer
: unformattable
{};
1191 template <typename Char
> struct string_value
{
1196 template <typename Char
> struct named_arg_value
{
1197 const named_arg_info
<Char
>* data
;
1201 template <typename Context
> struct custom_value
{
1202 using parse_context
= typename
Context::parse_context_type
;
1204 void (*format
)(void* arg
, parse_context
& parse_ctx
, Context
& ctx
);
1207 // A formatting argument value.
1208 template <typename Context
> class value
{
1210 using char_type
= typename
Context::char_type
;
1215 unsigned uint_value
;
1216 long long long_long_value
;
1217 unsigned long long ulong_long_value
;
1218 int128_t int128_value
;
1219 uint128_t uint128_value
;
1221 char_type char_value
;
1223 double double_value
;
1224 long double long_double_value
;
1225 const void* pointer
;
1226 string_value
<char_type
> string
;
1227 custom_value
<Context
> custom
;
1228 named_arg_value
<char_type
> named_args
;
1231 constexpr FMT_INLINE
value() : no_value() {}
1232 constexpr FMT_INLINE
value(int val
) : int_value(val
) {}
1233 constexpr FMT_INLINE
value(unsigned val
) : uint_value(val
) {}
1234 constexpr FMT_INLINE
value(long long val
) : long_long_value(val
) {}
1235 constexpr FMT_INLINE
value(unsigned long long val
) : ulong_long_value(val
) {}
1236 FMT_INLINE
value(int128_t val
) : int128_value(val
) {}
1237 FMT_INLINE
value(uint128_t val
) : uint128_value(val
) {}
1238 constexpr FMT_INLINE
value(float val
) : float_value(val
) {}
1239 constexpr FMT_INLINE
value(double val
) : double_value(val
) {}
1240 FMT_INLINE
value(long double val
) : long_double_value(val
) {}
1241 constexpr FMT_INLINE
value(bool val
) : bool_value(val
) {}
1242 constexpr FMT_INLINE
value(char_type val
) : char_value(val
) {}
1243 FMT_CONSTEXPR FMT_INLINE
value(const char_type
* val
) {
1245 if (is_constant_evaluated()) string
.size
= {};
1247 FMT_CONSTEXPR FMT_INLINE
value(basic_string_view
<char_type
> val
) {
1248 string
.data
= val
.data();
1249 string
.size
= val
.size();
1251 FMT_INLINE
value(const void* val
) : pointer(val
) {}
1252 FMT_INLINE
value(const named_arg_info
<char_type
>* args
, size_t size
)
1253 : named_args
{args
, size
} {}
1255 template <typename T
> FMT_CONSTEXPR FMT_INLINE
value(T
& val
) {
1256 using value_type
= remove_cvref_t
<T
>;
1257 custom
.value
= const_cast<value_type
*>(&val
);
1258 // Get the formatter type through the context to allow different contexts
1259 // have different extension points, e.g. `formatter<T>` for `format` and
1260 // `printf_formatter<T>` for `printf`.
1261 custom
.format
= format_custom_arg
<
1263 conditional_t
<has_formatter
<value_type
, Context
>::value
,
1264 typename
Context::template formatter_type
<value_type
>,
1265 fallback_formatter
<value_type
, char_type
>>>;
1267 value(unformattable
);
1268 value(unformattable_char
);
1269 value(unformattable_const
);
1270 value(unformattable_pointer
);
1273 // Formats an argument of a custom type, such as a user-defined class.
1274 template <typename T
, typename Formatter
>
1275 static void format_custom_arg(void* arg
,
1276 typename
Context::parse_context_type
& parse_ctx
,
1278 auto f
= Formatter();
1279 parse_ctx
.advance_to(f
.parse(parse_ctx
));
1280 using qualified_type
=
1281 conditional_t
<has_const_formatter
<T
, Context
>(), const T
, T
>;
1282 ctx
.advance_to(f
.format(*static_cast<qualified_type
*>(arg
), ctx
));
1286 template <typename Context
, typename T
>
1287 FMT_CONSTEXPR
auto make_arg(const T
& value
) -> basic_format_arg
<Context
>;
1289 // To minimize the number of types we need to deal with, long is translated
1290 // either to int or to long long depending on its size.
1291 enum { long_short
= sizeof(long) == sizeof(int) };
1292 using long_type
= conditional_t
<long_short
, int, long long>;
1293 using ulong_type
= conditional_t
<long_short
, unsigned, unsigned long long>;
1295 // Maps formatting arguments to core types.
1296 // arg_mapper reports errors by returning unformattable instead of using
1297 // static_assert because it's used in the is_formattable trait.
1298 template <typename Context
> struct arg_mapper
{
1299 using char_type
= typename
Context::char_type
;
1301 FMT_CONSTEXPR FMT_INLINE
auto map(signed char val
) -> int { return val
; }
1302 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned char val
) -> unsigned {
1305 FMT_CONSTEXPR FMT_INLINE
auto map(short val
) -> int { return val
; }
1306 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned short val
) -> unsigned {
1309 FMT_CONSTEXPR FMT_INLINE
auto map(int val
) -> int { return val
; }
1310 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned val
) -> unsigned { return val
; }
1311 FMT_CONSTEXPR FMT_INLINE
auto map(long val
) -> long_type
{ return val
; }
1312 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned long val
) -> ulong_type
{
1315 FMT_CONSTEXPR FMT_INLINE
auto map(long long val
) -> long long { return val
; }
1316 FMT_CONSTEXPR FMT_INLINE
auto map(unsigned long long val
)
1317 -> unsigned long long {
1320 FMT_CONSTEXPR FMT_INLINE
auto map(int128_t val
) -> int128_t
{ return val
; }
1321 FMT_CONSTEXPR FMT_INLINE
auto map(uint128_t val
) -> uint128_t
{ return val
; }
1322 FMT_CONSTEXPR FMT_INLINE
auto map(bool val
) -> bool { return val
; }
1324 template <typename T
, FMT_ENABLE_IF(std::is_same
<T
, char>::value
||
1325 std::is_same
<T
, char_type
>::value
)>
1326 FMT_CONSTEXPR FMT_INLINE
auto map(T val
) -> char_type
{
1329 template <typename T
, enable_if_t
<(std::is_same
<T
, wchar_t>::value
||
1330 #ifdef __cpp_char8_t
1331 std::is_same
<T
, char8_t
>::value
||
1333 std::is_same
<T
, char16_t
>::value
||
1334 std::is_same
<T
, char32_t
>::value
) &&
1335 !std::is_same
<T
, char_type
>::value
,
1337 FMT_CONSTEXPR FMT_INLINE
auto map(T
) -> unformattable_char
{
1341 FMT_CONSTEXPR FMT_INLINE
auto map(float val
) -> float { return val
; }
1342 FMT_CONSTEXPR FMT_INLINE
auto map(double val
) -> double { return val
; }
1343 FMT_CONSTEXPR FMT_INLINE
auto map(long double val
) -> long double {
1347 FMT_CONSTEXPR FMT_INLINE
auto map(char_type
* val
) -> const char_type
* {
1350 FMT_CONSTEXPR FMT_INLINE
auto map(const char_type
* val
) -> const char_type
* {
1353 template <typename T
,
1354 FMT_ENABLE_IF(is_string
<T
>::value
&& !std::is_pointer
<T
>::value
&&
1355 std::is_same
<char_type
, char_t
<T
>>::value
)>
1356 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& val
)
1357 -> basic_string_view
<char_type
> {
1358 return to_string_view(val
);
1360 template <typename T
,
1361 FMT_ENABLE_IF(is_string
<T
>::value
&& !std::is_pointer
<T
>::value
&&
1362 !std::is_same
<char_type
, char_t
<T
>>::value
)>
1363 FMT_CONSTEXPR FMT_INLINE
auto map(const T
&) -> unformattable_char
{
1366 template <typename T
,
1368 std::is_constructible
<basic_string_view
<char_type
>, T
>::value
&&
1369 !is_string
<T
>::value
&& !has_formatter
<T
, Context
>::value
&&
1370 !has_fallback_formatter
<T
, char_type
>::value
)>
1371 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& val
)
1372 -> basic_string_view
<char_type
> {
1373 return basic_string_view
<char_type
>(val
);
1378 std::is_constructible
<std_string_view
<char_type
>, T
>::value
&&
1379 !std::is_constructible
<basic_string_view
<char_type
>, T
>::value
&&
1380 !is_string
<T
>::value
&& !has_formatter
<T
, Context
>::value
&&
1381 !has_fallback_formatter
<T
, char_type
>::value
)>
1382 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& val
)
1383 -> basic_string_view
<char_type
> {
1384 return std_string_view
<char_type
>(val
);
1387 using cstring_result
= conditional_t
<std::is_same
<char_type
, char>::value
,
1388 const char*, unformattable_pointer
>;
1390 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE
auto map(const signed char* val
)
1392 return map(reinterpret_cast<const char*>(val
));
1394 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE
auto map(const unsigned char* val
)
1396 return map(reinterpret_cast<const char*>(val
));
1398 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE
auto map(signed char* val
)
1400 return map(reinterpret_cast<const char*>(val
));
1402 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE
auto map(unsigned char* val
)
1404 return map(reinterpret_cast<const char*>(val
));
1407 FMT_CONSTEXPR FMT_INLINE
auto map(void* val
) -> const void* { return val
; }
1408 FMT_CONSTEXPR FMT_INLINE
auto map(const void* val
) -> const void* {
1411 FMT_CONSTEXPR FMT_INLINE
auto map(std::nullptr_t val
) -> const void* {
1415 // We use SFINAE instead of a const T* parameter to avoid conflicting with
1416 // the C array overload.
1420 std::is_member_pointer
<T
>::value
||
1421 std::is_function
<typename
std::remove_pointer
<T
>::type
>::value
||
1422 (std::is_convertible
<const T
&, const void*>::value
&&
1423 !std::is_convertible
<const T
&, const char_type
*>::value
))>
1424 FMT_CONSTEXPR
auto map(const T
&) -> unformattable_pointer
{
1428 template <typename T
, std::size_t N
,
1429 FMT_ENABLE_IF(!std::is_same
<T
, wchar_t>::value
)>
1430 FMT_CONSTEXPR FMT_INLINE
auto map(const T (&values
)[N
]) -> const T (&)[N
] {
1434 template <typename T
,
1436 std::is_enum
<T
>::value
&& std::is_convertible
<T
, int>::value
&&
1437 !has_formatter
<T
, Context
>::value
&&
1438 !has_fallback_formatter
<T
, char_type
>::value
)>
1439 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& val
)
1440 -> decltype(std::declval
<arg_mapper
>().map(
1441 static_cast<typename
std::underlying_type
<T
>::type
>(val
))) {
1442 return map(static_cast<typename
std::underlying_type
<T
>::type
>(val
));
1445 FMT_CONSTEXPR FMT_INLINE
auto map(detail::byte val
) -> unsigned {
1446 return map(static_cast<unsigned char>(val
));
1449 template <typename T
, typename U
= remove_cvref_t
<T
>>
1451 : bool_constant
<has_const_formatter
<U
, Context
>() ||
1452 !std::is_const
<remove_reference_t
<T
>>::value
||
1453 has_fallback_formatter
<U
, char_type
>::value
> {};
1455 #if FMT_MSC_VER != 0 && FMT_MSC_VER < 1910
1456 // Workaround a bug in MSVC.
1457 template <typename T
> FMT_CONSTEXPR FMT_INLINE
auto do_map(T
&& val
) -> T
& {
1461 template <typename T
, FMT_ENABLE_IF(formattable
<T
>::value
)>
1462 FMT_CONSTEXPR FMT_INLINE
auto do_map(T
&& val
) -> T
& {
1465 template <typename T
, FMT_ENABLE_IF(!formattable
<T
>::value
)>
1466 FMT_CONSTEXPR FMT_INLINE
auto do_map(T
&&) -> unformattable_const
{
1471 template <typename T
, typename U
= remove_cvref_t
<T
>,
1472 FMT_ENABLE_IF(!is_string
<U
>::value
&& !is_char
<U
>::value
&&
1473 !std::is_array
<U
>::value
&&
1474 (has_formatter
<U
, Context
>::value
||
1475 has_fallback_formatter
<U
, char_type
>::value
))>
1476 FMT_CONSTEXPR FMT_INLINE
auto map(T
&& val
)
1477 -> decltype(this->do_map(std::forward
<T
>(val
))) {
1478 return do_map(std::forward
<T
>(val
));
1481 template <typename T
, FMT_ENABLE_IF(is_named_arg
<T
>::value
)>
1482 FMT_CONSTEXPR FMT_INLINE
auto map(const T
& named_arg
)
1483 -> decltype(std::declval
<arg_mapper
>().map(named_arg
.value
)) {
1484 return map(named_arg
.value
);
1487 auto map(...) -> unformattable
{ return {}; }
1490 // A type constant after applying arg_mapper<Context>.
1491 template <typename T
, typename Context
>
1492 using mapped_type_constant
=
1493 type_constant
<decltype(arg_mapper
<Context
>().map(std::declval
<const T
&>())),
1494 typename
Context::char_type
>;
1496 enum { packed_arg_bits
= 4 };
1497 // Maximum number of arguments with packed types.
1498 enum { max_packed_args
= 62 / packed_arg_bits
};
1499 enum : unsigned long long { is_unpacked_bit
= 1ULL << 63 };
1500 enum : unsigned long long { has_named_args_bit
= 1ULL << 62 };
1502 FMT_END_DETAIL_NAMESPACE
1504 // An output iterator that appends to a buffer.
1505 // It is used to reduce symbol sizes for the common case.
1506 class appender
: public std::back_insert_iterator
<detail::buffer
<char>> {
1507 using base
= std::back_insert_iterator
<detail::buffer
<char>>;
1509 template <typename T
>
1510 friend auto get_buffer(appender out
) -> detail::buffer
<char>& {
1511 return detail::get_container(out
);
1515 using std::back_insert_iterator
<detail::buffer
<char>>::back_insert_iterator
;
1516 appender(base it
) FMT_NOEXCEPT
: base(it
) {}
1517 using _Unchecked_type
= appender
; // Mark iterator as checked.
1519 auto operator++() FMT_NOEXCEPT
-> appender
& { return *this; }
1521 auto operator++(int) FMT_NOEXCEPT
-> appender
{ return *this; }
1524 // A formatting argument. It is a trivially copyable/constructible type to
1525 // allow storage in basic_memory_buffer.
1526 template <typename Context
> class basic_format_arg
{
1528 detail::value
<Context
> value_
;
1531 template <typename ContextType
, typename T
>
1532 friend FMT_CONSTEXPR
auto detail::make_arg(const T
& value
)
1533 -> basic_format_arg
<ContextType
>;
1535 template <typename Visitor
, typename Ctx
>
1536 friend FMT_CONSTEXPR
auto visit_format_arg(Visitor
&& vis
,
1537 const basic_format_arg
<Ctx
>& arg
)
1538 -> decltype(vis(0));
1540 friend class basic_format_args
<Context
>;
1541 friend class dynamic_format_arg_store
<Context
>;
1543 using char_type
= typename
Context::char_type
;
1545 template <typename T
, typename Char
, size_t NUM_ARGS
, size_t NUM_NAMED_ARGS
>
1546 friend struct detail::arg_data
;
1548 basic_format_arg(const detail::named_arg_info
<char_type
>* args
, size_t size
)
1549 : value_(args
, size
) {}
1554 explicit handle(detail::custom_value
<Context
> custom
) : custom_(custom
) {}
1556 void format(typename
Context::parse_context_type
& parse_ctx
,
1557 Context
& ctx
) const {
1558 custom_
.format(custom_
.value
, parse_ctx
, ctx
);
1562 detail::custom_value
<Context
> custom_
;
1565 constexpr basic_format_arg() : type_(detail::type::none_type
) {}
1567 constexpr explicit operator bool() const FMT_NOEXCEPT
{
1568 return type_
!= detail::type::none_type
;
1571 auto type() const -> detail::type
{ return type_
; }
1573 auto is_integral() const -> bool { return detail::is_integral_type(type_
); }
1574 auto is_arithmetic() const -> bool {
1575 return detail::is_arithmetic_type(type_
);
1581 Visits an argument dispatching to the appropriate visit method based on
1582 the argument type. For example, if the argument type is ``double`` then
1583 ``vis(value)`` will be called with the value of type ``double``.
1586 template <typename Visitor
, typename Context
>
1587 FMT_CONSTEXPR FMT_INLINE
auto visit_format_arg(
1588 Visitor
&& vis
, const basic_format_arg
<Context
>& arg
) -> decltype(vis(0)) {
1589 switch (arg
.type_
) {
1590 case detail::type::none_type
:
1592 case detail::type::int_type
:
1593 return vis(arg
.value_
.int_value
);
1594 case detail::type::uint_type
:
1595 return vis(arg
.value_
.uint_value
);
1596 case detail::type::long_long_type
:
1597 return vis(arg
.value_
.long_long_value
);
1598 case detail::type::ulong_long_type
:
1599 return vis(arg
.value_
.ulong_long_value
);
1600 case detail::type::int128_type
:
1601 return vis(detail::convert_for_visit(arg
.value_
.int128_value
));
1602 case detail::type::uint128_type
:
1603 return vis(detail::convert_for_visit(arg
.value_
.uint128_value
));
1604 case detail::type::bool_type
:
1605 return vis(arg
.value_
.bool_value
);
1606 case detail::type::char_type
:
1607 return vis(arg
.value_
.char_value
);
1608 case detail::type::float_type
:
1609 return vis(arg
.value_
.float_value
);
1610 case detail::type::double_type
:
1611 return vis(arg
.value_
.double_value
);
1612 case detail::type::long_double_type
:
1613 return vis(arg
.value_
.long_double_value
);
1614 case detail::type::cstring_type
:
1615 return vis(arg
.value_
.string
.data
);
1616 case detail::type::string_type
:
1617 using sv
= basic_string_view
<typename
Context::char_type
>;
1618 return vis(sv(arg
.value_
.string
.data
, arg
.value_
.string
.size
));
1619 case detail::type::pointer_type
:
1620 return vis(arg
.value_
.pointer
);
1621 case detail::type::custom_type
:
1622 return vis(typename basic_format_arg
<Context
>::handle(arg
.value_
.custom
));
1624 return vis(monostate());
1627 FMT_BEGIN_DETAIL_NAMESPACE
1629 template <typename Char
, typename InputIt
>
1630 auto copy_str(InputIt begin
, InputIt end
, appender out
) -> appender
{
1631 get_container(out
).append(begin
, end
);
1635 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
1636 // A workaround for gcc 4.8 to make void_t work in a SFINAE context.
1637 template <typename
... Ts
> struct void_t_impl
{ using type
= void; };
1638 template <typename
... Ts
>
1639 using void_t
= typename
detail::void_t_impl
<Ts
...>::type
;
1641 template <typename
...> using void_t
= void;
1644 template <typename It
, typename T
, typename Enable
= void>
1645 struct is_output_iterator
: std::false_type
{};
1647 template <typename It
, typename T
>
1648 struct is_output_iterator
<
1650 void_t
<typename
std::iterator_traits
<It
>::iterator_category
,
1651 decltype(*std::declval
<It
>() = std::declval
<T
>())>>
1652 : std::true_type
{};
1654 template <typename OutputIt
>
1655 struct is_back_insert_iterator
: std::false_type
{};
1656 template <typename Container
>
1657 struct is_back_insert_iterator
<std::back_insert_iterator
<Container
>>
1658 : std::true_type
{};
1660 template <typename OutputIt
>
1661 struct is_contiguous_back_insert_iterator
: std::false_type
{};
1662 template <typename Container
>
1663 struct is_contiguous_back_insert_iterator
<std::back_insert_iterator
<Container
>>
1664 : is_contiguous
<Container
> {};
1666 struct is_contiguous_back_insert_iterator
<appender
> : std::true_type
{};
1668 // A type-erased reference to an std::locale to avoid heavy <locale> include.
1671 const void* locale_
; // A type-erased pointer to std::locale.
1674 constexpr locale_ref() : locale_(nullptr) {}
1675 template <typename Locale
> explicit locale_ref(const Locale
& loc
);
1677 explicit operator bool() const FMT_NOEXCEPT
{ return locale_
!= nullptr; }
1679 template <typename Locale
> auto get() const -> Locale
;
1682 template <typename
> constexpr auto encode_types() -> unsigned long long {
1686 template <typename Context
, typename Arg
, typename
... Args
>
1687 constexpr auto encode_types() -> unsigned long long {
1688 return static_cast<unsigned>(mapped_type_constant
<Arg
, Context
>::value
) |
1689 (encode_types
<Context
, Args
...>() << packed_arg_bits
);
1692 template <typename Context
, typename T
>
1693 FMT_CONSTEXPR
auto make_arg(const T
& value
) -> basic_format_arg
<Context
> {
1694 basic_format_arg
<Context
> arg
;
1695 arg
.type_
= mapped_type_constant
<T
, Context
>::value
;
1696 arg
.value_
= arg_mapper
<Context
>().map(value
);
1700 // The type template parameter is there to avoid an ODR violation when using
1701 // a fallback formatter in one translation unit and an implicit conversion in
1702 // another (not recommended).
1703 template <bool IS_PACKED
, typename Context
, type
, typename T
,
1704 FMT_ENABLE_IF(IS_PACKED
)>
1705 FMT_CONSTEXPR FMT_INLINE
auto make_arg(T
&& val
) -> value
<Context
> {
1706 const auto& arg
= arg_mapper
<Context
>().map(std::forward
<T
>(val
));
1708 constexpr bool formattable_char
=
1709 !std::is_same
<decltype(arg
), const unformattable_char
&>::value
;
1710 static_assert(formattable_char
, "Mixing character types is disallowed.");
1712 constexpr bool formattable_const
=
1713 !std::is_same
<decltype(arg
), const unformattable_const
&>::value
;
1714 static_assert(formattable_const
, "Cannot format a const argument.");
1716 // Formatting of arbitrary pointers is disallowed. If you want to output
1717 // a pointer cast it to "void *" or "const void *". In particular, this
1718 // forbids formatting of "[const] volatile char *" which is printed as bool
1720 constexpr bool formattable_pointer
=
1721 !std::is_same
<decltype(arg
), const unformattable_pointer
&>::value
;
1722 static_assert(formattable_pointer
,
1723 "Formatting of non-void pointers is disallowed.");
1725 constexpr bool formattable
=
1726 !std::is_same
<decltype(arg
), const unformattable
&>::value
;
1729 "Cannot format an argument. To make type T formattable provide a "
1730 "formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
1734 template <bool IS_PACKED
, typename Context
, type
, typename T
,
1735 FMT_ENABLE_IF(!IS_PACKED
)>
1736 inline auto make_arg(const T
& value
) -> basic_format_arg
<Context
> {
1737 return make_arg
<Context
>(value
);
1739 FMT_END_DETAIL_NAMESPACE
1741 // Formatting context.
1742 template <typename OutputIt
, typename Char
> class basic_format_context
{
1744 /** The character type for the output. */
1745 using char_type
= Char
;
1749 basic_format_args
<basic_format_context
> args_
;
1750 detail::locale_ref loc_
;
1753 using iterator
= OutputIt
;
1754 using format_arg
= basic_format_arg
<basic_format_context
>;
1755 using parse_context_type
= basic_format_parse_context
<Char
>;
1756 template <typename T
> using formatter_type
= formatter
<T
, char_type
>;
1758 basic_format_context(basic_format_context
&&) = default;
1759 basic_format_context(const basic_format_context
&) = delete;
1760 void operator=(const basic_format_context
&) = delete;
1762 Constructs a ``basic_format_context`` object. References to the arguments are
1763 stored in the object so make sure they have appropriate lifetimes.
1765 constexpr basic_format_context(
1766 OutputIt out
, basic_format_args
<basic_format_context
> ctx_args
,
1767 detail::locale_ref loc
= detail::locale_ref())
1768 : out_(out
), args_(ctx_args
), loc_(loc
) {}
1770 constexpr auto arg(int id
) const -> format_arg
{ return args_
.get(id
); }
1771 FMT_CONSTEXPR
auto arg(basic_string_view
<char_type
> name
) -> format_arg
{
1772 return args_
.get(name
);
1774 FMT_CONSTEXPR
auto arg_id(basic_string_view
<char_type
> name
) -> int {
1775 return args_
.get_id(name
);
1777 auto args() const -> const basic_format_args
<basic_format_context
>& {
1781 FMT_CONSTEXPR
auto error_handler() -> detail::error_handler
{ return {}; }
1782 void on_error(const char* message
) { error_handler().on_error(message
); }
1784 // Returns an iterator to the beginning of the output range.
1785 FMT_CONSTEXPR
auto out() -> iterator
{ return out_
; }
1787 // Advances the begin iterator to ``it``.
1788 void advance_to(iterator it
) {
1789 if (!detail::is_back_insert_iterator
<iterator
>()) out_
= it
;
1792 FMT_CONSTEXPR
auto locale() -> detail::locale_ref
{ return loc_
; }
1795 template <typename Char
>
1796 using buffer_context
=
1797 basic_format_context
<detail::buffer_appender
<Char
>, Char
>;
1798 using format_context
= buffer_context
<char>;
1800 // Workaround an alias issue: https://stackoverflow.com/q/62767544/471164.
1801 #define FMT_BUFFER_CONTEXT(Char) \
1802 basic_format_context<detail::buffer_appender<Char>, Char>
1804 template <typename T
, typename Char
= char>
1805 using is_formattable
= bool_constant
<
1806 !std::is_base_of
<detail::unformattable
,
1807 decltype(detail::arg_mapper
<buffer_context
<Char
>>().map(
1808 std::declval
<T
>()))>::value
&&
1809 !detail::has_fallback_formatter
<T
, Char
>::value
>;
1813 An array of references to arguments. It can be implicitly converted into
1814 `~fmt::basic_format_args` for passing into type-erased formatting functions
1815 such as `~fmt::vformat`.
1818 template <typename Context
, typename
... Args
>
1819 class format_arg_store
1820 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1821 // Workaround a GCC template argument substitution bug.
1822 : public basic_format_args
<Context
>
1826 static const size_t num_args
= sizeof...(Args
);
1827 static const size_t num_named_args
= detail::count_named_args
<Args
...>();
1828 static const bool is_packed
= num_args
<= detail::max_packed_args
;
1830 using value_type
= conditional_t
<is_packed
, detail::value
<Context
>,
1831 basic_format_arg
<Context
>>;
1833 detail::arg_data
<value_type
, typename
Context::char_type
, num_args
,
1837 friend class basic_format_args
<Context
>;
1839 static constexpr unsigned long long desc
=
1840 (is_packed
? detail::encode_types
<Context
, Args
...>()
1841 : detail::is_unpacked_bit
| num_args
) |
1842 (num_named_args
!= 0
1843 ? static_cast<unsigned long long>(detail::has_named_args_bit
)
1847 template <typename
... T
>
1848 FMT_CONSTEXPR FMT_INLINE
format_arg_store(T
&&... args
)
1850 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1851 basic_format_args
<Context
>(*this),
1853 data_
{detail::make_arg
<
1855 detail::mapped_type_constant
<remove_cvref_t
<T
>, Context
>::value
>(
1856 std::forward
<T
>(args
))...} {
1857 detail::init_named_args(data_
.named_args(), 0, 0, args
...);
1863 Constructs a `~fmt::format_arg_store` object that contains references to
1864 arguments and can be implicitly converted to `~fmt::format_args`. `Context`
1865 can be omitted in which case it defaults to `~fmt::context`.
1866 See `~fmt::arg` for lifetime considerations.
1869 template <typename Context
= format_context
, typename
... Args
>
1870 constexpr auto make_format_args(Args
&&... args
)
1871 -> format_arg_store
<Context
, remove_cvref_t
<Args
>...> {
1872 return {std::forward
<Args
>(args
)...};
1877 Returns a named argument to be used in a formatting function.
1878 It should only be used in a call to a formatting function or
1879 `dynamic_format_arg_store::push_back`.
1883 fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
1886 template <typename Char
, typename T
>
1887 inline auto arg(const Char
* name
, const T
& arg
) -> detail::named_arg
<Char
, T
> {
1888 static_assert(!detail::is_named_arg
<T
>(), "nested named arguments");
1894 A view of a collection of formatting arguments. To avoid lifetime issues it
1895 should only be used as a parameter type in type-erased functions such as
1898 void vlog(string_view format_str, format_args args); // OK
1899 format_args args = make_format_args(42); // Error: dangling reference
1902 template <typename Context
> class basic_format_args
{
1904 using size_type
= int;
1905 using format_arg
= basic_format_arg
<Context
>;
1908 // A descriptor that contains information about formatting arguments.
1909 // If the number of arguments is less or equal to max_packed_args then
1910 // argument types are passed in the descriptor. This reduces binary code size
1911 // per formatting function call.
1912 unsigned long long desc_
;
1914 // If is_packed() returns true then argument values are stored in values_;
1915 // otherwise they are stored in args_. This is done to improve cache
1916 // locality and reduce compiled code size since storing larger objects
1917 // may require more code (at least on x86-64) even if the same amount of
1918 // data is actually copied to stack. It saves ~10% on the bloat test.
1919 const detail::value
<Context
>* values_
;
1920 const format_arg
* args_
;
1923 constexpr auto is_packed() const -> bool {
1924 return (desc_
& detail::is_unpacked_bit
) == 0;
1926 auto has_named_args() const -> bool {
1927 return (desc_
& detail::has_named_args_bit
) != 0;
1930 FMT_CONSTEXPR
auto type(int index
) const -> detail::type
{
1931 int shift
= index
* detail::packed_arg_bits
;
1932 unsigned int mask
= (1 << detail::packed_arg_bits
) - 1;
1933 return static_cast<detail::type
>((desc_
>> shift
) & mask
);
1936 constexpr FMT_INLINE
basic_format_args(unsigned long long desc
,
1937 const detail::value
<Context
>* values
)
1938 : desc_(desc
), values_(values
) {}
1939 constexpr basic_format_args(unsigned long long desc
, const format_arg
* args
)
1940 : desc_(desc
), args_(args
) {}
1943 constexpr basic_format_args() : desc_(0), args_(nullptr) {}
1947 Constructs a `basic_format_args` object from `~fmt::format_arg_store`.
1950 template <typename
... Args
>
1951 constexpr FMT_INLINE
basic_format_args(
1952 const format_arg_store
<Context
, Args
...>& store
)
1953 : basic_format_args(format_arg_store
<Context
, Args
...>::desc
,
1954 store
.data_
.args()) {}
1958 Constructs a `basic_format_args` object from
1959 `~fmt::dynamic_format_arg_store`.
1962 constexpr FMT_INLINE
basic_format_args(
1963 const dynamic_format_arg_store
<Context
>& store
)
1964 : basic_format_args(store
.get_types(), store
.data()) {}
1968 Constructs a `basic_format_args` object from a dynamic set of arguments.
1971 constexpr basic_format_args(const format_arg
* args
, int count
)
1972 : basic_format_args(detail::is_unpacked_bit
| detail::to_unsigned(count
),
1975 /** Returns the argument with the specified id. */
1976 FMT_CONSTEXPR
auto get(int id
) const -> format_arg
{
1979 if (id
< max_size()) arg
= args_
[id
];
1982 if (id
>= detail::max_packed_args
) return arg
;
1983 arg
.type_
= type(id
);
1984 if (arg
.type_
== detail::type::none_type
) return arg
;
1985 arg
.value_
= values_
[id
];
1989 template <typename Char
>
1990 auto get(basic_string_view
<Char
> name
) const -> format_arg
{
1991 int id
= get_id(name
);
1992 return id
>= 0 ? get(id
) : format_arg();
1995 template <typename Char
>
1996 auto get_id(basic_string_view
<Char
> name
) const -> int {
1997 if (!has_named_args()) return -1;
1998 const auto& named_args
=
1999 (is_packed() ? values_
[-1] : args_
[-1].value_
).named_args
;
2000 for (size_t i
= 0; i
< named_args
.size
; ++i
) {
2001 if (named_args
.data
[i
].name
== name
) return named_args
.data
[i
].id
;
2006 auto max_size() const -> int {
2007 unsigned long long max_packed
= detail::max_packed_args
;
2008 return static_cast<int>(is_packed() ? max_packed
2009 : desc_
& ~detail::is_unpacked_bit
);
2013 /** An alias to ``basic_format_args<format_context>``. */
2014 // A separate type would result in shorter symbols but break ABI compatibility
2015 // between clang and gcc on ARM (#1919).
2016 using format_args
= basic_format_args
<format_context
>;
2018 // We cannot use enum classes as bit fields because of a gcc bug
2019 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414.
2021 enum type
{ none
, left
, right
, center
, numeric
};
2023 using align_t
= align::type
;
2025 enum type
{ none
, minus
, plus
, space
};
2027 using sign_t
= sign::type
;
2029 FMT_BEGIN_DETAIL_NAMESPACE
2031 // Workaround an array initialization issue in gcc 4.8.
2032 template <typename Char
> struct fill_t
{
2034 enum { max_size
= 4 };
2035 Char data_
[max_size
] = {Char(' '), Char(0), Char(0), Char(0)};
2036 unsigned char size_
= 1;
2039 FMT_CONSTEXPR
void operator=(basic_string_view
<Char
> s
) {
2040 auto size
= s
.size();
2041 if (size
> max_size
) return throw_format_error("invalid fill");
2042 for (size_t i
= 0; i
< size
; ++i
) data_
[i
] = s
[i
];
2043 size_
= static_cast<unsigned char>(size
);
2046 constexpr auto size() const -> size_t { return size_
; }
2047 constexpr auto data() const -> const Char
* { return data_
; }
2049 FMT_CONSTEXPR
auto operator[](size_t index
) -> Char
& { return data_
[index
]; }
2050 FMT_CONSTEXPR
auto operator[](size_t index
) const -> const Char
& {
2051 return data_
[index
];
2054 FMT_END_DETAIL_NAMESPACE
2056 enum class presentation_type
: unsigned char {
2058 // Integer types should go first,
2065 hexfloat_lower
, // 'a'
2066 hexfloat_upper
, // 'A'
2071 general_lower
, // 'g'
2072 general_upper
, // 'G'
2078 // Format specifiers for built-in and string types.
2079 template <typename Char
> struct basic_format_specs
{
2082 presentation_type type
;
2085 bool alt
: 1; // Alternate form ('#').
2087 detail::fill_t
<Char
> fill
;
2089 constexpr basic_format_specs()
2092 type(presentation_type::none
),
2099 using format_specs
= basic_format_specs
<char>;
2101 FMT_BEGIN_DETAIL_NAMESPACE
2103 enum class arg_id_kind
{ none
, index
, name
};
2105 // An argument reference.
2106 template <typename Char
> struct arg_ref
{
2107 FMT_CONSTEXPR
arg_ref() : kind(arg_id_kind::none
), val() {}
2109 FMT_CONSTEXPR
explicit arg_ref(int index
)
2110 : kind(arg_id_kind::index
), val(index
) {}
2111 FMT_CONSTEXPR
explicit arg_ref(basic_string_view
<Char
> name
)
2112 : kind(arg_id_kind::name
), val(name
) {}
2114 FMT_CONSTEXPR
auto operator=(int idx
) -> arg_ref
& {
2115 kind
= arg_id_kind::index
;
2122 FMT_CONSTEXPR
value(int id
= 0) : index
{id
} {}
2123 FMT_CONSTEXPR
value(basic_string_view
<Char
> n
) : name(n
) {}
2126 basic_string_view
<Char
> name
;
2130 // Format specifiers with width and precision resolved at formatting rather
2131 // than parsing time to allow re-using the same parsed specifiers with
2132 // different sets of arguments (precompilation of format strings).
2133 template <typename Char
>
2134 struct dynamic_format_specs
: basic_format_specs
<Char
> {
2135 arg_ref
<Char
> width_ref
;
2136 arg_ref
<Char
> precision_ref
;
2141 // A format specifier handler that sets fields in basic_format_specs.
2142 template <typename Char
> class specs_setter
{
2144 basic_format_specs
<Char
>& specs_
;
2147 explicit FMT_CONSTEXPR
specs_setter(basic_format_specs
<Char
>& specs
)
2150 FMT_CONSTEXPR
specs_setter(const specs_setter
& other
)
2151 : specs_(other
.specs_
) {}
2153 FMT_CONSTEXPR
void on_align(align_t align
) { specs_
.align
= align
; }
2154 FMT_CONSTEXPR
void on_fill(basic_string_view
<Char
> fill
) {
2157 FMT_CONSTEXPR
void on_sign(sign_t s
) { specs_
.sign
= s
; }
2158 FMT_CONSTEXPR
void on_hash() { specs_
.alt
= true; }
2159 FMT_CONSTEXPR
void on_localized() { specs_
.localized
= true; }
2161 FMT_CONSTEXPR
void on_zero() {
2162 if (specs_
.align
== align::none
) specs_
.align
= align::numeric
;
2163 specs_
.fill
[0] = Char('0');
2166 FMT_CONSTEXPR
void on_width(int width
) { specs_
.width
= width
; }
2167 FMT_CONSTEXPR
void on_precision(int precision
) {
2168 specs_
.precision
= precision
;
2170 FMT_CONSTEXPR
void end_precision() {}
2172 FMT_CONSTEXPR
void on_type(presentation_type type
) { specs_
.type
= type
; }
2175 // Format spec handler that saves references to arguments representing dynamic
2176 // width and precision to be resolved at formatting time.
2177 template <typename ParseContext
>
2178 class dynamic_specs_handler
2179 : public specs_setter
<typename
ParseContext::char_type
> {
2181 using char_type
= typename
ParseContext::char_type
;
2183 FMT_CONSTEXPR
dynamic_specs_handler(dynamic_format_specs
<char_type
>& specs
,
2185 : specs_setter
<char_type
>(specs
), specs_(specs
), context_(ctx
) {}
2187 FMT_CONSTEXPR
dynamic_specs_handler(const dynamic_specs_handler
& other
)
2188 : specs_setter
<char_type
>(other
),
2189 specs_(other
.specs_
),
2190 context_(other
.context_
) {}
2192 template <typename Id
> FMT_CONSTEXPR
void on_dynamic_width(Id arg_id
) {
2193 specs_
.width_ref
= make_arg_ref(arg_id
);
2196 template <typename Id
> FMT_CONSTEXPR
void on_dynamic_precision(Id arg_id
) {
2197 specs_
.precision_ref
= make_arg_ref(arg_id
);
2200 FMT_CONSTEXPR
void on_error(const char* message
) {
2201 context_
.on_error(message
);
2205 dynamic_format_specs
<char_type
>& specs_
;
2206 ParseContext
& context_
;
2208 using arg_ref_type
= arg_ref
<char_type
>;
2210 FMT_CONSTEXPR
auto make_arg_ref(int arg_id
) -> arg_ref_type
{
2211 context_
.check_arg_id(arg_id
);
2212 return arg_ref_type(arg_id
);
2215 FMT_CONSTEXPR
auto make_arg_ref(auto_id
) -> arg_ref_type
{
2216 return arg_ref_type(context_
.next_arg_id());
2219 FMT_CONSTEXPR
auto make_arg_ref(basic_string_view
<char_type
> arg_id
)
2221 context_
.check_arg_id(arg_id
);
2222 basic_string_view
<char_type
> format_str(
2223 context_
.begin(), to_unsigned(context_
.end() - context_
.begin()));
2224 return arg_ref_type(arg_id
);
2228 template <typename Char
> constexpr bool is_ascii_letter(Char c
) {
2229 return (c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z');
2232 // Converts a character to ASCII. Returns a number > 127 on conversion failure.
2233 template <typename Char
, FMT_ENABLE_IF(std::is_integral
<Char
>::value
)>
2234 constexpr auto to_ascii(Char value
) -> Char
{
2237 template <typename Char
, FMT_ENABLE_IF(std::is_enum
<Char
>::value
)>
2238 constexpr auto to_ascii(Char value
) ->
2239 typename
std::underlying_type
<Char
>::type
{
2243 template <typename Char
>
2244 FMT_CONSTEXPR
auto code_point_length(const Char
* begin
) -> int {
2245 if (const_check(sizeof(Char
) != 1)) return 1;
2247 "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4";
2248 int len
= lengths
[static_cast<unsigned char>(*begin
) >> 3];
2250 // Compute the pointer to the next character early so that the next
2251 // iteration can start working on the next character. Neither Clang
2252 // nor GCC figure out this reordering on their own.
2256 // Return the result via the out param to workaround gcc bug 77539.
2257 template <bool IS_CONSTEXPR
, typename T
, typename Ptr
= const T
*>
2258 FMT_CONSTEXPR
auto find(Ptr first
, Ptr last
, T value
, Ptr
& out
) -> bool {
2259 for (out
= first
; out
!= last
; ++out
) {
2260 if (*out
== value
) return true;
2266 inline auto find
<false, char>(const char* first
, const char* last
, char value
,
2267 const char*& out
) -> bool {
2268 out
= static_cast<const char*>(
2269 std::memchr(first
, value
, to_unsigned(last
- first
)));
2270 return out
!= nullptr;
2273 // Parses the range [begin, end) as an unsigned integer. This function assumes
2274 // that the range is non-empty and the first character is a digit.
2275 template <typename Char
>
2276 FMT_CONSTEXPR
auto parse_nonnegative_int(const Char
*& begin
, const Char
* end
,
2277 int error_value
) noexcept
-> int {
2278 FMT_ASSERT(begin
!= end
&& '0' <= *begin
&& *begin
<= '9', "");
2279 unsigned value
= 0, prev
= 0;
2283 value
= value
* 10 + unsigned(*p
- '0');
2285 } while (p
!= end
&& '0' <= *p
&& *p
<= '9');
2286 auto num_digits
= p
- begin
;
2288 if (num_digits
<= std::numeric_limits
<int>::digits10
)
2289 return static_cast<int>(value
);
2290 // Check for overflow.
2291 const unsigned max
= to_unsigned((std::numeric_limits
<int>::max
)());
2292 return num_digits
== std::numeric_limits
<int>::digits10
+ 1 &&
2293 prev
* 10ull + unsigned(p
[-1] - '0') <= max
2294 ? static_cast<int>(value
)
2298 // Parses fill and alignment.
2299 template <typename Char
, typename Handler
>
2300 FMT_CONSTEXPR
auto parse_align(const Char
* begin
, const Char
* end
,
2301 Handler
&& handler
) -> const Char
* {
2302 FMT_ASSERT(begin
!= end
, "");
2303 auto align
= align::none
;
2304 auto p
= begin
+ code_point_length(begin
);
2305 if (p
>= end
) p
= begin
;
2307 switch (to_ascii(*p
)) {
2309 align
= align::left
;
2312 align
= align::right
;
2315 align
= align::center
;
2320 if (align
!= align::none
) {
2324 return handler
.on_error("invalid fill character '{'"), begin
;
2325 handler
.on_fill(basic_string_view
<Char
>(begin
, to_unsigned(p
- begin
)));
2329 handler
.on_align(align
);
2331 } else if (p
== begin
) {
2339 template <typename Char
> FMT_CONSTEXPR
bool is_name_start(Char c
) {
2340 return ('a' <= c
&& c
<= 'z') || ('A' <= c
&& c
<= 'Z') || '_' == c
;
2343 template <typename Char
, typename IDHandler
>
2344 FMT_CONSTEXPR
auto do_parse_arg_id(const Char
* begin
, const Char
* end
,
2345 IDHandler
&& handler
) -> const Char
* {
2346 FMT_ASSERT(begin
!= end
, "");
2348 if (c
>= '0' && c
<= '9') {
2352 parse_nonnegative_int(begin
, end
, (std::numeric_limits
<int>::max
)());
2355 if (begin
== end
|| (*begin
!= '}' && *begin
!= ':'))
2356 handler
.on_error("invalid format string");
2361 if (!is_name_start(c
)) {
2362 handler
.on_error("invalid format string");
2368 } while (it
!= end
&& (is_name_start(c
= *it
) || ('0' <= c
&& c
<= '9')));
2369 handler(basic_string_view
<Char
>(begin
, to_unsigned(it
- begin
)));
2373 template <typename Char
, typename IDHandler
>
2374 FMT_CONSTEXPR FMT_INLINE
auto parse_arg_id(const Char
* begin
, const Char
* end
,
2375 IDHandler
&& handler
) -> const Char
* {
2377 if (c
!= '}' && c
!= ':') return do_parse_arg_id(begin
, end
, handler
);
2382 template <typename Char
, typename Handler
>
2383 FMT_CONSTEXPR
auto parse_width(const Char
* begin
, const Char
* end
,
2384 Handler
&& handler
) -> const Char
* {
2385 using detail::auto_id
;
2386 struct width_adapter
{
2389 FMT_CONSTEXPR
void operator()() { handler
.on_dynamic_width(auto_id()); }
2390 FMT_CONSTEXPR
void operator()(int id
) { handler
.on_dynamic_width(id
); }
2391 FMT_CONSTEXPR
void operator()(basic_string_view
<Char
> id
) {
2392 handler
.on_dynamic_width(id
);
2394 FMT_CONSTEXPR
void on_error(const char* message
) {
2395 if (message
) handler
.on_error(message
);
2399 FMT_ASSERT(begin
!= end
, "");
2400 if ('0' <= *begin
&& *begin
<= '9') {
2401 int width
= parse_nonnegative_int(begin
, end
, -1);
2403 handler
.on_width(width
);
2405 handler
.on_error("number is too big");
2406 } else if (*begin
== '{') {
2408 if (begin
!= end
) begin
= parse_arg_id(begin
, end
, width_adapter
{handler
});
2409 if (begin
== end
|| *begin
!= '}')
2410 return handler
.on_error("invalid format string"), begin
;
2416 template <typename Char
, typename Handler
>
2417 FMT_CONSTEXPR
auto parse_precision(const Char
* begin
, const Char
* end
,
2418 Handler
&& handler
) -> const Char
* {
2419 using detail::auto_id
;
2420 struct precision_adapter
{
2423 FMT_CONSTEXPR
void operator()() { handler
.on_dynamic_precision(auto_id()); }
2424 FMT_CONSTEXPR
void operator()(int id
) { handler
.on_dynamic_precision(id
); }
2425 FMT_CONSTEXPR
void operator()(basic_string_view
<Char
> id
) {
2426 handler
.on_dynamic_precision(id
);
2428 FMT_CONSTEXPR
void on_error(const char* message
) {
2429 if (message
) handler
.on_error(message
);
2434 auto c
= begin
!= end
? *begin
: Char();
2435 if ('0' <= c
&& c
<= '9') {
2436 auto precision
= parse_nonnegative_int(begin
, end
, -1);
2437 if (precision
!= -1)
2438 handler
.on_precision(precision
);
2440 handler
.on_error("number is too big");
2441 } else if (c
== '{') {
2444 begin
= parse_arg_id(begin
, end
, precision_adapter
{handler
});
2445 if (begin
== end
|| *begin
++ != '}')
2446 return handler
.on_error("invalid format string"), begin
;
2448 return handler
.on_error("missing precision specifier"), begin
;
2450 handler
.end_precision();
2454 template <typename Char
>
2455 FMT_CONSTEXPR
auto parse_presentation_type(Char type
) -> presentation_type
{
2456 switch (to_ascii(type
)) {
2458 return presentation_type::dec
;
2460 return presentation_type::oct
;
2462 return presentation_type::hex_lower
;
2464 return presentation_type::hex_upper
;
2466 return presentation_type::bin_lower
;
2468 return presentation_type::bin_upper
;
2470 return presentation_type::hexfloat_lower
;
2472 return presentation_type::hexfloat_upper
;
2474 return presentation_type::exp_lower
;
2476 return presentation_type::exp_upper
;
2478 return presentation_type::fixed_lower
;
2480 return presentation_type::fixed_upper
;
2482 return presentation_type::general_lower
;
2484 return presentation_type::general_upper
;
2486 return presentation_type::chr
;
2488 return presentation_type::string
;
2490 return presentation_type::pointer
;
2492 return presentation_type::none
;
2496 // Parses standard format specifiers and sends notifications about parsed
2497 // components to handler.
2498 template <typename Char
, typename SpecHandler
>
2499 FMT_CONSTEXPR FMT_INLINE
auto parse_format_specs(const Char
* begin
,
2501 SpecHandler
&& handler
)
2503 if (1 < end
- begin
&& begin
[1] == '}' && is_ascii_letter(*begin
) &&
2505 presentation_type type
= parse_presentation_type(*begin
++);
2506 if (type
== presentation_type::none
)
2507 handler
.on_error("invalid type specifier");
2508 handler
.on_type(type
);
2512 if (begin
== end
) return begin
;
2514 begin
= parse_align(begin
, end
, handler
);
2515 if (begin
== end
) return begin
;
2518 switch (to_ascii(*begin
)) {
2520 handler
.on_sign(sign::plus
);
2524 handler
.on_sign(sign::minus
);
2528 handler
.on_sign(sign::space
);
2534 if (begin
== end
) return begin
;
2536 if (*begin
== '#') {
2538 if (++begin
== end
) return begin
;
2542 if (*begin
== '0') {
2544 if (++begin
== end
) return begin
;
2547 begin
= parse_width(begin
, end
, handler
);
2548 if (begin
== end
) return begin
;
2551 if (*begin
== '.') {
2552 begin
= parse_precision(begin
, end
, handler
);
2553 if (begin
== end
) return begin
;
2556 if (*begin
== 'L') {
2557 handler
.on_localized();
2562 if (begin
!= end
&& *begin
!= '}') {
2563 presentation_type type
= parse_presentation_type(*begin
++);
2564 if (type
== presentation_type::none
)
2565 handler
.on_error("invalid type specifier");
2566 handler
.on_type(type
);
2571 template <typename Char
, typename Handler
>
2572 FMT_CONSTEXPR
auto parse_replacement_field(const Char
* begin
, const Char
* end
,
2573 Handler
&& handler
) -> const Char
* {
2578 FMT_CONSTEXPR
void operator()() { arg_id
= handler
.on_arg_id(); }
2579 FMT_CONSTEXPR
void operator()(int id
) { arg_id
= handler
.on_arg_id(id
); }
2580 FMT_CONSTEXPR
void operator()(basic_string_view
<Char
> id
) {
2581 arg_id
= handler
.on_arg_id(id
);
2583 FMT_CONSTEXPR
void on_error(const char* message
) {
2584 if (message
) handler
.on_error(message
);
2589 if (begin
== end
) return handler
.on_error("invalid format string"), end
;
2590 if (*begin
== '}') {
2591 handler
.on_replacement_field(handler
.on_arg_id(), begin
);
2592 } else if (*begin
== '{') {
2593 handler
.on_text(begin
, begin
+ 1);
2595 auto adapter
= id_adapter
{handler
, 0};
2596 begin
= parse_arg_id(begin
, end
, adapter
);
2597 Char c
= begin
!= end
? *begin
: Char();
2599 handler
.on_replacement_field(adapter
.arg_id
, begin
);
2600 } else if (c
== ':') {
2601 begin
= handler
.on_format_specs(adapter
.arg_id
, begin
+ 1, end
);
2602 if (begin
== end
|| *begin
!= '}')
2603 return handler
.on_error("unknown format specifier"), end
;
2605 return handler
.on_error("missing '}' in format string"), end
;
2611 template <bool IS_CONSTEXPR
, typename Char
, typename Handler
>
2612 FMT_CONSTEXPR FMT_INLINE
void parse_format_string(
2613 basic_string_view
<Char
> format_str
, Handler
&& handler
) {
2614 // Workaround a name-lookup bug in MSVC's modules implementation.
2617 auto begin
= format_str
.data();
2618 auto end
= begin
+ format_str
.size();
2619 if (end
- begin
< 32) {
2620 // Use a simple loop instead of memchr for small strings.
2621 const Char
* p
= begin
;
2625 handler
.on_text(begin
, p
- 1);
2626 begin
= p
= parse_replacement_field(p
- 1, end
, handler
);
2627 } else if (c
== '}') {
2628 if (p
== end
|| *p
!= '}')
2629 return handler
.on_error("unmatched '}' in format string");
2630 handler
.on_text(begin
, p
);
2634 handler
.on_text(begin
, end
);
2638 FMT_CONSTEXPR
void operator()(const Char
* pbegin
, const Char
* pend
) {
2639 if (pbegin
== pend
) return;
2641 const Char
* p
= nullptr;
2642 if (!find
<IS_CONSTEXPR
>(pbegin
, pend
, Char('}'), p
))
2643 return handler_
.on_text(pbegin
, pend
);
2645 if (p
== pend
|| *p
!= '}')
2646 return handler_
.on_error("unmatched '}' in format string");
2647 handler_
.on_text(pbegin
, p
);
2653 while (begin
!= end
) {
2654 // Doing two passes with memchr (one for '{' and another for '}') is up to
2655 // 2.5x faster than the naive one-pass implementation on big format strings.
2656 const Char
* p
= begin
;
2657 if (*begin
!= '{' && !find
<IS_CONSTEXPR
>(begin
+ 1, end
, Char('{'), p
))
2658 return write(begin
, end
);
2660 begin
= parse_replacement_field(p
, end
, handler
);
2664 template <typename T
, typename ParseContext
>
2665 FMT_CONSTEXPR
auto parse_format_specs(ParseContext
& ctx
)
2666 -> decltype(ctx
.begin()) {
2667 using char_type
= typename
ParseContext::char_type
;
2668 using context
= buffer_context
<char_type
>;
2669 using mapped_type
= conditional_t
<
2670 mapped_type_constant
<T
, context
>::value
!= type::custom_type
,
2671 decltype(arg_mapper
<context
>().map(std::declval
<const T
&>())), T
>;
2672 auto f
= conditional_t
<has_formatter
<mapped_type
, context
>::value
,
2673 formatter
<mapped_type
, char_type
>,
2674 fallback_formatter
<T
, char_type
>>();
2675 return f
.parse(ctx
);
2678 // A parse context with extra argument id checks. It is only used at compile
2679 // time because adding checks at runtime would introduce substantial overhead
2680 // and would be redundant since argument ids are checked when arguments are
2681 // retrieved anyway.
2682 template <typename Char
, typename ErrorHandler
= error_handler
>
2683 class compile_parse_context
2684 : public basic_format_parse_context
<Char
, ErrorHandler
> {
2687 using base
= basic_format_parse_context
<Char
, ErrorHandler
>;
2690 explicit FMT_CONSTEXPR
compile_parse_context(
2691 basic_string_view
<Char
> format_str
,
2692 int num_args
= (std::numeric_limits
<int>::max
)(), ErrorHandler eh
= {})
2693 : base(format_str
, eh
), num_args_(num_args
) {}
2695 FMT_CONSTEXPR
auto next_arg_id() -> int {
2696 int id
= base::next_arg_id();
2697 if (id
>= num_args_
) this->on_error("argument not found");
2701 FMT_CONSTEXPR
void check_arg_id(int id
) {
2702 base::check_arg_id(id
);
2703 if (id
>= num_args_
) this->on_error("argument not found");
2705 using base::check_arg_id
;
2708 template <typename ErrorHandler
>
2709 FMT_CONSTEXPR
void check_int_type_spec(presentation_type type
,
2710 ErrorHandler
&& eh
) {
2711 if (type
> presentation_type::bin_upper
&& type
!= presentation_type::chr
)
2712 eh
.on_error("invalid type specifier");
2715 // Checks char specs and returns true if the type spec is char (and not int).
2716 template <typename Char
, typename ErrorHandler
= error_handler
>
2717 FMT_CONSTEXPR
auto check_char_specs(const basic_format_specs
<Char
>& specs
,
2718 ErrorHandler
&& eh
= {}) -> bool {
2719 if (specs
.type
!= presentation_type::none
&&
2720 specs
.type
!= presentation_type::chr
) {
2721 check_int_type_spec(specs
.type
, eh
);
2724 if (specs
.align
== align::numeric
|| specs
.sign
!= sign::none
|| specs
.alt
)
2725 eh
.on_error("invalid format specifier for char");
2729 // A floating-point presentation format.
2730 enum class float_format
: unsigned char {
2731 general
, // General: exponent notation or fixed point based on magnitude.
2732 exp
, // Exponent notation with the default precision of 6, e.g. 1.2e-3.
2733 fixed
, // Fixed point with the default precision of 6, e.g. 0.0012.
2737 struct float_specs
{
2739 float_format format
: 8;
2748 template <typename ErrorHandler
= error_handler
, typename Char
>
2749 FMT_CONSTEXPR
auto parse_float_type_spec(const basic_format_specs
<Char
>& specs
,
2750 ErrorHandler
&& eh
= {})
2752 auto result
= float_specs();
2753 result
.showpoint
= specs
.alt
;
2754 result
.locale
= specs
.localized
;
2755 switch (specs
.type
) {
2756 case presentation_type::none
:
2757 result
.format
= float_format::general
;
2759 case presentation_type::general_upper
:
2760 result
.upper
= true;
2762 case presentation_type::general_lower
:
2763 result
.format
= float_format::general
;
2765 case presentation_type::exp_upper
:
2766 result
.upper
= true;
2768 case presentation_type::exp_lower
:
2769 result
.format
= float_format::exp
;
2770 result
.showpoint
|= specs
.precision
!= 0;
2772 case presentation_type::fixed_upper
:
2773 result
.upper
= true;
2775 case presentation_type::fixed_lower
:
2776 result
.format
= float_format::fixed
;
2777 result
.showpoint
|= specs
.precision
!= 0;
2779 case presentation_type::hexfloat_upper
:
2780 result
.upper
= true;
2782 case presentation_type::hexfloat_lower
:
2783 result
.format
= float_format::hex
;
2786 eh
.on_error("invalid type specifier");
2792 template <typename ErrorHandler
= error_handler
>
2793 FMT_CONSTEXPR
auto check_cstring_type_spec(presentation_type type
,
2794 ErrorHandler
&& eh
= {}) -> bool {
2795 if (type
== presentation_type::none
|| type
== presentation_type::string
)
2797 if (type
!= presentation_type::pointer
) eh
.on_error("invalid type specifier");
2801 template <typename ErrorHandler
= error_handler
>
2802 FMT_CONSTEXPR
void check_string_type_spec(presentation_type type
,
2803 ErrorHandler
&& eh
= {}) {
2804 if (type
!= presentation_type::none
&& type
!= presentation_type::string
)
2805 eh
.on_error("invalid type specifier");
2808 template <typename ErrorHandler
>
2809 FMT_CONSTEXPR
void check_pointer_type_spec(presentation_type type
,
2810 ErrorHandler
&& eh
) {
2811 if (type
!= presentation_type::none
&& type
!= presentation_type::pointer
)
2812 eh
.on_error("invalid type specifier");
2815 // A parse_format_specs handler that checks if specifiers are consistent with
2816 // the argument type.
2817 template <typename Handler
> class specs_checker
: public Handler
{
2819 detail::type arg_type_
;
2821 FMT_CONSTEXPR
void require_numeric_argument() {
2822 if (!is_arithmetic_type(arg_type_
))
2823 this->on_error("format specifier requires numeric argument");
2827 FMT_CONSTEXPR
specs_checker(const Handler
& handler
, detail::type arg_type
)
2828 : Handler(handler
), arg_type_(arg_type
) {}
2830 FMT_CONSTEXPR
void on_align(align_t align
) {
2831 if (align
== align::numeric
) require_numeric_argument();
2832 Handler::on_align(align
);
2835 FMT_CONSTEXPR
void on_sign(sign_t s
) {
2836 require_numeric_argument();
2837 if (is_integral_type(arg_type_
) && arg_type_
!= type::int_type
&&
2838 arg_type_
!= type::long_long_type
&& arg_type_
!= type::char_type
) {
2839 this->on_error("format specifier requires signed argument");
2841 Handler::on_sign(s
);
2844 FMT_CONSTEXPR
void on_hash() {
2845 require_numeric_argument();
2849 FMT_CONSTEXPR
void on_localized() {
2850 require_numeric_argument();
2851 Handler::on_localized();
2854 FMT_CONSTEXPR
void on_zero() {
2855 require_numeric_argument();
2859 FMT_CONSTEXPR
void end_precision() {
2860 if (is_integral_type(arg_type_
) || arg_type_
== type::pointer_type
)
2861 this->on_error("precision not allowed for this argument type");
2865 constexpr int invalid_arg_index
= -1;
2867 #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
2868 template <int N
, typename T
, typename
... Args
, typename Char
>
2869 constexpr auto get_arg_index_by_name(basic_string_view
<Char
> name
) -> int {
2870 if constexpr (detail::is_statically_named_arg
<T
>()) {
2871 if (name
== T::name
) return N
;
2873 if constexpr (sizeof...(Args
) > 0)
2874 return get_arg_index_by_name
<N
+ 1, Args
...>(name
);
2875 (void)name
; // Workaround an MSVC bug about "unused" parameter.
2876 return invalid_arg_index
;
2880 template <typename
... Args
, typename Char
>
2881 FMT_CONSTEXPR
auto get_arg_index_by_name(basic_string_view
<Char
> name
) -> int {
2882 #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
2883 if constexpr (sizeof...(Args
) > 0)
2884 return get_arg_index_by_name
<0, Args
...>(name
);
2887 return invalid_arg_index
;
2890 template <typename Char
, typename ErrorHandler
, typename
... Args
>
2891 class format_string_checker
{
2893 using parse_context_type
= compile_parse_context
<Char
, ErrorHandler
>;
2894 enum { num_args
= sizeof...(Args
) };
2896 // Format specifier parsing function.
2897 using parse_func
= const Char
* (*)(parse_context_type
&);
2899 parse_context_type context_
;
2900 parse_func parse_funcs_
[num_args
> 0 ? num_args
: 1];
2903 explicit FMT_CONSTEXPR
format_string_checker(
2904 basic_string_view
<Char
> format_str
, ErrorHandler eh
)
2905 : context_(format_str
, num_args
, eh
),
2906 parse_funcs_
{&parse_format_specs
<Args
, parse_context_type
>...} {}
2908 FMT_CONSTEXPR
void on_text(const Char
*, const Char
*) {}
2910 FMT_CONSTEXPR
auto on_arg_id() -> int { return context_
.next_arg_id(); }
2911 FMT_CONSTEXPR
auto on_arg_id(int id
) -> int {
2912 return context_
.check_arg_id(id
), id
;
2914 FMT_CONSTEXPR
auto on_arg_id(basic_string_view
<Char
> id
) -> int {
2915 #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
2916 auto index
= get_arg_index_by_name
<Args
...>(id
);
2917 if (index
== invalid_arg_index
) on_error("named argument is not found");
2918 return context_
.check_arg_id(index
), index
;
2921 on_error("compile-time checks for named arguments require C++20 support");
2926 FMT_CONSTEXPR
void on_replacement_field(int, const Char
*) {}
2928 FMT_CONSTEXPR
auto on_format_specs(int id
, const Char
* begin
, const Char
*)
2930 context_
.advance_to(context_
.begin() + (begin
- &*context_
.begin()));
2931 // id >= 0 check is a workaround for gcc 10 bug (#2065).
2932 return id
>= 0 && id
< num_args
? parse_funcs_
[id
](context_
) : begin
;
2935 FMT_CONSTEXPR
void on_error(const char* message
) {
2936 context_
.on_error(message
);
2940 template <typename
... Args
, typename S
,
2941 enable_if_t
<(is_compile_string
<S
>::value
), int>>
2942 void check_format_string(S format_str
) {
2943 FMT_CONSTEXPR
auto s
= to_string_view(format_str
);
2944 using checker
= format_string_checker
<typename
S::char_type
, error_handler
,
2945 remove_cvref_t
<Args
>...>;
2946 FMT_CONSTEXPR
bool invalid_format
=
2947 (parse_format_string
<true>(s
, checker(s
, {})), true);
2948 ignore_unused(invalid_format
);
2951 template <typename Char
>
2953 buffer
<Char
>& buf
, basic_string_view
<Char
> fmt
,
2954 basic_format_args
<FMT_BUFFER_CONTEXT(type_identity_t
<Char
>)> args
,
2955 locale_ref loc
= {});
2957 FMT_API
void vprint_mojibake(std::FILE*, string_view
, format_args
);
2959 inline void vprint_mojibake(std::FILE*, string_view
, format_args
) {}
2961 FMT_END_DETAIL_NAMESPACE
2963 // A formatter specialization for the core types corresponding to detail::type
2965 template <typename T
, typename Char
>
2966 struct formatter
<T
, Char
,
2967 enable_if_t
<detail::type_constant
<T
, Char
>::value
!=
2968 detail::type::custom_type
>> {
2970 detail::dynamic_format_specs
<Char
> specs_
;
2973 // Parses format specifiers stopping either at the end of the range or at the
2975 template <typename ParseContext
>
2976 FMT_CONSTEXPR
auto parse(ParseContext
& ctx
) -> decltype(ctx
.begin()) {
2977 auto begin
= ctx
.begin(), end
= ctx
.end();
2978 if (begin
== end
) return begin
;
2979 using handler_type
= detail::dynamic_specs_handler
<ParseContext
>;
2980 auto type
= detail::type_constant
<T
, Char
>::value
;
2982 detail::specs_checker
<handler_type
>(handler_type(specs_
, ctx
), type
);
2983 auto it
= detail::parse_format_specs(begin
, end
, checker
);
2984 auto eh
= ctx
.error_handler();
2986 case detail::type::none_type
:
2987 FMT_ASSERT(false, "invalid argument type");
2989 case detail::type::bool_type
:
2990 if (specs_
.type
== presentation_type::none
||
2991 specs_
.type
== presentation_type::string
) {
2995 case detail::type::int_type
:
2996 case detail::type::uint_type
:
2997 case detail::type::long_long_type
:
2998 case detail::type::ulong_long_type
:
2999 case detail::type::int128_type
:
3000 case detail::type::uint128_type
:
3001 detail::check_int_type_spec(specs_
.type
, eh
);
3003 case detail::type::char_type
:
3004 detail::check_char_specs(specs_
, eh
);
3006 case detail::type::float_type
:
3007 if (detail::const_check(FMT_USE_FLOAT
))
3008 detail::parse_float_type_spec(specs_
, eh
);
3010 FMT_ASSERT(false, "float support disabled");
3012 case detail::type::double_type
:
3013 if (detail::const_check(FMT_USE_DOUBLE
))
3014 detail::parse_float_type_spec(specs_
, eh
);
3016 FMT_ASSERT(false, "double support disabled");
3018 case detail::type::long_double_type
:
3019 if (detail::const_check(FMT_USE_LONG_DOUBLE
))
3020 detail::parse_float_type_spec(specs_
, eh
);
3022 FMT_ASSERT(false, "long double support disabled");
3024 case detail::type::cstring_type
:
3025 detail::check_cstring_type_spec(specs_
.type
, eh
);
3027 case detail::type::string_type
:
3028 detail::check_string_type_spec(specs_
.type
, eh
);
3030 case detail::type::pointer_type
:
3031 detail::check_pointer_type_spec(specs_
.type
, eh
);
3033 case detail::type::custom_type
:
3034 // Custom format specifiers are checked in parse functions of
3035 // formatter specializations.
3041 template <typename FormatContext
>
3042 FMT_CONSTEXPR
auto format(const T
& val
, FormatContext
& ctx
) const
3043 -> decltype(ctx
.out());
3046 template <typename Char
> struct basic_runtime
{ basic_string_view
<Char
> str
; };
3048 /** A compile-time format string. */
3049 template <typename Char
, typename
... Args
> class basic_format_string
{
3051 basic_string_view
<Char
> str_
;
3054 template <typename S
,
3056 std::is_convertible
<const S
&, basic_string_view
<Char
>>::value
)>
3057 FMT_CONSTEVAL FMT_INLINE
basic_format_string(const S
& s
) : str_(s
) {
3060 (std::is_base_of
<detail::view
, remove_reference_t
<Args
>>::value
&&
3061 std::is_reference
<Args
>::value
)...>() == 0,
3062 "passing views as lvalues is disallowed");
3063 #ifdef FMT_HAS_CONSTEVAL
3064 if constexpr (detail::count_named_args
<Args
...>() ==
3065 detail::count_statically_named_args
<Args
...>()) {
3066 using checker
= detail::format_string_checker
<Char
, detail::error_handler
,
3067 remove_cvref_t
<Args
>...>;
3068 detail::parse_format_string
<true>(str_
, checker(s
, {}));
3071 detail::check_format_string
<Args
...>(s
);
3074 basic_format_string(basic_runtime
<Char
> r
) : str_(r
.str
) {}
3076 FMT_INLINE
operator basic_string_view
<Char
>() const { return str_
; }
3079 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
3080 // Workaround broken conversion on older gcc.
3081 template <typename
... Args
> using format_string
= string_view
;
3082 template <typename S
> auto runtime(const S
& s
) -> basic_string_view
<char_t
<S
>> {
3086 template <typename
... Args
>
3087 using format_string
= basic_format_string
<char, type_identity_t
<Args
>...>;
3090 Creates a runtime format string.
3094 // Check format string at runtime instead of compile-time.
3095 fmt::print(fmt::runtime("{:d}"), "I am not a number");
3098 template <typename S
> auto runtime(const S
& s
) -> basic_runtime
<char_t
<S
>> {
3103 FMT_API
auto vformat(string_view fmt
, format_args args
) -> std::string
;
3107 Formats ``args`` according to specifications in ``fmt`` and returns the result
3112 #include <fmt/core.h>
3113 std::string message = fmt::format("The answer is {}.", 42);
3116 template <typename
... T
>
3117 FMT_NODISCARD FMT_INLINE
auto format(format_string
<T
...> fmt
, T
&&... args
)
3119 return vformat(fmt
, fmt::make_format_args(args
...));
3122 /** Formats a string and writes the output to ``out``. */
3123 template <typename OutputIt
,
3124 FMT_ENABLE_IF(detail::is_output_iterator
<OutputIt
, char>::value
)>
3125 auto vformat_to(OutputIt out
, string_view fmt
, format_args args
) -> OutputIt
{
3126 using detail::get_buffer
;
3127 auto&& buf
= get_buffer
<char>(out
);
3128 detail::vformat_to(buf
, fmt
, args
, {});
3129 return detail::get_iterator(buf
);
3134 Formats ``args`` according to specifications in ``fmt``, writes the result to
3135 the output iterator ``out`` and returns the iterator past the end of the output
3136 range. `format_to` does not append a terminating null character.
3140 auto out = std::vector<char>();
3141 fmt::format_to(std::back_inserter(out), "{}", 42);
3144 template <typename OutputIt
, typename
... T
,
3145 FMT_ENABLE_IF(detail::is_output_iterator
<OutputIt
, char>::value
)>
3146 FMT_INLINE
auto format_to(OutputIt out
, format_string
<T
...> fmt
, T
&&... args
)
3148 return vformat_to(out
, fmt
, fmt::make_format_args(args
...));
3151 template <typename OutputIt
> struct format_to_n_result
{
3152 /** Iterator past the end of the output range. */
3154 /** Total (not truncated) output size. */
3158 template <typename OutputIt
, typename
... T
,
3159 FMT_ENABLE_IF(detail::is_output_iterator
<OutputIt
, char>::value
)>
3160 auto vformat_to_n(OutputIt out
, size_t n
, string_view fmt
, format_args args
)
3161 -> format_to_n_result
<OutputIt
> {
3162 using traits
= detail::fixed_buffer_traits
;
3163 auto buf
= detail::iterator_buffer
<OutputIt
, char, traits
>(out
, n
);
3164 detail::vformat_to(buf
, fmt
, args
, {});
3165 return {buf
.out(), buf
.count()};
3170 Formats ``args`` according to specifications in ``fmt``, writes up to ``n``
3171 characters of the result to the output iterator ``out`` and returns the total
3172 (not truncated) output size and the iterator past the end of the output range.
3173 `format_to_n` does not append a terminating null character.
3176 template <typename OutputIt
, typename
... T
,
3177 FMT_ENABLE_IF(detail::is_output_iterator
<OutputIt
, char>::value
)>
3178 FMT_INLINE
auto format_to_n(OutputIt out
, size_t n
, format_string
<T
...> fmt
,
3179 T
&&... args
) -> format_to_n_result
<OutputIt
> {
3180 return vformat_to_n(out
, n
, fmt
, fmt::make_format_args(args
...));
3183 /** Returns the number of chars in the output of ``format(fmt, args...)``. */
3184 template <typename
... T
>
3185 FMT_NODISCARD FMT_INLINE
auto formatted_size(format_string
<T
...> fmt
,
3186 T
&&... args
) -> size_t {
3187 auto buf
= detail::counting_buffer
<>();
3188 detail::vformat_to(buf
, string_view(fmt
), fmt::make_format_args(args
...), {});
3192 FMT_API
void vprint(string_view fmt
, format_args args
);
3193 FMT_API
void vprint(std::FILE* f
, string_view fmt
, format_args args
);
3197 Formats ``args`` according to specifications in ``fmt`` and writes the output
3202 fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
3205 template <typename
... T
>
3206 FMT_INLINE
void print(format_string
<T
...> fmt
, T
&&... args
) {
3207 const auto& vargs
= fmt::make_format_args(args
...);
3208 return detail::is_utf8() ? vprint(fmt
, vargs
)
3209 : detail::vprint_mojibake(stdout
, fmt
, vargs
);
3214 Formats ``args`` according to specifications in ``fmt`` and writes the
3215 output to the file ``f``.
3219 fmt::print(stderr, "Don't {}!", "panic");
3222 template <typename
... T
>
3223 FMT_INLINE
void print(std::FILE* f
, format_string
<T
...> fmt
, T
&&... args
) {
3224 const auto& vargs
= fmt::make_format_args(args
...);
3225 return detail::is_utf8() ? vprint(f
, fmt
, vargs
)
3226 : detail::vprint_mojibake(f
, fmt
, vargs
);
3229 FMT_MODULE_EXPORT_END
3230 FMT_GCC_PRAGMA("GCC pop_options")
3233 #ifdef FMT_HEADER_ONLY
3234 # include "format.h"
3236 #endif // FMT_CORE_H_