SimulationCraft
SimulationCraft is a tool to explore combat mechanics in the popular MMO RPG World of Warcraft (tm).
core.h
1 // Formatting library for C++ - the core API for char/UTF-8
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7 
8 #ifndef FMT_CORE_H_
9 #define FMT_CORE_H_
10 
11 #include <cstddef> // std::byte
12 #include <cstdio> // std::FILE
13 #include <cstring>
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.
311 FMT_GCC_PRAGMA("GCC push_options")
312 #ifndef __OPTIMIZE__
313 FMT_GCC_PRAGMA("GCC optimize(\"Og\")")
314 #endif
315 
316 FMT_BEGIN_NAMESPACE
317 FMT_MODULE_EXPORT_BEGIN
318 
319 // Implementations of enable_if_t and other metafunctions for older systems.
320 template <bool B, typename T = void>
321 using enable_if_t = typename std::enable_if<B, T>::type;
322 template <bool B, typename T, typename F>
323 using conditional_t = typename std::conditional<B, T, F>::type;
324 template <bool B> using bool_constant = std::integral_constant<bool, B>;
325 template <typename T>
326 using remove_reference_t = typename std::remove_reference<T>::type;
327 template <typename T>
328 using remove_const_t = typename std::remove_const<T>::type;
329 template <typename T>
330 using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
331 template <typename T> struct type_identity { using type = T; };
332 template <typename T> using type_identity_t = typename type_identity<T>::type;
333 
334 struct 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 
347 FMT_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.
352 template <typename... T> FMT_CONSTEXPR void ignore_unused(const T&...) {}
353 
354 constexpr FMT_INLINE auto is_constant_evaluated(bool default_value = false)
355  FMT_NOEXCEPT -> bool {
356 #ifdef __cpp_lib_is_constant_evaluated
357  ignore_unused(default_value);
358  return std::is_constant_evaluated();
359 #else
360  return default_value;
361 #endif
362 }
363 
364 // A function to suppress "conditional expression is constant" warnings.
365 template <typename T> constexpr FMT_INLINE auto const_check(T value) -> T {
366  return value;
367 }
368 
369 FMT_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
386 using byte = std::byte;
387 #else
388 enum class byte : unsigned char {};
389 #endif
390 
391 #if defined(FMT_USE_STRING_VIEW)
392 template <typename Char> using std_string_view = std::basic_string_view<Char>;
393 #elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
394 template <typename Char>
395 using std_string_view = std::experimental::basic_string_view<Char>;
396 #else
397 template <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
405 using int128_t = __int128_t;
406 using uint128_t = __uint128_t;
407 template <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
414 enum class int128_t {};
415 enum class uint128_t {};
416 // Reduce template instantiations.
417 template <typename T> inline auto convert_for_visit(T) -> monostate {
418  return {};
419 }
420 #endif
421 
422 // Casts a nonnegative integer to unsigned.
423 template <typename Int>
424 FMT_CONSTEXPR auto to_unsigned(Int value) ->
425  typename std::make_unsigned<Int>::type {
426  FMT_ASSERT(value >= 0, "negative value");
427  return static_cast<typename std::make_unsigned<Int>::type>(value);
428 }
429 
430 FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5";
431 
432 constexpr auto is_utf8() -> bool {
433  // Avoid buggy sign extensions in MSVC's constant evaluation mode.
434  // https://developercommunity.visualstudio.com/t/C-difference-in-behavior-for-unsigned/1233612
435  using uchar = unsigned char;
436  return FMT_UNICODE || (sizeof(micro) == 3 && uchar(micro[0]) == 0xC2 &&
437  uchar(micro[1]) == 0xB5);
438 }
439 FMT_END_DETAIL_NAMESPACE
440 
448 template <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 
460  constexpr basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT
461  : data_(s),
462  size_(count) {}
463 
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 
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 
492  constexpr auto data() const FMT_NOEXCEPT -> const Char* { return data_; }
493 
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 
541 
543 template <typename T> struct is_char : std::false_type {};
544 template <> struct is_char<char> : std::true_type {};
545 
546 // Returns a string view of `s`.
547 template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
548 FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view<Char> {
549  return s;
550 }
551 template <typename Char, typename Traits, typename Alloc>
552 inline auto to_string_view(const std::basic_string<Char, Traits, Alloc>& s)
554  return s;
555 }
556 template <typename Char>
557 constexpr auto to_string_view(basic_string_view<Char> s)
559  return s;
560 }
561 template <typename Char,
562  FMT_ENABLE_IF(!std::is_empty<detail::std_string_view<Char>>::value)>
563 inline auto to_string_view(detail::std_string_view<Char> s)
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).
570 struct compile_string {};
571 
572 template <typename S>
573 struct is_compile_string : std::is_base_of<compile_string, S> {};
574 
575 template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
576 constexpr auto to_string_view(const S& s)
579 }
580 
581 FMT_BEGIN_DETAIL_NAMESPACE
582 
583 void to_string_view(...);
584 using 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.
589 template <typename S>
590 struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> {
591 };
592 
593 template <typename S, typename = void> struct char_t_impl {};
594 template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
595  using result = decltype(to_string_view(std::declval<S>()));
596  using type = typename result::value_type;
597 };
598 
599 // Reports a compile-time error if S is not a valid format string.
600 template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
601 FMT_INLINE void check_format_string(const S&) {
602 #ifdef FMT_ENFORCE_COMPILE_STRING
603  static_assert(is_compile_string<S>::value,
604  "FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
605  "FMT_STRING.");
606 #endif
607 }
608 template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
609 void check_format_string(S);
610 
611 FMT_NORETURN FMT_API void throw_format_error(const char* message);
612 
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 };
620 FMT_END_DETAIL_NAMESPACE
621 
623 template <typename S> using char_t = typename detail::char_t_impl<S>::type;
624 
632 template <typename Char, typename ErrorHandler = detail::error_handler>
633 class 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 
651  constexpr auto begin() const FMT_NOEXCEPT -> iterator {
652  return format_str_.begin();
653  }
654 
658  constexpr auto end() const FMT_NOEXCEPT -> iterator {
659  return format_str_.end();
660  }
661 
663  FMT_CONSTEXPR void advance_to(iterator it) {
664  format_str_.remove_prefix(detail::to_unsigned(it - begin()));
665  }
666 
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 
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 
700 
701 template <typename Context> class basic_format_arg;
702 template <typename Context> class basic_format_args;
703 template <typename Context> class dynamic_format_arg_store;
704 
705 // A formatter for objects of type T.
706 template <typename T, typename Char = char, typename Enable = void>
707 struct 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.
714 template <typename T, typename Context>
715 using has_formatter =
716  std::is_constructible<typename Context::template formatter_type<T>>;
717 
718 // Checks whether T is a container with contiguous storage.
719 template <typename T> struct is_contiguous : std::false_type {};
720 template <typename Char>
721 struct is_contiguous<std::basic_string<Char>> : std::true_type {};
722 
723 class appender;
724 
725 FMT_BEGIN_DETAIL_NAMESPACE
726 
727 template <typename Context, typename T>
728 constexpr auto has_const_formatter_impl(T*)
729  -> decltype(typename Context::template formatter_type<T>().format(
730  std::declval<const T&>(), std::declval<Context&>()),
731  true) {
732  return true;
733 }
734 template <typename Context>
735 constexpr auto has_const_formatter_impl(...) -> bool {
736  return false;
737 }
738 template <typename T, typename Context>
739 constexpr 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.
744 template <typename Container>
745 inline 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 
755 template <typename Char, typename InputIt, typename OutputIt>
756 FMT_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 
762 template <typename Char, typename T, typename U,
763  FMT_ENABLE_IF(
764  std::is_same<remove_const_t<T>, U>::value&& is_char<U>::value)>
765 FMT_CONSTEXPR auto copy_str(T* begin, T* end, U* out) -> U* {
766  if (is_constant_evaluated()) return copy_str<Char, T*, U*>(begin, end, out);
767  auto size = to_unsigned(end - begin);
768  memcpy(out, begin, size * sizeof(U));
769  return out + size;
770 }
771 
778 template <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 
798  FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT {
799  ptr_ = buf_data;
800  capacity_ = buf_capacity;
801  }
802 
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 
820  constexpr auto size() const FMT_NOEXCEPT -> size_t { return size_; }
821 
823  constexpr auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; }
824 
826  FMT_CONSTEXPR auto data() FMT_NOEXCEPT -> T* { return ptr_; }
827 
829  FMT_CONSTEXPR auto data() const FMT_NOEXCEPT -> const T* { return ptr_; }
830 
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 
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 
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 
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.
888 template <typename OutputIt, typename T, typename Traits = buffer_traits>
889 class 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) {}
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 
920 template <typename T>
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) {}
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 
966 template <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.
977 template <typename Container>
978 class iterator_buffer<std::back_insert_iterator<Container>,
979  enable_if_t<is_contiguous<Container>::value,
980  typename Container::value_type>>
981  final : public buffer<typename Container::value_type> {
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.
1002 template <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 
1021 template <typename T>
1022 using 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.
1026 template <typename T, typename OutputIt>
1027 auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
1028  return iterator_buffer<OutputIt, T>(out);
1029 }
1030 
1031 template <typename Buffer>
1032 auto get_iterator(Buffer& buf) -> decltype(buf.out()) {
1033  return buf.out();
1034 }
1035 template <typename T> auto get_iterator(buffer<T>& buf) -> buffer_appender<T> {
1036  return buffer_appender<T>(buf);
1037 }
1038 
1039 template <typename T, typename Char = char, typename Enable = void>
1041  fallback_formatter() = delete;
1042 };
1043 
1044 // Specifies if T has an enabled fallback_formatter specialization.
1045 template <typename T, typename Char>
1046 using has_fallback_formatter =
1047  std::is_constructible<fallback_formatter<T, Char>>;
1048 
1049 struct view {};
1050 
1051 template <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 
1057 template <typename Char> struct named_arg_info {
1058  const Char* name;
1059  int id;
1060 };
1061 
1062 template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
1063 struct 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 
1076 template <typename T, typename Char, size_t NUM_ARGS>
1077 struct arg_data<T, Char, NUM_ARGS, 0> {
1078  // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
1079  T args_[NUM_ARGS != 0 ? NUM_ARGS : +1];
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 
1089 template <typename Char>
1090 inline void init_named_args(named_arg_info<Char>*, int, int) {}
1091 
1092 template <typename T> struct is_named_arg : std::false_type {};
1093 template <typename T> struct is_statically_named_arg : std::false_type {};
1094 
1095 template <typename T, typename Char>
1096 struct is_named_arg<named_arg<Char, T>> : std::true_type {};
1097 
1098 template <typename Char, typename T, typename... Tail,
1099  FMT_ENABLE_IF(!is_named_arg<T>::value)>
1100 void init_named_args(named_arg_info<Char>* named_args, int arg_count,
1101  int named_arg_count, const T&, const Tail&... args) {
1102  init_named_args(named_args, arg_count + 1, named_arg_count, args...);
1103 }
1104 
1105 template <typename Char, typename T, typename... Tail,
1106  FMT_ENABLE_IF(is_named_arg<T>::value)>
1107 void init_named_args(named_arg_info<Char>* named_args, int arg_count,
1108  int named_arg_count, const T& arg, const Tail&... args) {
1109  named_args[named_arg_count++] = {arg.name, arg_count};
1110  init_named_args(named_args, arg_count + 1, named_arg_count, args...);
1111 }
1112 
1113 template <typename... Args>
1114 FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int,
1115  const Args&...) {}
1116 
1117 template <bool B = false> constexpr auto count() -> size_t { return B ? 1 : 0; }
1118 template <bool B1, bool B2, bool... Tail> constexpr auto count() -> size_t {
1119  return (B1 ? 1 : 0) + count<B2, Tail...>();
1120 }
1121 
1122 template <typename... Args> constexpr auto count_named_args() -> size_t {
1123  return count<is_named_arg<Args>::value...>();
1124 }
1125 
1126 template <typename... Args>
1127 constexpr auto count_statically_named_args() -> size_t {
1128  return count<is_statically_named_arg<Args>::value...>();
1129 }
1130 
1131 enum 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.
1155 template <typename T, typename Char>
1156 struct 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 
1163 FMT_TYPE_CONSTANT(int, int_type);
1164 FMT_TYPE_CONSTANT(unsigned, uint_type);
1165 FMT_TYPE_CONSTANT(long long, long_long_type);
1166 FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
1167 FMT_TYPE_CONSTANT(int128_t, int128_type);
1168 FMT_TYPE_CONSTANT(uint128_t, uint128_type);
1169 FMT_TYPE_CONSTANT(bool, bool_type);
1170 FMT_TYPE_CONSTANT(Char, char_type);
1171 FMT_TYPE_CONSTANT(float, float_type);
1172 FMT_TYPE_CONSTANT(double, double_type);
1173 FMT_TYPE_CONSTANT(long double, long_double_type);
1174 FMT_TYPE_CONSTANT(const Char*, cstring_type);
1175 FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
1176 FMT_TYPE_CONSTANT(const void*, pointer_type);
1177 
1178 constexpr bool is_integral_type(type t) {
1179  return t > type::none_type && t <= type::last_integer_type;
1180 }
1181 
1182 constexpr bool is_arithmetic_type(type t) {
1183  return t > type::none_type && t <= type::last_numeric_type;
1184 }
1185 
1186 struct unformattable {};
1190 
1191 template <typename Char> struct string_value {
1192  const Char* data;
1193  size_t size;
1194 };
1195 
1196 template <typename Char> struct named_arg_value {
1197  const named_arg_info<Char>* data;
1198  size_t size;
1199 };
1200 
1201 template <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.
1208 template <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>,
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 
1286 template <typename Context, typename T>
1287 FMT_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.
1291 enum { long_short = sizeof(long) == sizeof(int) };
1292 using long_type = conditional_t<long_short, int, long long>;
1293 using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
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.
1298 template <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)
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)
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)
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>>
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>.
1491 template <typename T, typename Context>
1492 using mapped_type_constant =
1493  type_constant<decltype(arg_mapper<Context>().map(std::declval<const T&>())),
1494  typename Context::char_type>;
1495 
1496 enum { packed_arg_bits = 4 };
1497 // Maximum number of arguments with packed types.
1498 enum { max_packed_args = 62 / packed_arg_bits };
1499 enum : unsigned long long { is_unpacked_bit = 1ULL << 63 };
1500 enum : unsigned long long { has_named_args_bit = 1ULL << 62 };
1501 
1502 FMT_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.
1506 class 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.
1526 template <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)
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 
1586 template <typename Visitor, typename Context>
1587 FMT_CONSTEXPR FMT_INLINE auto visit_format_arg(
1588  Visitor&& vis, const basic_format_arg<Context>& arg) -> decltype(vis(0)) {
1589  switch (arg.type_) {
1590  case detail::type::none_type:
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:
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 
1627 FMT_BEGIN_DETAIL_NAMESPACE
1628 
1629 template <typename Char, typename InputIt>
1630 auto 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.
1637 template <typename... Ts> struct void_t_impl { using type = void; };
1638 template <typename... Ts>
1639 using void_t = typename detail::void_t_impl<Ts...>::type;
1640 #else
1641 template <typename...> using void_t = void;
1642 #endif
1643 
1644 template <typename It, typename T, typename Enable = void>
1645 struct is_output_iterator : std::false_type {};
1646 
1647 template <typename It, typename T>
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 
1654 template <typename OutputIt>
1655 struct is_back_insert_iterator : std::false_type {};
1656 template <typename Container>
1657 struct is_back_insert_iterator<std::back_insert_iterator<Container>>
1658  : std::true_type {};
1659 
1660 template <typename OutputIt>
1661 struct is_contiguous_back_insert_iterator : std::false_type {};
1662 template <typename Container>
1663 struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
1664  : is_contiguous<Container> {};
1665 template <>
1666 struct is_contiguous_back_insert_iterator<appender> : std::true_type {};
1667 
1668 // A type-erased reference to an std::locale to avoid heavy <locale> include.
1669 class 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 
1682 template <typename> constexpr auto encode_types() -> unsigned long long {
1683  return 0;
1684 }
1685 
1686 template <typename Context, typename Arg, typename... Args>
1687 constexpr auto encode_types() -> unsigned long long {
1688  return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) |
1689  (encode_types<Context, Args...>() << packed_arg_bits);
1690 }
1691 
1692 template <typename Context, typename T>
1693 FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context> {
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).
1703 template <bool IS_PACKED, typename Context, type, typename T,
1704  FMT_ENABLE_IF(IS_PACKED)>
1705 FMT_CONSTEXPR FMT_INLINE auto make_arg(T&& val) -> value<Context> {
1706  const auto& arg = arg_mapper<Context>().map(std::forward<T>(val));
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 
1734 template <bool IS_PACKED, typename Context, type, typename T,
1735  FMT_ENABLE_IF(!IS_PACKED)>
1736 inline auto make_arg(const T& value) -> basic_format_arg<Context> {
1737  return make_arg<Context>(value);
1738 }
1739 FMT_END_DETAIL_NAMESPACE
1740 
1741 // Formatting context.
1742 template <typename OutputIt, typename Char> class basic_format_context {
1743  public:
1745  using char_type = Char;
1746 
1747  private:
1748  OutputIt out_;
1750  detail::locale_ref loc_;
1751 
1752  public:
1753  using iterator = OutputIt;
1756  template <typename T> using formatter_type = formatter<T, char_type>;
1757 
1759  basic_format_context(const basic_format_context&) = delete;
1760  void operator=(const basic_format_context&) = delete;
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 
1795 template <typename Char>
1796 using buffer_context =
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 
1804 template <typename T, typename Char = char>
1805 using is_formattable = bool_constant<
1806  !std::is_base_of<detail::unformattable,
1807  decltype(detail::arg_mapper<buffer_context<Char>>().map(
1808  std::declval<T>()))>::value &&
1809  !detail::has_fallback_formatter<T, Char>::value>;
1810 
1818 template <typename Context, typename... Args>
1820 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1821  // Workaround a GCC template argument substitution bug.
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>,
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
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 
1869 template <typename Context = format_context, typename... Args>
1870 constexpr auto make_format_args(Args&&... args)
1872  return {std::forward<Args>(args)...};
1873 }
1874 
1886 template <typename Char, typename T>
1887 inline auto arg(const Char* name, const T& arg) -> detail::named_arg<Char, T> {
1888  static_assert(!detail::is_named_arg<T>(), "nested named arguments");
1889  return {name, arg};
1890 }
1891 
1902 template <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 
1950  template <typename... Args>
1951  constexpr FMT_INLINE basic_format_args(
1953  : basic_format_args(format_arg_store<Context, Args...>::desc,
1954  store.data_.args()) {}
1955 
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 
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 
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 
2014 // A separate type would result in shorter symbols but break ABI compatibility
2015 // between clang and gcc on ARM (#1919).
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.
2020 namespace align {
2021 enum type { none, left, right, center, numeric };
2022 }
2023 using align_t = align::type;
2024 namespace sign {
2025 enum type { none, minus, plus, space };
2026 }
2027 using sign_t = sign::type;
2028 
2029 FMT_BEGIN_DETAIL_NAMESPACE
2030 
2031 // Workaround an array initialization issue in gcc 4.8.
2032 template <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 };
2054 FMT_END_DETAIL_NAMESPACE
2055 
2056 enum 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.
2079 template <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 
2100 
2101 FMT_BEGIN_DETAIL_NAMESPACE
2102 
2103 enum class arg_id_kind { none, index, name };
2104 
2105 // An argument reference.
2106 template <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;
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).
2133 template <typename Char>
2135  arg_ref<Char> width_ref;
2136  arg_ref<Char> precision_ref;
2137 };
2138 
2139 struct auto_id {};
2140 
2141 // A format specifier handler that sets fields in basic_format_specs.
2142 template <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.
2177 template <typename ParseContext>
2179  : public specs_setter<typename ParseContext::char_type> {
2180  public:
2181  using char_type = typename ParseContext::char_type;
2182 
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:
2206  ParseContext& context_;
2207 
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 
2228 template <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.
2233 template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
2234 constexpr auto to_ascii(Char value) -> Char {
2235  return value;
2236 }
2237 template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
2238 constexpr auto to_ascii(Char value) ->
2239  typename std::underlying_type<Char>::type {
2240  return value;
2241 }
2242 
2243 template <typename Char>
2244 FMT_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.
2257 template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
2258 FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool {
2259  for (out = first; out != last; ++out) {
2260  if (*out == value) return true;
2261  }
2262  return false;
2263 }
2264 
2265 template <>
2266 inline auto find<false, char>(const char* first, const char* last, char value,
2267  const char*& out) -> bool {
2268  out = static_cast<const char*>(
2269  std::memchr(first, value, to_unsigned(last - first)));
2270  return out != nullptr;
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.
2275 template <typename Char>
2276 FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end,
2277  int error_value) noexcept -> int {
2278  FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', "");
2279  unsigned value = 0, prev = 0;
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.
2299 template <typename Char, typename Handler>
2300 FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
2301  Handler&& handler) -> const Char* {
2302  FMT_ASSERT(begin != end, "");
2303  auto align = align::none;
2304  auto p = begin + code_point_length(begin);
2305  if (p >= end) p = begin;
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 
2339 template <typename Char> FMT_CONSTEXPR bool is_name_start(Char c) {
2340  return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
2341 }
2342 
2343 template <typename Char, typename IDHandler>
2344 FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end,
2345  IDHandler&& handler) -> const Char* {
2346  FMT_ASSERT(begin != end, "");
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 
2373 template <typename Char, typename IDHandler>
2374 FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end,
2375  IDHandler&& handler) -> const Char* {
2376  Char c = *begin;
2377  if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler);
2378  handler();
2379  return begin;
2380 }
2381 
2382 template <typename Char, typename Handler>
2383 FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end,
2384  Handler&& handler) -> const Char* {
2385  using detail::auto_id;
2386  struct width_adapter {
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 
2416 template <typename Char, typename Handler>
2417 FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
2418  Handler&& handler) -> const Char* {
2419  using detail::auto_id;
2420  struct precision_adapter {
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 
2454 template <typename Char>
2455 FMT_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.
2498 template <typename Char, typename SpecHandler>
2499 FMT_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 
2571 template <typename Char, typename Handler>
2572 FMT_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 
2611 template <bool IS_CONSTEXPR, typename Char, typename Handler>
2612 FMT_CONSTEXPR FMT_INLINE void parse_format_string(
2613  basic_string_view<Char> format_str, Handler&& handler) {
2614  // Workaround a name-lookup bug in MSVC's modules implementation.
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 
2664 template <typename T, typename ParseContext>
2665 FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx)
2666  -> decltype(ctx.begin()) {
2667  using char_type = typename ParseContext::char_type;
2668  using context = buffer_context<char_type>;
2669  using mapped_type = conditional_t<
2670  mapped_type_constant<T, context>::value != type::custom_type,
2671  decltype(arg_mapper<context>().map(std::declval<const T&>())), T>;
2672  auto f = conditional_t<has_formatter<mapped_type, context>::value,
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.
2682 template <typename Char, typename ErrorHandler = error_handler>
2684  : public basic_format_parse_context<Char, ErrorHandler> {
2685  private:
2686  int num_args_;
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 
2708 template <typename ErrorHandler>
2709 FMT_CONSTEXPR void check_int_type_spec(presentation_type type,
2710  ErrorHandler&& eh) {
2711  if (type > presentation_type::bin_upper && type != presentation_type::chr)
2712  eh.on_error("invalid type specifier");
2713 }
2714 
2715 // Checks char specs and returns true if the type spec is char (and not int).
2716 template <typename Char, typename ErrorHandler = error_handler>
2717 FMT_CONSTEXPR auto check_char_specs(const basic_format_specs<Char>& specs,
2718  ErrorHandler&& eh = {}) -> bool {
2719  if (specs.type != presentation_type::none &&
2720  specs.type != presentation_type::chr) {
2721  check_int_type_spec(specs.type, eh);
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.
2730 enum class float_format : unsigned char {
2731  general, // General: exponent notation or fixed point based on magnitude.
2732  exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3.
2733  fixed, // Fixed point with the default precision of 6, e.g. 0.0012.
2734  hex
2735 };
2736 
2737 struct 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 
2748 template <typename ErrorHandler = error_handler, typename Char>
2749 FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs<Char>& specs,
2750  ErrorHandler&& eh = {})
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 
2792 template <typename ErrorHandler = error_handler>
2793 FMT_CONSTEXPR auto check_cstring_type_spec(presentation_type type,
2794  ErrorHandler&& eh = {}) -> bool {
2795  if (type == presentation_type::none || type == presentation_type::string)
2796  return true;
2797  if (type != presentation_type::pointer) eh.on_error("invalid type specifier");
2798  return false;
2799 }
2800 
2801 template <typename ErrorHandler = error_handler>
2802 FMT_CONSTEXPR void check_string_type_spec(presentation_type type,
2803  ErrorHandler&& eh = {}) {
2804  if (type != presentation_type::none && type != presentation_type::string)
2805  eh.on_error("invalid type specifier");
2806 }
2807 
2808 template <typename ErrorHandler>
2809 FMT_CONSTEXPR void check_pointer_type_spec(presentation_type type,
2810  ErrorHandler&& eh) {
2811  if (type != presentation_type::none && type != presentation_type::pointer)
2812  eh.on_error("invalid type specifier");
2813 }
2814 
2815 // A parse_format_specs handler that checks if specifiers are consistent with
2816 // the argument type.
2817 template <typename Handler> class specs_checker : public Handler {
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 
2865 constexpr int invalid_arg_index = -1;
2866 
2867 #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
2868 template <int N, typename T, typename... Args, typename Char>
2869 constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
2870  if constexpr (detail::is_statically_named_arg<T>()) {
2871  if (name == T::name) return N;
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 
2880 template <typename... Args, typename Char>
2881 FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
2882 #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
2883  if constexpr (sizeof...(Args) > 0)
2884  return get_arg_index_by_name<0, Args...>(name);
2885 #endif
2886  (void)name;
2887  return invalid_arg_index;
2888 }
2889 
2890 template <typename Char, typename ErrorHandler, typename... Args>
2892  private:
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 
2940 template <typename... Args, typename S,
2941  enable_if_t<(is_compile_string<S>::value), int>>
2942 void check_format_string(S format_str) {
2943  FMT_CONSTEXPR auto s = to_string_view(format_str);
2944  using checker = format_string_checker<typename S::char_type, error_handler,
2945  remove_cvref_t<Args>...>;
2946  FMT_CONSTEXPR bool invalid_format =
2947  (parse_format_string<true>(s, checker(s, {})), true);
2948  ignore_unused(invalid_format);
2949 }
2950 
2951 template <typename Char>
2952 void vformat_to(
2954  basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args,
2955  locale_ref loc = {});
2956 
2957 FMT_API void vprint_mojibake(std::FILE*, string_view, format_args);
2958 #ifndef _WIN32
2959 inline void vprint_mojibake(std::FILE*, string_view, format_args) {}
2960 #endif
2961 FMT_END_DETAIL_NAMESPACE
2962 
2963 // A formatter specialization for the core types corresponding to detail::type
2964 // constants.
2965 template <typename T, typename Char>
2966 struct formatter<T, Char,
2967  enable_if_t<detail::type_constant<T, Char>::value !=
2968  detail::type::custom_type>> {
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 
3046 template <typename Char> struct basic_runtime { basic_string_view<Char> str; };
3047 
3049 template <typename Char, typename... Args> class basic_format_string {
3050  private:
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.
3081 template <typename... Args> using format_string = string_view;
3082 template <typename S> auto runtime(const S& s) -> basic_string_view<char_t<S>> {
3083  return s;
3084 }
3085 #else
3086 template <typename... Args>
3087 using format_string = basic_format_string<char, type_identity_t<Args>...>;
3098 template <typename S> auto runtime(const S& s) -> basic_runtime<char_t<S>> {
3099  return {{s}};
3100 }
3101 #endif
3102 
3103 FMT_API auto vformat(string_view fmt, format_args args) -> std::string;
3104 
3116 template <typename... T>
3117 FMT_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 
3123 template <typename OutputIt,
3124  FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3125 auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt {
3126  using detail::get_buffer;
3127  auto&& buf = get_buffer<char>(out);
3128  detail::vformat_to(buf, fmt, args, {});
3129  return detail::get_iterator(buf);
3130 }
3131 
3144 template <typename OutputIt, typename... T,
3145  FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3146 FMT_INLINE auto format_to(OutputIt out, format_string<T...> fmt, T&&... args)
3147  -> OutputIt {
3148  return vformat_to(out, fmt, fmt::make_format_args(args...));
3149 }
3150 
3151 template <typename OutputIt> struct format_to_n_result {
3153  OutputIt out;
3155  size_t size;
3156 };
3157 
3158 template <typename OutputIt, typename... T,
3159  FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3160 auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args)
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 
3176 template <typename OutputIt, typename... T,
3177  FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3178 FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string<T...> fmt,
3179  T&&... args) -> format_to_n_result<OutputIt> {
3180  return vformat_to_n(out, n, fmt, fmt::make_format_args(args...));
3181 }
3182 
3184 template <typename... T>
3185 FMT_NODISCARD FMT_INLINE auto formatted_size(format_string<T...> fmt,
3186  T&&... args) -> size_t {
3187  auto buf = detail::counting_buffer<>();
3188  detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...), {});
3189  return buf.count();
3190 }
3191 
3192 FMT_API void vprint(string_view fmt, format_args args);
3193 FMT_API void vprint(std::FILE* f, string_view fmt, format_args args);
3194 
3205 template <typename... T>
3206 FMT_INLINE void print(format_string<T...> fmt, T&&... args) {
3207  const auto& vargs = fmt::make_format_args(args...);
3208  return detail::is_utf8() ? vprint(fmt, vargs)
3209  : detail::vprint_mojibake(stdout, fmt, vargs);
3210 }
3211 
3222 template <typename... T>
3223 FMT_INLINE void print(std::FILE* f, format_string<T...> fmt, T&&... args) {
3224  const auto& vargs = fmt::make_format_args(args...);
3225  return detail::is_utf8() ? vprint(f, fmt, vargs)
3226  : detail::vprint_mojibake(f, fmt, vargs);
3227 }
3228 
3229 FMT_MODULE_EXPORT_END
3230 FMT_GCC_PRAGMA("GCC pop_options")
3231 FMT_END_NAMESPACE
3232 
3233 #ifdef FMT_HEADER_ONLY
3234 # include "format.h"
3235 #endif
3236 #endif // FMT_CORE_H_
Definition: core.h:573
Definition: core.h:2020
FMT_CONSTEXPR basic_string_view(const std::basic_string< Char, Traits, Alloc > &s) FMT_NOEXCEPT
Constructs a string reference from a std::basic_string object.
Definition: core.h:481
Definition: core.h:2178
constexpr auto size() const FMT_NOEXCEPT -> size_t
Returns the size of this buffer.
Definition: core.h:820
Definition: core.h:707
Definition: core.h:1057
Definition: core.h:1092
Definition: core.h:889
FMT_CONSTEXPR void advance_to(iterator it)
Advances the begin iterator to it.
Definition: core.h:663
constexpr auto begin() const FMT_NOEXCEPT -> iterator
Returns an iterator to the beginning of the format string range being parsed.
Definition: core.h:651
Definition: core.h:1187
Definition: core.h:590
Definition: core.h:613
Definition: core.h:1201
Definition: core.h:2139
FMT_CONSTEXPR_CHAR_TRAITS FMT_INLINE basic_string_view(const Char *s)
Constructs a string reference object from a C string computing the size with std::char_traits<Char>::...
Definition: core.h:472
Definition: core.h:1188
Definition: span.hpp:609
FMT_CONSTEXPR auto get(int id) const -> format_arg
Returns the argument with the specified id.
Definition: core.h:1976
constexpr FMT_INLINE basic_format_args(const dynamic_format_arg_store< Context > &store)
Constructs a basic_format_args object from ~fmtdynamic_format_arg_store.
Definition: core.h:1962
constexpr FMT_INLINE basic_format_args(const format_arg_store< Context, Args... > &store)
Constructs a basic_format_args object from ~fmtformat_arg_store.
Definition: core.h:1951
constexpr auto capacity() const FMT_NOEXCEPT -> size_t
Returns the capacity of this buffer.
Definition: core.h:823
OutputIt out
Iterator past the end of the output range.
Definition: core.h:3153
A compile-time format string.
Definition: core.h:3049
constexpr auto end() const FMT_NOEXCEPT -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition: core.h:658
Definition: core.h:719
A dynamic version of fmt::format_arg_store.
Definition: args.h:74
void clear()
Clears this buffer.
Definition: core.h:832
constexpr auto data() const FMT_NOEXCEPT -> const Char *
Returns a pointer to the string data.
Definition: core.h:492
Definition: core.h:3046
Definition: core.h:2737
Definition: core.h:2134
An array of references to arguments.
Definition: core.h:1819
A contiguous memory buffer with an optional growing ability.
Definition: core.h:778
FMT_CONSTEXPR auto data() const FMT_NOEXCEPT -> const T *
Returns a pointer to the buffer data.
Definition: core.h:829
Definition: core.h:2106
FMT_CONSTEXPR auto next_arg_id() -> int
Reports an error if using the manual argument indexing; otherwise returns the next argument index and...
Definition: core.h:671
constexpr auto size() const FMT_NOEXCEPT -> size_t
Returns the string size.
Definition: core.h:495
Definition: sc_data.cpp:17
Definition: core.h:331
An implementation of std::basic_string_view for pre-C++17.
Definition: core.h:448
A view of a collection of formatting arguments.
Definition: core.h:702
Char char_type
The character type for the output.
Definition: core.h:1745
Definition: core.h:872
Definition: core.h:2024
FMT_CONSTEXPR auto data() FMT_NOEXCEPT -> T *
Returns a pointer to the buffer data.
Definition: core.h:826
Definition: core.h:1051
constexpr basic_string_view(const Char *s, size_t count) FMT_NOEXCEPT
Constructs a string reference object from a C string and a size.
Definition: core.h:460
Definition: core.h:334
Definition: core.h:701
Definition: core.h:1552
Definition: core.h:2683
Definition: core.h:1063
Definition: core.h:1196
FMT_CONSTEXPR20 void grow(size_t) override
Increases the buffer capacity to hold at least capacity elements.
Definition: core.h:968
Definition: core.h:866
Definition: core.h:1002
FMT_CONSTEXPR20 void grow(size_t) override
Increases the buffer capacity to hold at least capacity elements.
Definition: core.h:1009
Definition: core.h:2817
Definition: core.h:2079
Definition: core.h:1186
Definition: format.h:876
Definition: core.h:2891
FMT_CONSTEXPR20 void grow(size_t) override
Increases the buffer capacity to hold at least capacity elements.
Definition: core.h:930
Definition: core.h:1191
Definition: core.h:1669
constexpr basic_format_args(const format_arg *args, int count)
Constructs a basic_format_args object from a dynamic set of arguments.
Definition: core.h:1971
Definition: core.h:1040
Definition: core.h:1189
Definition: core.h:1049
Definition: core.h:3151
Definition: core.h:1661
Definition: color.hpp:198
Definition: core.h:2142
Definition: core.h:1208
Definition: core.h:1298
Definition: core.h:2032
FMT_CONSTEXPR20 void grow(size_t capacity) override
Increases the buffer capacity to hold at least capacity elements.
Definition: core.h:986
Definition: core.h:1450
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition: core.h:633
Definition: core.h:1655
Definition: core.h:397
FMT_CONSTEXPR void check_arg_id(int)
Reports an error if using the automatic argument indexing; otherwise switches to the manual indexing...
Definition: core.h:683
Definition: core.h:1093
Definition: core.h:1506
Definition: core.h:593
Definition: core.h:570
Specifies if T is a character type.
Definition: core.h:543
Definition: core.h:1645
Definition: core.h:1156
constexpr basic_format_context(OutputIt out, basic_format_args< basic_format_context > ctx_args, detail::locale_ref loc=detail::locale_ref())
Constructs a basic_format_context object.
Definition: core.h:1765
FMT_CONSTEXPR20 void grow(size_t) override
Increases the buffer capacity to hold at least capacity elements.
Definition: core.h:896
size_t size
Total (not truncated) output size.
Definition: core.h:3155
Definition: core.h:1742