Add vendor/fmt
[lttng-tools.git] / src / vendor / fmt / core.h
CommitLineData
05aa7e19
JG
1// Formatting library for C++ - the core API for char/UTF-8
2//
3// Copyright (c) 2012 - present, Victor Zverovich
4// All rights reserved.
5//
6// For the license information refer to format.h.
7
8#ifndef FMT_CORE_H_
9#define FMT_CORE_H_
10
11#include <cstddef> // std::byte
12#include <cstdio> // std::FILE
13#include <cstring>
14#include <iterator>
15#include <limits>
16#include <string>
17#include <type_traits>
18
19// The fmt library version in the form major * 10000 + minor * 100 + patch.
20#define FMT_VERSION 80101
21
22#if defined(__clang__) && !defined(__ibmxl__)
23# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
24#else
25# define FMT_CLANG_VERSION 0
26#endif
27
28#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && \
29 !defined(__NVCOMPILER)
30# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
31#else
32# define FMT_GCC_VERSION 0
33#endif
34
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)
39# else
40# define FMT_GCC_PRAGMA(arg)
41# endif
42#endif
43
44#ifdef __ICL
45# define FMT_ICC_VERSION __ICL
46#elif defined(__INTEL_COMPILER)
47# define FMT_ICC_VERSION __INTEL_COMPILER
48#else
49# define FMT_ICC_VERSION 0
50#endif
51
52#ifdef __NVCC__
53# define FMT_NVCC __NVCC__
54#else
55# define FMT_NVCC 0
56#endif
57
58#ifdef _MSC_VER
59# define FMT_MSC_VER _MSC_VER
60# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__))
61#else
62# define FMT_MSC_VER 0
63# define FMT_MSC_WARNING(...)
64#endif
65
66#ifdef __has_feature
67# define FMT_HAS_FEATURE(x) __has_feature(x)
68#else
69# define FMT_HAS_FEATURE(x) 0
70#endif
71
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)
76#else
77# define FMT_HAS_INCLUDE(x) 0
78#endif
79
80#ifdef __has_cpp_attribute
81# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
82#else
83# define FMT_HAS_CPP_ATTRIBUTE(x) 0
84#endif
85
86#ifdef _MSVC_LANG
87# define FMT_CPLUSPLUS _MSVC_LANG
88#else
89# define FMT_CPLUSPLUS __cplusplus
90#endif
91
92#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
93 (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
94
95#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
96 (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
97
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
105#endif
106#if FMT_USE_CONSTEXPR
107# define FMT_CONSTEXPR constexpr
108# define FMT_CONSTEXPR_DECL constexpr
109#else
110# define FMT_CONSTEXPR
111# define FMT_CONSTEXPR_DECL
112#endif
113
114#if ((__cplusplus >= 202002L) && \
115 (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 9)) || \
116 (__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002)
117# define FMT_CONSTEXPR20 constexpr
118#else
119# define FMT_CONSTEXPR20
120#endif
121
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
127# endif
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
133#endif
134#ifndef FMT_CONSTEXPR_CHAR_TRAITS
135# define FMT_CONSTEXPR_CHAR_TRAITS
136#endif
137
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
143# else
144# define FMT_EXCEPTIONS 1
145# endif
146#endif
147
148// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature).
149#ifndef FMT_USE_NOEXCEPT
150# define FMT_USE_NOEXCEPT 0
151#endif
152
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
157#else
158# define FMT_DETECTED_NOEXCEPT throw()
159# define FMT_HAS_CXX11_NOEXCEPT 0
160#endif
161
162#ifndef FMT_NOEXCEPT
163# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT
164# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT
165# else
166# define FMT_NOEXCEPT
167# endif
168#endif
169
170// [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code
171// warnings.
172#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \
173 !FMT_NVCC
174# define FMT_NORETURN [[noreturn]]
175#else
176# define FMT_NORETURN
177#endif
178
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]]
187# else
188# define FMT_FALLTHROUGH
189# endif
190#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough)
191# define FMT_FALLTHROUGH [[fallthrough]]
192#else
193# define FMT_FALLTHROUGH
194#endif
195
196#ifndef FMT_NODISCARD
197# if FMT_HAS_CPP17_ATTRIBUTE(nodiscard)
198# define FMT_NODISCARD [[nodiscard]]
199# else
200# define FMT_NODISCARD
201# endif
202#endif
203
204#ifndef FMT_USE_FLOAT
205# define FMT_USE_FLOAT 1
206#endif
207#ifndef FMT_USE_DOUBLE
208# define FMT_USE_DOUBLE 1
209#endif
210#ifndef FMT_USE_LONG_DOUBLE
211# define FMT_USE_LONG_DOUBLE 1
212#endif
213
214#ifndef FMT_INLINE
215# if FMT_GCC_VERSION || FMT_CLANG_VERSION
216# define FMT_INLINE inline __attribute__((always_inline))
217# else
218# define FMT_INLINE inline
219# endif
220#endif
221
222#ifndef FMT_DEPRECATED
223# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900
224# define FMT_DEPRECATED [[deprecated]]
225# else
226# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
227# define FMT_DEPRECATED __attribute__((deprecated))
228# elif FMT_MSC_VER
229# define FMT_DEPRECATED __declspec(deprecated)
230# else
231# define FMT_DEPRECATED /* deprecated */
232# endif
233# endif
234#endif
235
236#ifndef FMT_BEGIN_NAMESPACE
237# define FMT_BEGIN_NAMESPACE \
238 namespace fmt { \
239 inline namespace v8 {
240# define FMT_END_NAMESPACE \
241 } \
242 }
243#endif
244
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 }
251#endif
252
253#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
254# define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275)
255# ifdef FMT_EXPORT
256# define FMT_API __declspec(dllexport)
257# elif defined(FMT_SHARED)
258# define FMT_API __declspec(dllimport)
259# endif
260#else
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")))
265# endif
266# endif
267#endif
268#ifndef FMT_API
269# define FMT_API
270#endif
271
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
281#endif
282
283#ifndef FMT_UNICODE
284# define FMT_UNICODE !FMT_MSC_VER
285#endif
286
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
295# else
296# define FMT_CONSTEVAL
297# endif
298#endif
299
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
305# else
306# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0
307# endif
308#endif
309
310// Enable minimal optimizations for more compact code in debug mode.
311FMT_GCC_PRAGMA("GCC push_options")
312#ifndef __OPTIMIZE__
313FMT_GCC_PRAGMA("GCC optimize(\"Og\")")
314#endif
315
316FMT_BEGIN_NAMESPACE
317FMT_MODULE_EXPORT_BEGIN
318
319// Implementations of enable_if_t and other metafunctions for older systems.
320template <bool B, typename T = void>
321using enable_if_t = typename std::enable_if<B, T>::type;
322template <bool B, typename T, typename F>
323using conditional_t = typename std::conditional<B, T, F>::type;
324template <bool B> using bool_constant = std::integral_constant<bool, B>;
325template <typename T>
326using remove_reference_t = typename std::remove_reference<T>::type;
327template <typename T>
328using remove_const_t = typename std::remove_const<T>::type;
329template <typename T>
330using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
331template <typename T> struct type_identity { using type = T; };
332template <typename T> using type_identity_t = typename type_identity<T>::type;
333
334struct monostate {
335 constexpr monostate() {}
336};
337
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).
341#ifdef FMT_DOC
342# define FMT_ENABLE_IF(...)
343#else
344# define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0
345#endif
346
347FMT_BEGIN_DETAIL_NAMESPACE
348
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.
352template <typename... T> FMT_CONSTEXPR void ignore_unused(const T&...) {}
353
354constexpr 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();
359#else
360 return default_value;
361#endif
362}
363
364// A function to suppress "conditional expression is constant" warnings.
365template <typename T> constexpr FMT_INLINE auto const_check(T value) -> T {
366 return value;
367}
368
369FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
370 const char* message);
371
372#ifndef FMT_ASSERT
373# ifdef NDEBUG
374// FMT_ASSERT is not empty to avoid -Werror=empty-body.
375# define FMT_ASSERT(condition, message) \
376 ::fmt::detail::ignore_unused((condition), (message))
377# else
378# define FMT_ASSERT(condition, message) \
379 ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
380 ? (void)0 \
381 : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
382# endif
383#endif
384
385#ifdef __cpp_lib_byte
386using byte = std::byte;
387#else
388enum class byte : unsigned char {};
389#endif
390
391#if defined(FMT_USE_STRING_VIEW)
392template <typename Char> using std_string_view = std::basic_string_view<Char>;
393#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
394template <typename Char>
395using std_string_view = std::experimental::basic_string_view<Char>;
396#else
397template <typename T> struct std_string_view {};
398#endif
399
400#ifdef FMT_USE_INT128
401// Do nothing.
402#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \
403 !(FMT_CLANG_VERSION && FMT_MSC_VER)
404# define FMT_USE_INT128 1
405using int128_t = __int128_t;
406using uint128_t = __uint128_t;
407template <typename T> inline auto convert_for_visit(T value) -> T {
408 return value;
409}
410#else
411# define FMT_USE_INT128 0
412#endif
413#if !FMT_USE_INT128
414enum class int128_t {};
415enum class uint128_t {};
416// Reduce template instantiations.
417template <typename T> inline auto convert_for_visit(T) -> monostate {
418 return {};
419}
420#endif
421
422// Casts a nonnegative integer to unsigned.
423template <typename Int>
424FMT_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);
428}
429
430FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5";
431
432constexpr 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);
438}
439FMT_END_DETAIL_NAMESPACE
440
441/**
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
446 recommended).
447 */
448template <typename Char> class basic_string_view {
449 private:
450 const Char* data_;
451 size_t size_;
452
453 public:
454 using value_type = Char;
455 using iterator = const Char*;
456
457 constexpr basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {}
458
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
461 : data_(s),
462 size_(count) {}
463
464 /**
465 \rst
466 Constructs a string reference object from a C string computing
467 the size with ``std::char_traits<Char>::length``.
468 \endrst
469 */
470 FMT_CONSTEXPR_CHAR_TRAITS
471 FMT_INLINE
472 basic_string_view(const Char* s)
473 : data_(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)) {}
478
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
483 : data_(s.data()),
484 size_(s.size()) {}
485
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()),
489 size_(s.size()) {}
490
491 /** Returns a pointer to the string data. */
492 constexpr auto data() const FMT_NOEXCEPT -> const Char* { return data_; }
493
494 /** Returns the string size. */
495 constexpr auto size() const FMT_NOEXCEPT -> size_t { return size_; }
496
497 constexpr auto begin() const FMT_NOEXCEPT -> iterator { return data_; }
498 constexpr auto end() const FMT_NOEXCEPT -> iterator { return data_ + size_; }
499
500 constexpr auto operator[](size_t pos) const FMT_NOEXCEPT -> const Char& {
501 return data_[pos];
502 }
503
504 FMT_CONSTEXPR void remove_prefix(size_t n) FMT_NOEXCEPT {
505 data_ += n;
506 size_ -= n;
507 }
508
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);
513 if (result == 0)
514 result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
515 return result;
516 }
517
518 FMT_CONSTEXPR_CHAR_TRAITS friend auto operator==(basic_string_view lhs,
519 basic_string_view rhs)
520 -> bool {
521 return lhs.compare(rhs) == 0;
522 }
523 friend auto operator!=(basic_string_view lhs, basic_string_view rhs) -> bool {
524 return lhs.compare(rhs) != 0;
525 }
526 friend auto operator<(basic_string_view lhs, basic_string_view rhs) -> bool {
527 return lhs.compare(rhs) < 0;
528 }
529 friend auto operator<=(basic_string_view lhs, basic_string_view rhs) -> bool {
530 return lhs.compare(rhs) <= 0;
531 }
532 friend auto operator>(basic_string_view lhs, basic_string_view rhs) -> bool {
533 return lhs.compare(rhs) > 0;
534 }
535 friend auto operator>=(basic_string_view lhs, basic_string_view rhs) -> bool {
536 return lhs.compare(rhs) >= 0;
537 }
538};
539
540using string_view = basic_string_view<char>;
541
542/** Specifies if ``T`` is a character type. Can be specialized by users. */
543template <typename T> struct is_char : std::false_type {};
544template <> struct is_char<char> : std::true_type {};
545
546// Returns a string view of `s`.
547template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
548FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view<Char> {
549 return s;
550}
551template <typename Char, typename Traits, typename Alloc>
552inline auto to_string_view(const std::basic_string<Char, Traits, Alloc>& s)
553 -> basic_string_view<Char> {
554 return s;
555}
556template <typename Char>
557constexpr auto to_string_view(basic_string_view<Char> s)
558 -> basic_string_view<Char> {
559 return s;
560}
561template <typename Char,
562 FMT_ENABLE_IF(!std::is_empty<detail::std_string_view<Char>>::value)>
563inline auto to_string_view(detail::std_string_view<Char> s)
564 -> basic_string_view<Char> {
565 return s;
566}
567
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).
570struct compile_string {};
571
572template <typename S>
573struct is_compile_string : std::is_base_of<compile_string, S> {};
574
575template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
576constexpr 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);
579}
580
581FMT_BEGIN_DETAIL_NAMESPACE
582
583void to_string_view(...);
584using fmt::to_string_view;
585
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.
589template <typename S>
590struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> {
591};
592
593template <typename S, typename = void> struct char_t_impl {};
594template <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;
597};
598
599// Reports a compile-time error if S is not a valid format string.
600template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
601FMT_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 "
605 "FMT_STRING.");
606#endif
607}
608template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
609void check_format_string(S);
610
611FMT_NORETURN FMT_API void throw_format_error(const char* message);
612
613struct error_handler {
614 constexpr error_handler() = default;
615 constexpr error_handler(const error_handler&) = default;
616
617 // This function is intentionally not constexpr to give a compile-time error.
618 FMT_NORETURN FMT_API void on_error(const char* message);
619};
620FMT_END_DETAIL_NAMESPACE
621
622/** String's character type. */
623template <typename S> using char_t = typename detail::char_t_impl<S>::type;
624
625/**
626 \rst
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.
630 \endrst
631 */
632template <typename Char, typename ErrorHandler = detail::error_handler>
633class basic_format_parse_context : private ErrorHandler {
634 private:
635 basic_string_view<Char> format_str_;
636 int next_arg_id_;
637
638 public:
639 using char_type = Char;
640 using iterator = typename basic_string_view<Char>::iterator;
641
642 explicit constexpr basic_format_parse_context(
643 basic_string_view<Char> format_str, ErrorHandler eh = {},
644 int next_arg_id = 0)
645 : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {}
646
647 /**
648 Returns an iterator to the beginning of the format string range being
649 parsed.
650 */
651 constexpr auto begin() const FMT_NOEXCEPT -> iterator {
652 return format_str_.begin();
653 }
654
655 /**
656 Returns an iterator past the end of the format string range being parsed.
657 */
658 constexpr auto end() const FMT_NOEXCEPT -> iterator {
659 return format_str_.end();
660 }
661
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()));
665 }
666
667 /**
668 Reports an error if using the manual argument indexing; otherwise returns
669 the next argument index and switches to the automatic indexing.
670 */
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");
676 return 0;
677 }
678
679 /**
680 Reports an error if using the automatic argument indexing; otherwise
681 switches to the manual indexing.
682 */
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");
686 else
687 next_arg_id_ = -1;
688 }
689
690 FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
691
692 FMT_CONSTEXPR void on_error(const char* message) {
693 ErrorHandler::on_error(message);
694 }
695
696 constexpr auto error_handler() const -> ErrorHandler { return *this; }
697};
698
699using format_parse_context = basic_format_parse_context<char>;
700
701template <typename Context> class basic_format_arg;
702template <typename Context> class basic_format_args;
703template <typename Context> class dynamic_format_arg_store;
704
705// A formatter for objects of type T.
706template <typename T, typename Char = char, typename Enable = void>
707struct formatter {
708 // A deleted default constructor indicates a disabled formatter.
709 formatter() = delete;
710};
711
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.
714template <typename T, typename Context>
715using has_formatter =
716 std::is_constructible<typename Context::template formatter_type<T>>;
717
718// Checks whether T is a container with contiguous storage.
719template <typename T> struct is_contiguous : std::false_type {};
720template <typename Char>
721struct is_contiguous<std::basic_string<Char>> : std::true_type {};
722
723class appender;
724
725FMT_BEGIN_DETAIL_NAMESPACE
726
727template <typename Context, typename T>
728constexpr auto has_const_formatter_impl(T*)
729 -> decltype(typename Context::template formatter_type<T>().format(
730 std::declval<const T&>(), std::declval<Context&>()),
731 true) {
732 return true;
733}
734template <typename Context>
735constexpr auto has_const_formatter_impl(...) -> bool {
736 return false;
737}
738template <typename T, typename Context>
739constexpr auto has_const_formatter() -> bool {
740 return has_const_formatter_impl<Context>(static_cast<T*>(nullptr));
741}
742
743// Extracts a reference to the container from back_insert_iterator.
744template <typename Container>
745inline auto get_container(std::back_insert_iterator<Container> it)
746 -> Container& {
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;
751 };
752 return *accessor(it).container;
753}
754
755template <typename Char, typename InputIt, typename OutputIt>
756FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out)
757 -> OutputIt {
758 while (begin != end) *out++ = static_cast<Char>(*begin++);
759 return out;
760}
761
762template <typename Char, typename T, typename U,
763 FMT_ENABLE_IF(
764 std::is_same<remove_const_t<T>, U>::value&& is_char<U>::value)>
765FMT_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));
769 return out + size;
770}
771
772/**
773 \rst
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`.
776 \endrst
777 */
778template <typename T> class buffer {
779 private:
780 T* ptr_;
781 size_t size_;
782 size_t capacity_;
783
784 protected:
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) {}
788
789 FMT_CONSTEXPR20 buffer(T* p = nullptr, size_t sz = 0,
790 size_t cap = 0) FMT_NOEXCEPT : ptr_(p),
791 size_(sz),
792 capacity_(cap) {}
793
794 FMT_CONSTEXPR20 ~buffer() = default;
795 buffer(buffer&&) = default;
796
797 /** Sets the buffer data and capacity. */
798 FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT {
799 ptr_ = buf_data;
800 capacity_ = buf_capacity;
801 }
802
803 /** Increases the buffer capacity to hold at least *capacity* elements. */
804 virtual FMT_CONSTEXPR20 void grow(size_t capacity) = 0;
805
806 public:
807 using value_type = T;
808 using const_reference = const T&;
809
810 buffer(const buffer&) = delete;
811 void operator=(const buffer&) = delete;
812
813 auto begin() FMT_NOEXCEPT -> T* { return ptr_; }
814 auto end() FMT_NOEXCEPT -> T* { return ptr_ + size_; }
815
816 auto begin() const FMT_NOEXCEPT -> const T* { return ptr_; }
817 auto end() const FMT_NOEXCEPT -> const T* { return ptr_ + size_; }
818
819 /** Returns the size of this buffer. */
820 constexpr auto size() const FMT_NOEXCEPT -> size_t { return size_; }
821
822 /** Returns the capacity of this buffer. */
823 constexpr auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; }
824
825 /** Returns a pointer to the buffer data. */
826 FMT_CONSTEXPR auto data() FMT_NOEXCEPT -> T* { return ptr_; }
827
828 /** Returns a pointer to the buffer data. */
829 FMT_CONSTEXPR auto data() const FMT_NOEXCEPT -> const T* { return ptr_; }
830
831 /** Clears this buffer. */
832 void clear() { size_ = 0; }
833
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) {
837 try_reserve(count);
838 size_ = count <= capacity_ ? count : capacity_;
839 }
840
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);
847 }
848
849 FMT_CONSTEXPR20 void push_back(const T& value) {
850 try_reserve(size_ + 1);
851 ptr_[size_++] = value;
852 }
853
854 /** Appends data to the end of the buffer. */
855 template <typename U> void append(const U* begin, const U* end);
856
857 template <typename I> FMT_CONSTEXPR auto operator[](I index) -> T& {
858 return ptr_[index];
859 }
860 template <typename I>
861 FMT_CONSTEXPR auto operator[](I index) const -> const T& {
862 return ptr_[index];
863 }
864};
865
866struct 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; }
870};
871
872class fixed_buffer_traits {
873 private:
874 size_t count_ = 0;
875 size_t limit_;
876
877 public:
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;
882 count_ += size;
883 return size < n ? size : n;
884 }
885};
886
887// A buffer that writes to an output iterator when flushed.
888template <typename OutputIt, typename T, typename Traits = buffer_traits>
889class iterator_buffer final : public Traits, public buffer<T> {
890 private:
891 OutputIt out_;
892 enum { buffer_size = 256 };
893 T data_[buffer_size];
894
895 protected:
896 FMT_CONSTEXPR20 void grow(size_t) override {
897 if (this->size() == buffer_size) flush();
898 }
899
900 void flush() {
901 auto size = this->size();
902 this->clear();
903 out_ = copy_str<T>(data_, data_ + this->limit(size), out_);
904 }
905
906 public:
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(); }
912
913 auto out() -> OutputIt {
914 flush();
915 return out_;
916 }
917 auto count() const -> size_t { return Traits::count() + this->size(); }
918};
919
920template <typename T>
921class iterator_buffer<T*, T, fixed_buffer_traits> final
922 : public fixed_buffer_traits,
923 public buffer<T> {
924 private:
925 T* out_;
926 enum { buffer_size = 256 };
927 T data_[buffer_size];
928
929 protected:
930 FMT_CONSTEXPR20 void grow(size_t) override {
931 if (this->size() == this->capacity()) flush();
932 }
933
934 void flush() {
935 size_t n = this->limit(this->size());
936 if (this->data() == out_) {
937 out_ += n;
938 this->set(data_, buffer_size);
939 }
940 this->clear();
941 }
942
943 public:
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)),
949 out_(other.out_) {
950 if (this->data() != out_) {
951 this->set(data_, buffer_size);
952 this->clear();
953 }
954 }
955 ~iterator_buffer() { flush(); }
956
957 auto out() -> T* {
958 flush();
959 return out_;
960 }
961 auto count() const -> size_t {
962 return fixed_buffer_traits::count() + this->size();
963 }
964};
965
966template <typename T> class iterator_buffer<T*, T> final : public buffer<T> {
967 protected:
968 FMT_CONSTEXPR20 void grow(size_t) override {}
969
970 public:
971 explicit iterator_buffer(T* out, size_t = 0) : buffer<T>(out, 0, ~size_t()) {}
972
973 auto out() -> T* { return &*this->end(); }
974};
975
976// A buffer that writes to a container with the contiguous storage.
977template <typename Container>
978class 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> {
982 private:
983 Container& container_;
984
985 protected:
986 FMT_CONSTEXPR20 void grow(size_t capacity) override {
987 container_.resize(capacity);
988 this->set(&container_[0], capacity);
989 }
990
991 public:
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_);
998 }
999};
1000
1001// A buffer that counts the number of code units written discarding the output.
1002template <typename T = char> class counting_buffer final : public buffer<T> {
1003 private:
1004 enum { buffer_size = 256 };
1005 T data_[buffer_size];
1006 size_t count_ = 0;
1007
1008 protected:
1009 FMT_CONSTEXPR20 void grow(size_t) override {
1010 if (this->size() != buffer_size) return;
1011 count_ += this->size();
1012 this->clear();
1013 }
1014
1015 public:
1016 counting_buffer() : buffer<T>(data_, 0, buffer_size) {}
1017
1018 auto count() -> size_t { return count_ + this->size(); }
1019};
1020
1021template <typename T>
1022using buffer_appender = conditional_t<std::is_same<T, char>::value, appender,
1023 std::back_insert_iterator<buffer<T>>>;
1024
1025// Maps an output iterator to a buffer.
1026template <typename T, typename OutputIt>
1027auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
1028 return iterator_buffer<OutputIt, T>(out);
1029}
1030
1031template <typename Buffer>
1032auto get_iterator(Buffer& buf) -> decltype(buf.out()) {
1033 return buf.out();
1034}
1035template <typename T> auto get_iterator(buffer<T>& buf) -> buffer_appender<T> {
1036 return buffer_appender<T>(buf);
1037}
1038
1039template <typename T, typename Char = char, typename Enable = void>
1040struct fallback_formatter {
1041 fallback_formatter() = delete;
1042};
1043
1044// Specifies if T has an enabled fallback_formatter specialization.
1045template <typename T, typename Char>
1046using has_fallback_formatter =
1047 std::is_constructible<fallback_formatter<T, Char>>;
1048
1049struct view {};
1050
1051template <typename Char, typename T> struct named_arg : view {
1052 const Char* name;
1053 const T& value;
1054 named_arg(const Char* n, const T& v) : name(n), value(v) {}
1055};
1056
1057template <typename Char> struct named_arg_info {
1058 const Char* name;
1059 int id;
1060};
1061
1062template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
1063struct arg_data {
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];
1068
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_; }
1074};
1075
1076template <typename T, typename Char, size_t NUM_ARGS>
1077struct 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];
1080
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 {
1085 return nullptr;
1086 }
1087};
1088
1089template <typename Char>
1090inline void init_named_args(named_arg_info<Char>*, int, int) {}
1091
1092template <typename T> struct is_named_arg : std::false_type {};
1093template <typename T> struct is_statically_named_arg : std::false_type {};
1094
1095template <typename T, typename Char>
1096struct is_named_arg<named_arg<Char, T>> : std::true_type {};
1097
1098template <typename Char, typename T, typename... Tail,
1099 FMT_ENABLE_IF(!is_named_arg<T>::value)>
1100void 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...);
1103}
1104
1105template <typename Char, typename T, typename... Tail,
1106 FMT_ENABLE_IF(is_named_arg<T>::value)>
1107void 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...);
1111}
1112
1113template <typename... Args>
1114FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int,
1115 const Args&...) {}
1116
1117template <bool B = false> constexpr auto count() -> size_t { return B ? 1 : 0; }
1118template <bool B1, bool B2, bool... Tail> constexpr auto count() -> size_t {
1119 return (B1 ? 1 : 0) + count<B2, Tail...>();
1120}
1121
1122template <typename... Args> constexpr auto count_named_args() -> size_t {
1123 return count<is_named_arg<Args>::value...>();
1124}
1125
1126template <typename... Args>
1127constexpr auto count_statically_named_args() -> size_t {
1128 return count<is_statically_named_arg<Args>::value...>();
1129}
1130
1131enum class type {
1132 none_type,
1133 // Integer types should go first,
1134 int_type,
1135 uint_type,
1136 long_long_type,
1137 ulong_long_type,
1138 int128_type,
1139 uint128_type,
1140 bool_type,
1141 char_type,
1142 last_integer_type = char_type,
1143 // followed by floating-point types.
1144 float_type,
1145 double_type,
1146 long_double_type,
1147 last_numeric_type = long_double_type,
1148 cstring_type,
1149 string_type,
1150 pointer_type,
1151 custom_type
1152};
1153
1154// Maps core type T to the corresponding type enum constant.
1155template <typename T, typename Char>
1156struct type_constant : std::integral_constant<type, type::custom_type> {};
1157
1158#define FMT_TYPE_CONSTANT(Type, constant) \
1159 template <typename Char> \
1160 struct type_constant<Type, Char> \
1161 : std::integral_constant<type, type::constant> {}
1162
1163FMT_TYPE_CONSTANT(int, int_type);
1164FMT_TYPE_CONSTANT(unsigned, uint_type);
1165FMT_TYPE_CONSTANT(long long, long_long_type);
1166FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
1167FMT_TYPE_CONSTANT(int128_t, int128_type);
1168FMT_TYPE_CONSTANT(uint128_t, uint128_type);
1169FMT_TYPE_CONSTANT(bool, bool_type);
1170FMT_TYPE_CONSTANT(Char, char_type);
1171FMT_TYPE_CONSTANT(float, float_type);
1172FMT_TYPE_CONSTANT(double, double_type);
1173FMT_TYPE_CONSTANT(long double, long_double_type);
1174FMT_TYPE_CONSTANT(const Char*, cstring_type);
1175FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
1176FMT_TYPE_CONSTANT(const void*, pointer_type);
1177
1178constexpr bool is_integral_type(type t) {
1179 return t > type::none_type && t <= type::last_integer_type;
1180}
1181
1182constexpr bool is_arithmetic_type(type t) {
1183 return t > type::none_type && t <= type::last_numeric_type;
1184}
1185
1186struct unformattable {};
1187struct unformattable_char : unformattable {};
1188struct unformattable_const : unformattable {};
1189struct unformattable_pointer : unformattable {};
1190
1191template <typename Char> struct string_value {
1192 const Char* data;
1193 size_t size;
1194};
1195
1196template <typename Char> struct named_arg_value {
1197 const named_arg_info<Char>* data;
1198 size_t size;
1199};
1200
1201template <typename Context> struct custom_value {
1202 using parse_context = typename Context::parse_context_type;
1203 void* value;
1204 void (*format)(void* arg, parse_context& parse_ctx, Context& ctx);
1205};
1206
1207// A formatting argument value.
1208template <typename Context> class value {
1209 public:
1210 using char_type = typename Context::char_type;
1211
1212 union {
1213 monostate no_value;
1214 int int_value;
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;
1220 bool bool_value;
1221 char_type char_value;
1222 float float_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;
1229 };
1230
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) {
1244 string.data = val;
1245 if (is_constant_evaluated()) string.size = {};
1246 }
1247 FMT_CONSTEXPR FMT_INLINE value(basic_string_view<char_type> val) {
1248 string.data = val.data();
1249 string.size = val.size();
1250 }
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} {}
1254
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<
1262 value_type,
1263 conditional_t<has_formatter<value_type, Context>::value,
1264 typename Context::template formatter_type<value_type>,
1265 fallback_formatter<value_type, char_type>>>;
1266 }
1267 value(unformattable);
1268 value(unformattable_char);
1269 value(unformattable_const);
1270 value(unformattable_pointer);
1271
1272 private:
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,
1277 Context& 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));
1283 }
1284};
1285
1286template <typename Context, typename T>
1287FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context>;
1288
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.
1291enum { long_short = sizeof(long) == sizeof(int) };
1292using long_type = conditional_t<long_short, int, long long>;
1293using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
1294
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.
1298template <typename Context> struct arg_mapper {
1299 using char_type = typename Context::char_type;
1300
1301 FMT_CONSTEXPR FMT_INLINE auto map(signed char val) -> int { return val; }
1302 FMT_CONSTEXPR FMT_INLINE auto map(unsigned char val) -> unsigned {
1303 return val;
1304 }
1305 FMT_CONSTEXPR FMT_INLINE auto map(short val) -> int { return val; }
1306 FMT_CONSTEXPR FMT_INLINE auto map(unsigned short val) -> unsigned {
1307 return val;
1308 }
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 {
1313 return val;
1314 }
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 {
1318 return val;
1319 }
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; }
1323
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 {
1327 return val;
1328 }
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 ||
1332#endif
1333 std::is_same<T, char16_t>::value ||
1334 std::is_same<T, char32_t>::value) &&
1335 !std::is_same<T, char_type>::value,
1336 int> = 0>
1337 FMT_CONSTEXPR FMT_INLINE auto map(T) -> unformattable_char {
1338 return {};
1339 }
1340
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 {
1344 return val;
1345 }
1346
1347 FMT_CONSTEXPR FMT_INLINE auto map(char_type* val) -> const char_type* {
1348 return val;
1349 }
1350 FMT_CONSTEXPR FMT_INLINE auto map(const char_type* val) -> const char_type* {
1351 return val;
1352 }
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);
1359 }
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 {
1364 return {};
1365 }
1366 template <typename T,
1367 FMT_ENABLE_IF(
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);
1374 }
1375 template <
1376 typename T,
1377 FMT_ENABLE_IF(
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);
1385 }
1386
1387 using cstring_result = conditional_t<std::is_same<char_type, char>::value,
1388 const char*, unformattable_pointer>;
1389
1390 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val)
1391 -> cstring_result {
1392 return map(reinterpret_cast<const char*>(val));
1393 }
1394 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val)
1395 -> cstring_result {
1396 return map(reinterpret_cast<const char*>(val));
1397 }
1398 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(signed char* val)
1399 -> cstring_result {
1400 return map(reinterpret_cast<const char*>(val));
1401 }
1402 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val)
1403 -> cstring_result {
1404 return map(reinterpret_cast<const char*>(val));
1405 }
1406
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* {
1409 return val;
1410 }
1411 FMT_CONSTEXPR FMT_INLINE auto map(std::nullptr_t val) -> const void* {
1412 return val;
1413 }
1414
1415 // We use SFINAE instead of a const T* parameter to avoid conflicting with
1416 // the C array overload.
1417 template <
1418 typename T,
1419 FMT_ENABLE_IF(
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 {
1425 return {};
1426 }
1427
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] {
1431 return values;
1432 }
1433
1434 template <typename T,
1435 FMT_ENABLE_IF(
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));
1443 }
1444
1445 FMT_CONSTEXPR FMT_INLINE auto map(detail::byte val) -> unsigned {
1446 return map(static_cast<unsigned char>(val));
1447 }
1448
1449 template <typename T, typename U = remove_cvref_t<T>>
1450 struct formattable
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> {};
1454
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& {
1458 return val;
1459 }
1460#else
1461 template <typename T, FMT_ENABLE_IF(formattable<T>::value)>
1462 FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& {
1463 return val;
1464 }
1465 template <typename T, FMT_ENABLE_IF(!formattable<T>::value)>
1466 FMT_CONSTEXPR FMT_INLINE auto do_map(T&&) -> unformattable_const {
1467 return {};
1468 }
1469#endif
1470
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));
1479 }
1480
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);
1485 }
1486
1487 auto map(...) -> unformattable { return {}; }
1488};
1489
1490// A type constant after applying arg_mapper<Context>.
1491template <typename T, typename Context>
1492using mapped_type_constant =
1493 type_constant<decltype(arg_mapper<Context>().map(std::declval<const T&>())),
1494 typename Context::char_type>;
1495
1496enum { packed_arg_bits = 4 };
1497// Maximum number of arguments with packed types.
1498enum { max_packed_args = 62 / packed_arg_bits };
1499enum : unsigned long long { is_unpacked_bit = 1ULL << 63 };
1500enum : unsigned long long { has_named_args_bit = 1ULL << 62 };
1501
1502FMT_END_DETAIL_NAMESPACE
1503
1504// An output iterator that appends to a buffer.
1505// It is used to reduce symbol sizes for the common case.
1506class appender : public std::back_insert_iterator<detail::buffer<char>> {
1507 using base = std::back_insert_iterator<detail::buffer<char>>;
1508
1509 template <typename T>
1510 friend auto get_buffer(appender out) -> detail::buffer<char>& {
1511 return detail::get_container(out);
1512 }
1513
1514 public:
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.
1518
1519 auto operator++() FMT_NOEXCEPT -> appender& { return *this; }
1520
1521 auto operator++(int) FMT_NOEXCEPT -> appender { return *this; }
1522};
1523
1524// A formatting argument. It is a trivially copyable/constructible type to
1525// allow storage in basic_memory_buffer.
1526template <typename Context> class basic_format_arg {
1527 private:
1528 detail::value<Context> value_;
1529 detail::type type_;
1530
1531 template <typename ContextType, typename T>
1532 friend FMT_CONSTEXPR auto detail::make_arg(const T& value)
1533 -> basic_format_arg<ContextType>;
1534
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));
1539
1540 friend class basic_format_args<Context>;
1541 friend class dynamic_format_arg_store<Context>;
1542
1543 using char_type = typename Context::char_type;
1544
1545 template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
1546 friend struct detail::arg_data;
1547
1548 basic_format_arg(const detail::named_arg_info<char_type>* args, size_t size)
1549 : value_(args, size) {}
1550
1551 public:
1552 class handle {
1553 public:
1554 explicit handle(detail::custom_value<Context> custom) : custom_(custom) {}
1555
1556 void format(typename Context::parse_context_type& parse_ctx,
1557 Context& ctx) const {
1558 custom_.format(custom_.value, parse_ctx, ctx);
1559 }
1560
1561 private:
1562 detail::custom_value<Context> custom_;
1563 };
1564
1565 constexpr basic_format_arg() : type_(detail::type::none_type) {}
1566
1567 constexpr explicit operator bool() const FMT_NOEXCEPT {
1568 return type_ != detail::type::none_type;
1569 }
1570
1571 auto type() const -> detail::type { return type_; }
1572
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_);
1576 }
1577};
1578
1579/**
1580 \rst
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``.
1584 \endrst
1585 */
1586template <typename Visitor, typename Context>
1587FMT_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:
1591 break;
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));
1623 }
1624 return vis(monostate());
1625}
1626
1627FMT_BEGIN_DETAIL_NAMESPACE
1628
1629template <typename Char, typename InputIt>
1630auto copy_str(InputIt begin, InputIt end, appender out) -> appender {
1631 get_container(out).append(begin, end);
1632 return out;
1633}
1634
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.
1637template <typename... Ts> struct void_t_impl { using type = void; };
1638template <typename... Ts>
1639using void_t = typename detail::void_t_impl<Ts...>::type;
1640#else
1641template <typename...> using void_t = void;
1642#endif
1643
1644template <typename It, typename T, typename Enable = void>
1645struct is_output_iterator : std::false_type {};
1646
1647template <typename It, typename T>
1648struct is_output_iterator<
1649 It, T,
1650 void_t<typename std::iterator_traits<It>::iterator_category,
1651 decltype(*std::declval<It>() = std::declval<T>())>>
1652 : std::true_type {};
1653
1654template <typename OutputIt>
1655struct is_back_insert_iterator : std::false_type {};
1656template <typename Container>
1657struct is_back_insert_iterator<std::back_insert_iterator<Container>>
1658 : std::true_type {};
1659
1660template <typename OutputIt>
1661struct is_contiguous_back_insert_iterator : std::false_type {};
1662template <typename Container>
1663struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
1664 : is_contiguous<Container> {};
1665template <>
1666struct is_contiguous_back_insert_iterator<appender> : std::true_type {};
1667
1668// A type-erased reference to an std::locale to avoid heavy <locale> include.
1669class locale_ref {
1670 private:
1671 const void* locale_; // A type-erased pointer to std::locale.
1672
1673 public:
1674 constexpr locale_ref() : locale_(nullptr) {}
1675 template <typename Locale> explicit locale_ref(const Locale& loc);
1676
1677 explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; }
1678
1679 template <typename Locale> auto get() const -> Locale;
1680};
1681
1682template <typename> constexpr auto encode_types() -> unsigned long long {
1683 return 0;
1684}
1685
1686template <typename Context, typename Arg, typename... Args>
1687constexpr 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);
1690}
1691
1692template <typename Context, typename T>
1693FMT_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);
1697 return arg;
1698}
1699
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).
1703template <bool IS_PACKED, typename Context, type, typename T,
1704 FMT_ENABLE_IF(IS_PACKED)>
1705FMT_CONSTEXPR FMT_INLINE auto make_arg(T&& val) -> value<Context> {
1706 const auto& arg = arg_mapper<Context>().map(std::forward<T>(val));
1707
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.");
1711
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.");
1715
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
1719 // by iostreams.
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.");
1724
1725 constexpr bool formattable =
1726 !std::is_same<decltype(arg), const unformattable&>::value;
1727 static_assert(
1728 formattable,
1729 "Cannot format an argument. To make type T formattable provide a "
1730 "formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
1731 return {arg};
1732}
1733
1734template <bool IS_PACKED, typename Context, type, typename T,
1735 FMT_ENABLE_IF(!IS_PACKED)>
1736inline auto make_arg(const T& value) -> basic_format_arg<Context> {
1737 return make_arg<Context>(value);
1738}
1739FMT_END_DETAIL_NAMESPACE
1740
1741// Formatting context.
1742template <typename OutputIt, typename Char> class basic_format_context {
1743 public:
1744 /** The character type for the output. */
1745 using char_type = Char;
1746
1747 private:
1748 OutputIt out_;
1749 basic_format_args<basic_format_context> args_;
1750 detail::locale_ref loc_;
1751
1752 public:
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>;
1757
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;
1761 /**
1762 Constructs a ``basic_format_context`` object. References to the arguments are
1763 stored in the object so make sure they have appropriate lifetimes.
1764 */
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) {}
1769
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);
1773 }
1774 FMT_CONSTEXPR auto arg_id(basic_string_view<char_type> name) -> int {
1775 return args_.get_id(name);
1776 }
1777 auto args() const -> const basic_format_args<basic_format_context>& {
1778 return args_;
1779 }
1780
1781 FMT_CONSTEXPR auto error_handler() -> detail::error_handler { return {}; }
1782 void on_error(const char* message) { error_handler().on_error(message); }
1783
1784 // Returns an iterator to the beginning of the output range.
1785 FMT_CONSTEXPR auto out() -> iterator { return out_; }
1786
1787 // Advances the begin iterator to ``it``.
1788 void advance_to(iterator it) {
1789 if (!detail::is_back_insert_iterator<iterator>()) out_ = it;
1790 }
1791
1792 FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; }
1793};
1794
1795template <typename Char>
1796using buffer_context =
1797 basic_format_context<detail::buffer_appender<Char>, Char>;
1798using format_context = buffer_context<char>;
1799
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>
1803
1804template <typename T, typename Char = char>
1805using 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>;
1810
1811/**
1812 \rst
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`.
1816 \endrst
1817 */
1818template <typename Context, typename... Args>
1819class 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>
1823#endif
1824{
1825 private:
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;
1829
1830 using value_type = conditional_t<is_packed, detail::value<Context>,
1831 basic_format_arg<Context>>;
1832
1833 detail::arg_data<value_type, typename Context::char_type, num_args,
1834 num_named_args>
1835 data_;
1836
1837 friend class basic_format_args<Context>;
1838
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)
1844 : 0);
1845
1846 public:
1847 template <typename... T>
1848 FMT_CONSTEXPR FMT_INLINE format_arg_store(T&&... args)
1849 :
1850#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1851 basic_format_args<Context>(*this),
1852#endif
1853 data_{detail::make_arg<
1854 is_packed, Context,
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...);
1858 }
1859};
1860
1861/**
1862 \rst
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.
1867 \endrst
1868 */
1869template <typename Context = format_context, typename... Args>
1870constexpr auto make_format_args(Args&&... args)
1871 -> format_arg_store<Context, remove_cvref_t<Args>...> {
1872 return {std::forward<Args>(args)...};
1873}
1874
1875/**
1876 \rst
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`.
1880
1881 **Example**::
1882
1883 fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
1884 \endrst
1885 */
1886template <typename Char, typename T>
1887inline auto arg(const Char* name, const T& arg) -> detail::named_arg<Char, T> {
1888 static_assert(!detail::is_named_arg<T>(), "nested named arguments");
1889 return {name, arg};
1890}
1891
1892/**
1893 \rst
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
1896 ``vformat``::
1897
1898 void vlog(string_view format_str, format_args args); // OK
1899 format_args args = make_format_args(42); // Error: dangling reference
1900 \endrst
1901 */
1902template <typename Context> class basic_format_args {
1903 public:
1904 using size_type = int;
1905 using format_arg = basic_format_arg<Context>;
1906
1907 private:
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_;
1913 union {
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_;
1921 };
1922
1923 constexpr auto is_packed() const -> bool {
1924 return (desc_ & detail::is_unpacked_bit) == 0;
1925 }
1926 auto has_named_args() const -> bool {
1927 return (desc_ & detail::has_named_args_bit) != 0;
1928 }
1929
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);
1934 }
1935
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) {}
1941
1942 public:
1943 constexpr basic_format_args() : desc_(0), args_(nullptr) {}
1944
1945 /**
1946 \rst
1947 Constructs a `basic_format_args` object from `~fmt::format_arg_store`.
1948 \endrst
1949 */
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()) {}
1955
1956 /**
1957 \rst
1958 Constructs a `basic_format_args` object from
1959 `~fmt::dynamic_format_arg_store`.
1960 \endrst
1961 */
1962 constexpr FMT_INLINE basic_format_args(
1963 const dynamic_format_arg_store<Context>& store)
1964 : basic_format_args(store.get_types(), store.data()) {}
1965
1966 /**
1967 \rst
1968 Constructs a `basic_format_args` object from a dynamic set of arguments.
1969 \endrst
1970 */
1971 constexpr basic_format_args(const format_arg* args, int count)
1972 : basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count),
1973 args) {}
1974
1975 /** Returns the argument with the specified id. */
1976 FMT_CONSTEXPR auto get(int id) const -> format_arg {
1977 format_arg arg;
1978 if (!is_packed()) {
1979 if (id < max_size()) arg = args_[id];
1980 return arg;
1981 }
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];
1986 return arg;
1987 }
1988
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();
1993 }
1994
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;
2002 }
2003 return -1;
2004 }
2005
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);
2010 }
2011};
2012
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).
2016using format_args = basic_format_args<format_context>;
2017
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.
2020namespace align {
2021enum type { none, left, right, center, numeric };
2022}
2023using align_t = align::type;
2024namespace sign {
2025enum type { none, minus, plus, space };
2026}
2027using sign_t = sign::type;
2028
2029FMT_BEGIN_DETAIL_NAMESPACE
2030
2031// Workaround an array initialization issue in gcc 4.8.
2032template <typename Char> struct fill_t {
2033 private:
2034 enum { max_size = 4 };
2035 Char data_[max_size] = {Char(' '), Char(0), Char(0), Char(0)};
2036 unsigned char size_ = 1;
2037
2038 public:
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);
2044 }
2045
2046 constexpr auto size() const -> size_t { return size_; }
2047 constexpr auto data() const -> const Char* { return data_; }
2048
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];
2052 }
2053};
2054FMT_END_DETAIL_NAMESPACE
2055
2056enum class presentation_type : unsigned char {
2057 none,
2058 // Integer types should go first,
2059 dec, // 'd'
2060 oct, // 'o'
2061 hex_lower, // 'x'
2062 hex_upper, // 'X'
2063 bin_lower, // 'b'
2064 bin_upper, // 'B'
2065 hexfloat_lower, // 'a'
2066 hexfloat_upper, // 'A'
2067 exp_lower, // 'e'
2068 exp_upper, // 'E'
2069 fixed_lower, // 'f'
2070 fixed_upper, // 'F'
2071 general_lower, // 'g'
2072 general_upper, // 'G'
2073 chr, // 'c'
2074 string, // 's'
2075 pointer // 'p'
2076};
2077
2078// Format specifiers for built-in and string types.
2079template <typename Char> struct basic_format_specs {
2080 int width;
2081 int precision;
2082 presentation_type type;
2083 align_t align : 4;
2084 sign_t sign : 3;
2085 bool alt : 1; // Alternate form ('#').
2086 bool localized : 1;
2087 detail::fill_t<Char> fill;
2088
2089 constexpr basic_format_specs()
2090 : width(0),
2091 precision(-1),
2092 type(presentation_type::none),
2093 align(align::none),
2094 sign(sign::none),
2095 alt(false),
2096 localized(false) {}
2097};
2098
2099using format_specs = basic_format_specs<char>;
2100
2101FMT_BEGIN_DETAIL_NAMESPACE
2102
2103enum class arg_id_kind { none, index, name };
2104
2105// An argument reference.
2106template <typename Char> struct arg_ref {
2107 FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {}
2108
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) {}
2113
2114 FMT_CONSTEXPR auto operator=(int idx) -> arg_ref& {
2115 kind = arg_id_kind::index;
2116 val.index = idx;
2117 return *this;
2118 }
2119
2120 arg_id_kind kind;
2121 union value {
2122 FMT_CONSTEXPR value(int id = 0) : index{id} {}
2123 FMT_CONSTEXPR value(basic_string_view<Char> n) : name(n) {}
2124
2125 int index;
2126 basic_string_view<Char> name;
2127 } val;
2128};
2129
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).
2133template <typename Char>
2134struct dynamic_format_specs : basic_format_specs<Char> {
2135 arg_ref<Char> width_ref;
2136 arg_ref<Char> precision_ref;
2137};
2138
2139struct auto_id {};
2140
2141// A format specifier handler that sets fields in basic_format_specs.
2142template <typename Char> class specs_setter {
2143 protected:
2144 basic_format_specs<Char>& specs_;
2145
2146 public:
2147 explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char>& specs)
2148 : specs_(specs) {}
2149
2150 FMT_CONSTEXPR specs_setter(const specs_setter& other)
2151 : specs_(other.specs_) {}
2152
2153 FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; }
2154 FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) {
2155 specs_.fill = fill;
2156 }
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; }
2160
2161 FMT_CONSTEXPR void on_zero() {
2162 if (specs_.align == align::none) specs_.align = align::numeric;
2163 specs_.fill[0] = Char('0');
2164 }
2165
2166 FMT_CONSTEXPR void on_width(int width) { specs_.width = width; }
2167 FMT_CONSTEXPR void on_precision(int precision) {
2168 specs_.precision = precision;
2169 }
2170 FMT_CONSTEXPR void end_precision() {}
2171
2172 FMT_CONSTEXPR void on_type(presentation_type type) { specs_.type = type; }
2173};
2174
2175// Format spec handler that saves references to arguments representing dynamic
2176// width and precision to be resolved at formatting time.
2177template <typename ParseContext>
2178class dynamic_specs_handler
2179 : public specs_setter<typename ParseContext::char_type> {
2180 public:
2181 using char_type = typename ParseContext::char_type;
2182
2183 FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs<char_type>& specs,
2184 ParseContext& ctx)
2185 : specs_setter<char_type>(specs), specs_(specs), context_(ctx) {}
2186
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_) {}
2191
2192 template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
2193 specs_.width_ref = make_arg_ref(arg_id);
2194 }
2195
2196 template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
2197 specs_.precision_ref = make_arg_ref(arg_id);
2198 }
2199
2200 FMT_CONSTEXPR void on_error(const char* message) {
2201 context_.on_error(message);
2202 }
2203
2204 private:
2205 dynamic_format_specs<char_type>& specs_;
2206 ParseContext& context_;
2207
2208 using arg_ref_type = arg_ref<char_type>;
2209
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);
2213 }
2214
2215 FMT_CONSTEXPR auto make_arg_ref(auto_id) -> arg_ref_type {
2216 return arg_ref_type(context_.next_arg_id());
2217 }
2218
2219 FMT_CONSTEXPR auto make_arg_ref(basic_string_view<char_type> arg_id)
2220 -> arg_ref_type {
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);
2225 }
2226};
2227
2228template <typename Char> constexpr bool is_ascii_letter(Char c) {
2229 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
2230}
2231
2232// Converts a character to ASCII. Returns a number > 127 on conversion failure.
2233template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
2234constexpr auto to_ascii(Char value) -> Char {
2235 return value;
2236}
2237template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
2238constexpr auto to_ascii(Char value) ->
2239 typename std::underlying_type<Char>::type {
2240 return value;
2241}
2242
2243template <typename Char>
2244FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int {
2245 if (const_check(sizeof(Char) != 1)) return 1;
2246 auto lengths =
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];
2249
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.
2253 return len + !len;
2254}
2255
2256// Return the result via the out param to workaround gcc bug 77539.
2257template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
2258FMT_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;
2261 }
2262 return false;
2263}
2264
2265template <>
2266inline 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;
2271}
2272
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.
2275template <typename Char>
2276FMT_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;
2280 auto p = begin;
2281 do {
2282 prev = value;
2283 value = value * 10 + unsigned(*p - '0');
2284 ++p;
2285 } while (p != end && '0' <= *p && *p <= '9');
2286 auto num_digits = p - begin;
2287 begin = p;
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)
2295 : error_value;
2296}
2297
2298// Parses fill and alignment.
2299template <typename Char, typename Handler>
2300FMT_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;
2306 for (;;) {
2307 switch (to_ascii(*p)) {
2308 case '<':
2309 align = align::left;
2310 break;
2311 case '>':
2312 align = align::right;
2313 break;
2314 case '^':
2315 align = align::center;
2316 break;
2317 default:
2318 break;
2319 }
2320 if (align != align::none) {
2321 if (p != begin) {
2322 auto c = *begin;
2323 if (c == '{')
2324 return handler.on_error("invalid fill character '{'"), begin;
2325 handler.on_fill(basic_string_view<Char>(begin, to_unsigned(p - begin)));
2326 begin = p + 1;
2327 } else
2328 ++begin;
2329 handler.on_align(align);
2330 break;
2331 } else if (p == begin) {
2332 break;
2333 }
2334 p = begin;
2335 }
2336 return begin;
2337}
2338
2339template <typename Char> FMT_CONSTEXPR bool is_name_start(Char c) {
2340 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
2341}
2342
2343template <typename Char, typename IDHandler>
2344FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end,
2345 IDHandler&& handler) -> const Char* {
2346 FMT_ASSERT(begin != end, "");
2347 Char c = *begin;
2348 if (c >= '0' && c <= '9') {
2349 int index = 0;
2350 if (c != '0')
2351 index =
2352 parse_nonnegative_int(begin, end, (std::numeric_limits<int>::max)());
2353 else
2354 ++begin;
2355 if (begin == end || (*begin != '}' && *begin != ':'))
2356 handler.on_error("invalid format string");
2357 else
2358 handler(index);
2359 return begin;
2360 }
2361 if (!is_name_start(c)) {
2362 handler.on_error("invalid format string");
2363 return begin;
2364 }
2365 auto it = begin;
2366 do {
2367 ++it;
2368 } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9')));
2369 handler(basic_string_view<Char>(begin, to_unsigned(it - begin)));
2370 return it;
2371}
2372
2373template <typename Char, typename IDHandler>
2374FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end,
2375 IDHandler&& handler) -> const Char* {
2376 Char c = *begin;
2377 if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler);
2378 handler();
2379 return begin;
2380}
2381
2382template <typename Char, typename Handler>
2383FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end,
2384 Handler&& handler) -> const Char* {
2385 using detail::auto_id;
2386 struct width_adapter {
2387 Handler& handler;
2388
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);
2393 }
2394 FMT_CONSTEXPR void on_error(const char* message) {
2395 if (message) handler.on_error(message);
2396 }
2397 };
2398
2399 FMT_ASSERT(begin != end, "");
2400 if ('0' <= *begin && *begin <= '9') {
2401 int width = parse_nonnegative_int(begin, end, -1);
2402 if (width != -1)
2403 handler.on_width(width);
2404 else
2405 handler.on_error("number is too big");
2406 } else if (*begin == '{') {
2407 ++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;
2411 ++begin;
2412 }
2413 return begin;
2414}
2415
2416template <typename Char, typename Handler>
2417FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
2418 Handler&& handler) -> const Char* {
2419 using detail::auto_id;
2420 struct precision_adapter {
2421 Handler& handler;
2422
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);
2427 }
2428 FMT_CONSTEXPR void on_error(const char* message) {
2429 if (message) handler.on_error(message);
2430 }
2431 };
2432
2433 ++begin;
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);
2439 else
2440 handler.on_error("number is too big");
2441 } else if (c == '{') {
2442 ++begin;
2443 if (begin != end)
2444 begin = parse_arg_id(begin, end, precision_adapter{handler});
2445 if (begin == end || *begin++ != '}')
2446 return handler.on_error("invalid format string"), begin;
2447 } else {
2448 return handler.on_error("missing precision specifier"), begin;
2449 }
2450 handler.end_precision();
2451 return begin;
2452}
2453
2454template <typename Char>
2455FMT_CONSTEXPR auto parse_presentation_type(Char type) -> presentation_type {
2456 switch (to_ascii(type)) {
2457 case 'd':
2458 return presentation_type::dec;
2459 case 'o':
2460 return presentation_type::oct;
2461 case 'x':
2462 return presentation_type::hex_lower;
2463 case 'X':
2464 return presentation_type::hex_upper;
2465 case 'b':
2466 return presentation_type::bin_lower;
2467 case 'B':
2468 return presentation_type::bin_upper;
2469 case 'a':
2470 return presentation_type::hexfloat_lower;
2471 case 'A':
2472 return presentation_type::hexfloat_upper;
2473 case 'e':
2474 return presentation_type::exp_lower;
2475 case 'E':
2476 return presentation_type::exp_upper;
2477 case 'f':
2478 return presentation_type::fixed_lower;
2479 case 'F':
2480 return presentation_type::fixed_upper;
2481 case 'g':
2482 return presentation_type::general_lower;
2483 case 'G':
2484 return presentation_type::general_upper;
2485 case 'c':
2486 return presentation_type::chr;
2487 case 's':
2488 return presentation_type::string;
2489 case 'p':
2490 return presentation_type::pointer;
2491 default:
2492 return presentation_type::none;
2493 }
2494}
2495
2496// Parses standard format specifiers and sends notifications about parsed
2497// components to handler.
2498template <typename Char, typename SpecHandler>
2499FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin,
2500 const Char* end,
2501 SpecHandler&& handler)
2502 -> const Char* {
2503 if (1 < end - begin && begin[1] == '}' && is_ascii_letter(*begin) &&
2504 *begin != 'L') {
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);
2509 return begin;
2510 }
2511
2512 if (begin == end) return begin;
2513
2514 begin = parse_align(begin, end, handler);
2515 if (begin == end) return begin;
2516
2517 // Parse sign.
2518 switch (to_ascii(*begin)) {
2519 case '+':
2520 handler.on_sign(sign::plus);
2521 ++begin;
2522 break;
2523 case '-':
2524 handler.on_sign(sign::minus);
2525 ++begin;
2526 break;
2527 case ' ':
2528 handler.on_sign(sign::space);
2529 ++begin;
2530 break;
2531 default:
2532 break;
2533 }
2534 if (begin == end) return begin;
2535
2536 if (*begin == '#') {
2537 handler.on_hash();
2538 if (++begin == end) return begin;
2539 }
2540
2541 // Parse zero flag.
2542 if (*begin == '0') {
2543 handler.on_zero();
2544 if (++begin == end) return begin;
2545 }
2546
2547 begin = parse_width(begin, end, handler);
2548 if (begin == end) return begin;
2549
2550 // Parse precision.
2551 if (*begin == '.') {
2552 begin = parse_precision(begin, end, handler);
2553 if (begin == end) return begin;
2554 }
2555
2556 if (*begin == 'L') {
2557 handler.on_localized();
2558 ++begin;
2559 }
2560
2561 // Parse type.
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);
2567 }
2568 return begin;
2569}
2570
2571template <typename Char, typename Handler>
2572FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end,
2573 Handler&& handler) -> const Char* {
2574 struct id_adapter {
2575 Handler& handler;
2576 int arg_id;
2577
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);
2582 }
2583 FMT_CONSTEXPR void on_error(const char* message) {
2584 if (message) handler.on_error(message);
2585 }
2586 };
2587
2588 ++begin;
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);
2594 } else {
2595 auto adapter = id_adapter{handler, 0};
2596 begin = parse_arg_id(begin, end, adapter);
2597 Char c = begin != end ? *begin : Char();
2598 if (c == '}') {
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;
2604 } else {
2605 return handler.on_error("missing '}' in format string"), end;
2606 }
2607 }
2608 return begin + 1;
2609}
2610
2611template <bool IS_CONSTEXPR, typename Char, typename Handler>
2612FMT_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.
2615 using detail::find;
2616
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;
2622 while (p != end) {
2623 auto c = *p++;
2624 if (c == '{') {
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);
2631 begin = ++p;
2632 }
2633 }
2634 handler.on_text(begin, end);
2635 return;
2636 }
2637 struct writer {
2638 FMT_CONSTEXPR void operator()(const Char* pbegin, const Char* pend) {
2639 if (pbegin == pend) return;
2640 for (;;) {
2641 const Char* p = nullptr;
2642 if (!find<IS_CONSTEXPR>(pbegin, pend, Char('}'), p))
2643 return handler_.on_text(pbegin, pend);
2644 ++p;
2645 if (p == pend || *p != '}')
2646 return handler_.on_error("unmatched '}' in format string");
2647 handler_.on_text(pbegin, p);
2648 pbegin = p + 1;
2649 }
2650 }
2651 Handler& handler_;
2652 } write{handler};
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);
2659 write(begin, p);
2660 begin = parse_replacement_field(p, end, handler);
2661 }
2662}
2663
2664template <typename T, typename ParseContext>
2665FMT_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);
2676}
2677
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.
2682template <typename Char, typename ErrorHandler = error_handler>
2683class compile_parse_context
2684 : public basic_format_parse_context<Char, ErrorHandler> {
2685 private:
2686 int num_args_;
2687 using base = basic_format_parse_context<Char, ErrorHandler>;
2688
2689 public:
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) {}
2694
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");
2698 return id;
2699 }
2700
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");
2704 }
2705 using base::check_arg_id;
2706};
2707
2708template <typename ErrorHandler>
2709FMT_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");
2713}
2714
2715// Checks char specs and returns true if the type spec is char (and not int).
2716template <typename Char, typename ErrorHandler = error_handler>
2717FMT_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);
2722 return false;
2723 }
2724 if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
2725 eh.on_error("invalid format specifier for char");
2726 return true;
2727}
2728
2729// A floating-point presentation format.
2730enum 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.
2734 hex
2735};
2736
2737struct float_specs {
2738 int precision;
2739 float_format format : 8;
2740 sign_t sign : 8;
2741 bool upper : 1;
2742 bool locale : 1;
2743 bool binary32 : 1;
2744 bool fallback : 1;
2745 bool showpoint : 1;
2746};
2747
2748template <typename ErrorHandler = error_handler, typename Char>
2749FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs<Char>& specs,
2750 ErrorHandler&& eh = {})
2751 -> float_specs {
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;
2758 break;
2759 case presentation_type::general_upper:
2760 result.upper = true;
2761 FMT_FALLTHROUGH;
2762 case presentation_type::general_lower:
2763 result.format = float_format::general;
2764 break;
2765 case presentation_type::exp_upper:
2766 result.upper = true;
2767 FMT_FALLTHROUGH;
2768 case presentation_type::exp_lower:
2769 result.format = float_format::exp;
2770 result.showpoint |= specs.precision != 0;
2771 break;
2772 case presentation_type::fixed_upper:
2773 result.upper = true;
2774 FMT_FALLTHROUGH;
2775 case presentation_type::fixed_lower:
2776 result.format = float_format::fixed;
2777 result.showpoint |= specs.precision != 0;
2778 break;
2779 case presentation_type::hexfloat_upper:
2780 result.upper = true;
2781 FMT_FALLTHROUGH;
2782 case presentation_type::hexfloat_lower:
2783 result.format = float_format::hex;
2784 break;
2785 default:
2786 eh.on_error("invalid type specifier");
2787 break;
2788 }
2789 return result;
2790}
2791
2792template <typename ErrorHandler = error_handler>
2793FMT_CONSTEXPR auto check_cstring_type_spec(presentation_type type,
2794 ErrorHandler&& eh = {}) -> bool {
2795 if (type == presentation_type::none || type == presentation_type::string)
2796 return true;
2797 if (type != presentation_type::pointer) eh.on_error("invalid type specifier");
2798 return false;
2799}
2800
2801template <typename ErrorHandler = error_handler>
2802FMT_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");
2806}
2807
2808template <typename ErrorHandler>
2809FMT_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");
2813}
2814
2815// A parse_format_specs handler that checks if specifiers are consistent with
2816// the argument type.
2817template <typename Handler> class specs_checker : public Handler {
2818 private:
2819 detail::type arg_type_;
2820
2821 FMT_CONSTEXPR void require_numeric_argument() {
2822 if (!is_arithmetic_type(arg_type_))
2823 this->on_error("format specifier requires numeric argument");
2824 }
2825
2826 public:
2827 FMT_CONSTEXPR specs_checker(const Handler& handler, detail::type arg_type)
2828 : Handler(handler), arg_type_(arg_type) {}
2829
2830 FMT_CONSTEXPR void on_align(align_t align) {
2831 if (align == align::numeric) require_numeric_argument();
2832 Handler::on_align(align);
2833 }
2834
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");
2840 }
2841 Handler::on_sign(s);
2842 }
2843
2844 FMT_CONSTEXPR void on_hash() {
2845 require_numeric_argument();
2846 Handler::on_hash();
2847 }
2848
2849 FMT_CONSTEXPR void on_localized() {
2850 require_numeric_argument();
2851 Handler::on_localized();
2852 }
2853
2854 FMT_CONSTEXPR void on_zero() {
2855 require_numeric_argument();
2856 Handler::on_zero();
2857 }
2858
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");
2862 }
2863};
2864
2865constexpr int invalid_arg_index = -1;
2866
2867#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
2868template <int N, typename T, typename... Args, typename Char>
2869constexpr 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;
2872 }
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;
2877}
2878#endif
2879
2880template <typename... Args, typename Char>
2881FMT_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);
2885#endif
2886 (void)name;
2887 return invalid_arg_index;
2888}
2889
2890template <typename Char, typename ErrorHandler, typename... Args>
2891class format_string_checker {
2892 private:
2893 using parse_context_type = compile_parse_context<Char, ErrorHandler>;
2894 enum { num_args = sizeof...(Args) };
2895
2896 // Format specifier parsing function.
2897 using parse_func = const Char* (*)(parse_context_type&);
2898
2899 parse_context_type context_;
2900 parse_func parse_funcs_[num_args > 0 ? num_args : 1];
2901
2902 public:
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>...} {}
2907
2908 FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
2909
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;
2913 }
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;
2919#else
2920 (void)id;
2921 on_error("compile-time checks for named arguments require C++20 support");
2922 return 0;
2923#endif
2924 }
2925
2926 FMT_CONSTEXPR void on_replacement_field(int, const Char*) {}
2927
2928 FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char*)
2929 -> 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;
2933 }
2934
2935 FMT_CONSTEXPR void on_error(const char* message) {
2936 context_.on_error(message);
2937 }
2938};
2939
2940template <typename... Args, typename S,
2941 enable_if_t<(is_compile_string<S>::value), int>>
2942void 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);
2949}
2950
2951template <typename Char>
2952void vformat_to(
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 = {});
2956
2957FMT_API void vprint_mojibake(std::FILE*, string_view, format_args);
2958#ifndef _WIN32
2959inline void vprint_mojibake(std::FILE*, string_view, format_args) {}
2960#endif
2961FMT_END_DETAIL_NAMESPACE
2962
2963// A formatter specialization for the core types corresponding to detail::type
2964// constants.
2965template <typename T, typename Char>
2966struct formatter<T, Char,
2967 enable_if_t<detail::type_constant<T, Char>::value !=
2968 detail::type::custom_type>> {
2969 private:
2970 detail::dynamic_format_specs<Char> specs_;
2971
2972 public:
2973 // Parses format specifiers stopping either at the end of the range or at the
2974 // terminating '}'.
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;
2981 auto checker =
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();
2985 switch (type) {
2986 case detail::type::none_type:
2987 FMT_ASSERT(false, "invalid argument type");
2988 break;
2989 case detail::type::bool_type:
2990 if (specs_.type == presentation_type::none ||
2991 specs_.type == presentation_type::string) {
2992 break;
2993 }
2994 FMT_FALLTHROUGH;
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);
3002 break;
3003 case detail::type::char_type:
3004 detail::check_char_specs(specs_, eh);
3005 break;
3006 case detail::type::float_type:
3007 if (detail::const_check(FMT_USE_FLOAT))
3008 detail::parse_float_type_spec(specs_, eh);
3009 else
3010 FMT_ASSERT(false, "float support disabled");
3011 break;
3012 case detail::type::double_type:
3013 if (detail::const_check(FMT_USE_DOUBLE))
3014 detail::parse_float_type_spec(specs_, eh);
3015 else
3016 FMT_ASSERT(false, "double support disabled");
3017 break;
3018 case detail::type::long_double_type:
3019 if (detail::const_check(FMT_USE_LONG_DOUBLE))
3020 detail::parse_float_type_spec(specs_, eh);
3021 else
3022 FMT_ASSERT(false, "long double support disabled");
3023 break;
3024 case detail::type::cstring_type:
3025 detail::check_cstring_type_spec(specs_.type, eh);
3026 break;
3027 case detail::type::string_type:
3028 detail::check_string_type_spec(specs_.type, eh);
3029 break;
3030 case detail::type::pointer_type:
3031 detail::check_pointer_type_spec(specs_.type, eh);
3032 break;
3033 case detail::type::custom_type:
3034 // Custom format specifiers are checked in parse functions of
3035 // formatter specializations.
3036 break;
3037 }
3038 return it;
3039 }
3040
3041 template <typename FormatContext>
3042 FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const
3043 -> decltype(ctx.out());
3044};
3045
3046template <typename Char> struct basic_runtime { basic_string_view<Char> str; };
3047
3048/** A compile-time format string. */
3049template <typename Char, typename... Args> class basic_format_string {
3050 private:
3051 basic_string_view<Char> str_;
3052
3053 public:
3054 template <typename S,
3055 FMT_ENABLE_IF(
3056 std::is_convertible<const S&, basic_string_view<Char>>::value)>
3057 FMT_CONSTEVAL FMT_INLINE basic_format_string(const S& s) : str_(s) {
3058 static_assert(
3059 detail::count<
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, {}));
3069 }
3070#else
3071 detail::check_format_string<Args...>(s);
3072#endif
3073 }
3074 basic_format_string(basic_runtime<Char> r) : str_(r.str) {}
3075
3076 FMT_INLINE operator basic_string_view<Char>() const { return str_; }
3077};
3078
3079#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
3080// Workaround broken conversion on older gcc.
3081template <typename... Args> using format_string = string_view;
3082template <typename S> auto runtime(const S& s) -> basic_string_view<char_t<S>> {
3083 return s;
3084}
3085#else
3086template <typename... Args>
3087using format_string = basic_format_string<char, type_identity_t<Args>...>;
3088/**
3089 \rst
3090 Creates a runtime format string.
3091
3092 **Example**::
3093
3094 // Check format string at runtime instead of compile-time.
3095 fmt::print(fmt::runtime("{:d}"), "I am not a number");
3096 \endrst
3097 */
3098template <typename S> auto runtime(const S& s) -> basic_runtime<char_t<S>> {
3099 return {{s}};
3100}
3101#endif
3102
3103FMT_API auto vformat(string_view fmt, format_args args) -> std::string;
3104
3105/**
3106 \rst
3107 Formats ``args`` according to specifications in ``fmt`` and returns the result
3108 as a string.
3109
3110 **Example**::
3111
3112 #include <fmt/core.h>
3113 std::string message = fmt::format("The answer is {}.", 42);
3114 \endrst
3115*/
3116template <typename... T>
3117FMT_NODISCARD FMT_INLINE auto format(format_string<T...> fmt, T&&... args)
3118 -> std::string {
3119 return vformat(fmt, fmt::make_format_args(args...));
3120}
3121
3122/** Formats a string and writes the output to ``out``. */
3123template <typename OutputIt,
3124 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3125auto 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);
3130}
3131
3132/**
3133 \rst
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.
3137
3138 **Example**::
3139
3140 auto out = std::vector<char>();
3141 fmt::format_to(std::back_inserter(out), "{}", 42);
3142 \endrst
3143 */
3144template <typename OutputIt, typename... T,
3145 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3146FMT_INLINE auto format_to(OutputIt out, format_string<T...> fmt, T&&... args)
3147 -> OutputIt {
3148 return vformat_to(out, fmt, fmt::make_format_args(args...));
3149}
3150
3151template <typename OutputIt> struct format_to_n_result {
3152 /** Iterator past the end of the output range. */
3153 OutputIt out;
3154 /** Total (not truncated) output size. */
3155 size_t size;
3156};
3157
3158template <typename OutputIt, typename... T,
3159 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3160auto 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()};
3166}
3167
3168/**
3169 \rst
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.
3174 \endrst
3175 */
3176template <typename OutputIt, typename... T,
3177 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3178FMT_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...));
3181}
3182
3183/** Returns the number of chars in the output of ``format(fmt, args...)``. */
3184template <typename... T>
3185FMT_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...), {});
3189 return buf.count();
3190}
3191
3192FMT_API void vprint(string_view fmt, format_args args);
3193FMT_API void vprint(std::FILE* f, string_view fmt, format_args args);
3194
3195/**
3196 \rst
3197 Formats ``args`` according to specifications in ``fmt`` and writes the output
3198 to ``stdout``.
3199
3200 **Example**::
3201
3202 fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
3203 \endrst
3204 */
3205template <typename... T>
3206FMT_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);
3210}
3211
3212/**
3213 \rst
3214 Formats ``args`` according to specifications in ``fmt`` and writes the
3215 output to the file ``f``.
3216
3217 **Example**::
3218
3219 fmt::print(stderr, "Don't {}!", "panic");
3220 \endrst
3221 */
3222template <typename... T>
3223FMT_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);
3227}
3228
3229FMT_MODULE_EXPORT_END
3230FMT_GCC_PRAGMA("GCC pop_options")
3231FMT_END_NAMESPACE
3232
3233#ifdef FMT_HEADER_ONLY
3234# include "format.h"
3235#endif
3236#endif // FMT_CORE_H_
This page took 0.168087 seconds and 4 git commands to generate.