13 #pragma GCC system_header
17 #pragma clang system_header
26 #include <type_traits>
29 #define FMT_VERSION 90101
31 #if defined(__clang__) && !defined(__ibmxl__)
32 #define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
34 #define FMT_CLANG_VERSION 0
37 #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && \
38 !defined(__NVCOMPILER)
39 #define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
41 #define FMT_GCC_VERSION 0
44 #ifndef FMT_GCC_PRAGMA
46 #if FMT_GCC_VERSION >= 504
47 #define FMT_GCC_PRAGMA(arg) _Pragma(arg)
49 #define FMT_GCC_PRAGMA(arg)
54 #define FMT_ICC_VERSION __ICL
55 #elif defined(__INTEL_COMPILER)
56 #define FMT_ICC_VERSION __INTEL_COMPILER
58 #define FMT_ICC_VERSION 0
62 #define FMT_MSC_VERSION _MSC_VER
63 #define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__))
65 #define FMT_MSC_VERSION 0
66 #define FMT_MSC_WARNING(...)
70 #define FMT_CPLUSPLUS _MSVC_LANG
72 #define FMT_CPLUSPLUS __cplusplus
76 #define FMT_HAS_FEATURE(x) __has_feature(x)
78 #define FMT_HAS_FEATURE(x) 0
81 #if defined(__has_include) || FMT_ICC_VERSION >= 1600 || FMT_MSC_VERSION > 1900
82 #define FMT_HAS_INCLUDE(x) __has_include(x)
84 #define FMT_HAS_INCLUDE(x) 0
87 #ifdef __has_cpp_attribute
88 #define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
90 #define FMT_HAS_CPP_ATTRIBUTE(x) 0
93 #define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
94 (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
96 #define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
97 (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
101 #ifndef FMT_USE_CONSTEXPR
102 #if (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912 || \
103 (FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L)) && \
104 !FMT_ICC_VERSION && !defined(__NVCC__)
105 #define FMT_USE_CONSTEXPR 1
107 #define FMT_USE_CONSTEXPR 0
110 #if FMT_USE_CONSTEXPR
111 #define FMT_CONSTEXPR constexpr
113 #define FMT_CONSTEXPR
116 #if ((FMT_CPLUSPLUS >= 202002L) && \
117 (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 9)) || \
118 (FMT_CPLUSPLUS >= 201709L && FMT_GCC_VERSION >= 1002)
119 #define FMT_CONSTEXPR20 constexpr
121 #define FMT_CONSTEXPR20
125 #if defined(__GLIBCXX__)
126 #if FMT_CPLUSPLUS >= 201703L && defined(_GLIBCXX_RELEASE) && \
127 _GLIBCXX_RELEASE >= 7
128 #define FMT_CONSTEXPR_CHAR_TRAITS constexpr
130 #elif defined(_LIBCPP_VERSION) && FMT_CPLUSPLUS >= 201703L && \
131 _LIBCPP_VERSION >= 4000
132 #define FMT_CONSTEXPR_CHAR_TRAITS constexpr
133 #elif FMT_MSC_VERSION >= 1914 && FMT_CPLUSPLUS >= 201703L
134 #define FMT_CONSTEXPR_CHAR_TRAITS constexpr
136 #ifndef FMT_CONSTEXPR_CHAR_TRAITS
137 #define FMT_CONSTEXPR_CHAR_TRAITS
141 #ifndef FMT_EXCEPTIONS
142 #if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
143 (FMT_MSC_VERSION && !_HAS_EXCEPTIONS)
144 #define FMT_EXCEPTIONS 0
146 #define FMT_EXCEPTIONS 1
150 #ifndef FMT_DEPRECATED
151 #if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VERSION >= 1900
152 #define FMT_DEPRECATED [[deprecated]]
154 #if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
155 #define FMT_DEPRECATED __attribute__((deprecated))
156 #elif FMT_MSC_VERSION
157 #define FMT_DEPRECATED __declspec(deprecated)
159 #define FMT_DEPRECATED
165 #if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && \
167 #define FMT_NORETURN [[noreturn]]
172 #if FMT_HAS_CPP17_ATTRIBUTE(fallthrough)
173 #define FMT_FALLTHROUGH [[fallthrough]]
174 #elif defined(__clang__)
175 #define FMT_FALLTHROUGH [[clang::fallthrough]]
176 #elif FMT_GCC_VERSION >= 700 && \
177 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
178 #define FMT_FALLTHROUGH [[gnu::fallthrough]]
180 #define FMT_FALLTHROUGH
183 #ifndef FMT_NODISCARD
184 #if FMT_HAS_CPP17_ATTRIBUTE(nodiscard)
185 #define FMT_NODISCARD [[nodiscard]]
187 #define FMT_NODISCARD
191 #ifndef FMT_USE_FLOAT
192 #define FMT_USE_FLOAT 1
194 #ifndef FMT_USE_DOUBLE
195 #define FMT_USE_DOUBLE 1
197 #ifndef FMT_USE_LONG_DOUBLE
198 #define FMT_USE_LONG_DOUBLE 1
202 #if FMT_GCC_VERSION || FMT_CLANG_VERSION
203 #define FMT_INLINE inline __attribute__((always_inline))
205 #define FMT_INLINE inline
210 #define FMT_FORWARD(...) static_cast<decltype(__VA_ARGS__) &&>(__VA_ARGS__)
213 #define FMT_UNCHECKED_ITERATOR(It) \
214 using _Unchecked_type = It
216 #define FMT_UNCHECKED_ITERATOR(It) using unchecked_type = It
219 #ifndef FMT_BEGIN_NAMESPACE
220 #define FMT_BEGIN_NAMESPACE \
222 inline namespace v9 {
223 #define FMT_END_NAMESPACE \
228 #ifndef FMT_MODULE_EXPORT
229 #define FMT_MODULE_EXPORT
230 #define FMT_MODULE_EXPORT_BEGIN
231 #define FMT_MODULE_EXPORT_END
232 #define FMT_BEGIN_DETAIL_NAMESPACE namespace detail {
233 #define FMT_END_DETAIL_NAMESPACE }
236 #if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
237 #define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275)
239 #define FMT_API __declspec(dllexport)
240 #elif defined(FMT_SHARED)
241 #define FMT_API __declspec(dllimport)
244 #define FMT_CLASS_API
245 #if defined(FMT_EXPORT) || defined(FMT_SHARED)
246 #if defined(__GNUC__) || defined(__clang__)
247 #define FMT_API __attribute__((visibility("default")))
256 #if FMT_HAS_INCLUDE(<string_view>) && \
257 (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION))
258 #include <string_view>
259 #define FMT_USE_STRING_VIEW
260 #elif FMT_HAS_INCLUDE("experimental/string_view") && FMT_CPLUSPLUS >= 201402L
261 #include <experimental/string_view>
262 #define FMT_USE_EXPERIMENTAL_STRING_VIEW
266 #define FMT_UNICODE !FMT_MSC_VERSION
269 #ifndef FMT_CONSTEVAL
270 #if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \
271 FMT_CPLUSPLUS >= 202002L && !defined(__apple_build_version__)) || \
272 (defined(__cpp_consteval) && \
273 (!FMT_MSC_VERSION || _MSC_FULL_VER >= 193030704))
275 #define FMT_CONSTEVAL consteval
276 #define FMT_HAS_CONSTEVAL
278 #define FMT_CONSTEVAL
282 #ifndef FMT_USE_NONTYPE_TEMPLATE_ARGS
283 #if defined(__cpp_nontype_template_args) && \
284 ((FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L) || \
285 __cpp_nontype_template_args >= 201911L) && \
286 !defined(__NVCOMPILER) && !defined(__LCC__)
287 #define FMT_USE_NONTYPE_TEMPLATE_ARGS 1
289 #define FMT_USE_NONTYPE_TEMPLATE_ARGS 0
294 FMT_GCC_PRAGMA(
"GCC push_options")
295 #if !defined(__OPTIMIZE__) && !defined(__NVCOMPILER) && !defined(__LCC__)
296 FMT_GCC_PRAGMA(
"GCC optimize(\"Og\")")
300 FMT_MODULE_EXPORT_BEGIN
303 template <
bool B,
typename T =
void>
304 using enable_if_t =
typename std::enable_if<B, T>::type;
305 template <
bool B,
typename T,
typename F>
306 using conditional_t =
typename std::conditional<B, T, F>::type;
307 template <
bool B>
using bool_constant = std::integral_constant<bool, B>;
308 template <
typename T>
309 using remove_reference_t =
typename std::remove_reference<T>::type;
310 template <
typename T>
311 using remove_const_t =
typename std::remove_const<T>::type;
312 template <
typename T>
313 using remove_cvref_t =
typename std::remove_cv<remove_reference_t<T>>::type;
314 template <
typename T>
struct type_identity {
317 template <
typename T>
using type_identity_t =
typename type_identity<T>::type;
318 template <
typename T>
319 using underlying_t =
typename std::underlying_type<T>::type;
322 constexpr monostate() {}
329 #define FMT_ENABLE_IF(...)
331 #define FMT_ENABLE_IF(...) fmt::enable_if_t<(__VA_ARGS__), int> = 0
334 FMT_BEGIN_DETAIL_NAMESPACE
339 template <
typename... T> FMT_CONSTEXPR
void ignore_unused(
const T &...) {}
341 constexpr FMT_INLINE
auto
342 is_constant_evaluated(
bool default_value =
false) noexcept ->
bool {
346 #if FMT_CPLUSPLUS >= 202002L && defined(_GLIBCXX_RELEASE) && \
347 _GLIBCXX_RELEASE >= 12 && \
348 (FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500)
349 ignore_unused(default_value);
350 return __builtin_is_constant_evaluated();
351 #elif defined(__cpp_lib_is_constant_evaluated)
352 ignore_unused(default_value);
353 return std::is_constant_evaluated();
355 return default_value;
360 template <
typename T> constexpr FMT_INLINE
auto const_check(T value) -> T {
364 FMT_NORETURN FMT_API
void assert_fail(
const char *file,
int line,
365 const char *message);
370 #define FMT_ASSERT(condition, message) \
371 ::fmt::detail::ignore_unused((condition), (message))
373 #define FMT_ASSERT(condition, message) \
377 ::fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
381 #if defined(FMT_USE_STRING_VIEW)
382 template <
typename Char>
using std_string_view = std::basic_string_view<Char>;
383 #elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
384 template <
typename Char>
385 using std_string_view = std::experimental::basic_string_view<Char>;
387 template <
typename T>
struct std_string_view {};
390 #ifdef FMT_USE_INT128
392 #elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \
393 !(FMT_CLANG_VERSION && FMT_MSC_VERSION)
394 #define FMT_USE_INT128 1
395 using int128_opt = __int128_t;
396 using uint128_opt = __uint128_t;
397 template <
typename T>
inline auto convert_for_visit(T value) -> T {
401 #define FMT_USE_INT128 0
404 enum class int128_opt {};
405 enum class uint128_opt {};
407 template <
typename T>
auto convert_for_visit(T) -> monostate {
return {}; }
411 template <
typename Int>
412 FMT_CONSTEXPR
auto to_unsigned(Int value) ->
413 typename std::make_unsigned<Int>::type {
414 FMT_ASSERT(std::is_unsigned<Int>::value || value >= 0,
"negative value");
415 return static_cast<typename std::make_unsigned<Int>::type
>(value);
418 FMT_CONSTEXPR
inline auto is_utf8() ->
bool {
419 FMT_MSC_WARNING(suppress : 4566) constexpr
unsigned char section[] =
"\u00A7";
422 using uchar =
unsigned char;
423 return FMT_UNICODE || (
sizeof(section) == 3 && uchar(section[0]) == 0xC2 &&
424 uchar(section[1]) == 0xA7);
426 FMT_END_DETAIL_NAMESPACE
441 using value_type = Char;
442 using iterator =
const Char *;
448 : data_(s), size_(count) {}
456 FMT_CONSTEXPR_CHAR_TRAITS
460 size_(detail::const_check(std::is_same<Char, char>::value &&
461 !detail::is_constant_evaluated(true)) ?
462 std::strlen(reinterpret_cast<const char *>(s)) :
463 std::char_traits<Char>::length(s)) {}
466 template <
typename Traits,
typename Alloc>
469 : data_(s.data()), size_(s.size()) {}
471 template <
typename S, FMT_ENABLE_IF(std::is_same<
472 S, detail::std_string_view<Char>>::value)>
474 : data_(s.data()), size_(s.size()) {}
477 constexpr
auto data() const noexcept -> const Char * {
return data_; }
480 constexpr
auto size() const noexcept ->
size_t {
return size_; }
482 constexpr
auto begin() const noexcept -> iterator {
return data_; }
483 constexpr
auto end() const noexcept -> iterator {
return data_ + size_; }
485 constexpr
auto operator[](
size_t pos)
const noexcept ->
const Char & {
489 FMT_CONSTEXPR
void remove_prefix(
size_t n) noexcept {
494 FMT_CONSTEXPR_CHAR_TRAITS
bool
496 return size_ >= sv.size_ &&
497 std::char_traits<Char>::compare(data_, sv.data_, sv.size_) == 0;
499 FMT_CONSTEXPR_CHAR_TRAITS
bool starts_with(Char c)
const noexcept {
500 return size_ >= 1 && std::char_traits<Char>::eq(*data_, c);
502 FMT_CONSTEXPR_CHAR_TRAITS
bool starts_with(
const Char *s)
const {
508 size_t str_size = size_ < other.size_ ? size_ : other.size_;
509 int result = std::char_traits<Char>::compare(data_, other.data_, str_size);
511 result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
518 return lhs.compare(rhs) == 0;
521 return lhs.compare(rhs) != 0;
524 return lhs.compare(rhs) < 0;
527 return lhs.compare(rhs) <= 0;
530 return lhs.compare(rhs) > 0;
533 return lhs.compare(rhs) >= 0;
540 template <
typename T>
struct is_char : std::false_type {};
541 template <>
struct is_char<char> : std::true_type {};
543 FMT_BEGIN_DETAIL_NAMESPACE
546 struct compile_string {};
548 template <
typename S>
549 struct is_compile_string : std::is_base_of<compile_string, S> {};
552 template <
typename Char, FMT_ENABLE_IF(is_
char<Char>::value)>
556 template <
typename Char,
typename Traits,
typename Alloc>
557 inline auto to_string_view(
const std::basic_string<Char, Traits, Alloc> &s)
561 template <
typename Char>
566 template <
typename Char,
567 FMT_ENABLE_IF(!std::is_empty<std_string_view<Char>>::value)>
571 template <
typename S, FMT_ENABLE_IF(is_compile_
string<S>::value)>
572 constexpr
auto to_string_view(
const S &s)
576 void to_string_view(...);
582 template <
typename S>
583 struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> {
586 template <
typename S,
typename =
void>
struct char_t_impl {};
587 template <
typename S>
struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
588 using result = decltype(to_string_view(std::declval<S>()));
589 using type =
typename result::value_type;
603 last_integer_type = char_type,
608 last_numeric_type = long_double_type,
616 template <
typename T,
typename Char>
617 struct type_constant : std::integral_constant<type, type::custom_type> {};
619 #define FMT_TYPE_CONSTANT(Type, constant) \
620 template <typename Char> \
621 struct type_constant<Type, Char> \
622 : std::integral_constant<type, type::constant> {}
624 FMT_TYPE_CONSTANT(
int, int_type);
625 FMT_TYPE_CONSTANT(
unsigned, uint_type);
626 FMT_TYPE_CONSTANT(
long long, long_long_type);
627 FMT_TYPE_CONSTANT(
unsigned long long, ulong_long_type);
628 FMT_TYPE_CONSTANT(int128_opt, int128_type);
629 FMT_TYPE_CONSTANT(uint128_opt, uint128_type);
630 FMT_TYPE_CONSTANT(
bool, bool_type);
631 FMT_TYPE_CONSTANT(Char, char_type);
632 FMT_TYPE_CONSTANT(
float, float_type);
633 FMT_TYPE_CONSTANT(
double, double_type);
634 FMT_TYPE_CONSTANT(
long double, long_double_type);
635 FMT_TYPE_CONSTANT(
const Char *, cstring_type);
637 FMT_TYPE_CONSTANT(
const void *, pointer_type);
639 constexpr
bool is_integral_type(type t) {
640 return t > type::none_type && t <= type::last_integer_type;
642 constexpr
bool is_arithmetic_type(type t) {
643 return t > type::none_type && t <= type::last_numeric_type;
646 constexpr
auto set(type rhs) ->
int {
return 1 <<
static_cast<int>(rhs); }
647 constexpr
auto in(type t,
int set) ->
bool {
648 return ((set >>
static_cast<int>(t)) & 1) != 0;
654 set(type::int_type) | set(type::long_long_type) | set(type::int128_type),
655 uint_set = set(type::uint_type) | set(type::ulong_long_type) |
656 set(type::uint128_type),
657 bool_set = set(type::bool_type),
658 char_set = set(type::char_type),
659 float_set = set(type::float_type) | set(type::double_type) |
660 set(type::long_double_type),
661 string_set = set(type::string_type),
662 cstring_set = set(type::cstring_type),
663 pointer_set = set(type::pointer_type)
666 FMT_NORETURN FMT_API
void throw_format_error(
const char *message);
668 struct error_handler {
669 constexpr error_handler() =
default;
672 FMT_NORETURN
void on_error(
const char *message) {
673 throw_format_error(message);
676 FMT_END_DETAIL_NAMESPACE
679 template <
typename S>
using char_t =
typename detail::char_t_impl<S>::type;
693 FMT_CONSTEXPR
void do_check_arg_id(
int id);
696 using char_type = Char;
697 using iterator =
const Char *;
701 : format_str_(format_str), next_arg_id_(
next_arg_id) {}
707 constexpr
auto begin() const noexcept -> iterator {
708 return format_str_.begin();
714 constexpr
auto end() const noexcept -> iterator {
return format_str_.end(); }
718 format_str_.remove_prefix(detail::to_unsigned(it -
begin()));
726 if (next_arg_id_ < 0) {
727 detail::throw_format_error(
728 "cannot switch from manual to automatic argument indexing");
731 int id = next_arg_id_++;
741 if (next_arg_id_ > 0) {
742 detail::throw_format_error(
743 "cannot switch from automatic to manual argument indexing");
750 FMT_CONSTEXPR
void check_dynamic_spec(
int arg_id);
755 FMT_BEGIN_DETAIL_NAMESPACE
757 template <
typename Char>
765 explicit FMT_CONSTEXPR
767 const type *types,
int next_arg_id = 0)
768 : base(format_str, next_arg_id), num_args_(num_args), types_(types) {}
770 constexpr
auto num_args() const ->
int {
return num_args_; }
771 constexpr
auto arg_type(
int id)
const -> type {
return types_[id]; }
776 throw_format_error(
"argument not found");
783 throw_format_error(
"argument not found");
787 FMT_CONSTEXPR
void check_dynamic_spec(
int arg_id) {
788 detail::ignore_unused(arg_id);
789 #if !defined(__LCC__)
790 if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
791 throw_format_error(
"width/precision is not integer");
795 FMT_END_DETAIL_NAMESPACE
797 template <
typename Char>
801 if (detail::is_constant_evaluated() &&
802 (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) {
803 using context = detail::compile_parse_context<Char>;
804 if (
id >=
static_cast<context *
>(
this)->num_args())
805 detail::throw_format_error(
"argument not found");
809 template <
typename Char>
812 if (detail::is_constant_evaluated() &&
813 (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) {
814 using context = detail::compile_parse_context<Char>;
815 static_cast<context *
>(
this)->check_dynamic_spec(arg_id);
819 template <
typename Context>
class basic_format_arg;
824 template <
typename T,
typename Char =
char,
typename Enable =
void>
827 formatter() =
delete;
832 template <
typename T,
typename Context>
833 using has_formatter =
834 std::is_constructible<typename Context::template formatter_type<T>>;
837 template <
typename T>
struct is_contiguous : std::false_type {};
838 template <
typename Char>
839 struct is_contiguous<std::basic_string<Char>> : std::true_type {};
843 FMT_BEGIN_DETAIL_NAMESPACE
845 template <
typename Context,
typename T>
846 constexpr
auto has_const_formatter_impl(T *)
847 -> decltype(
typename Context::template formatter_type<T>().format(
848 std::declval<const T &>(), std::declval<Context &>()),
852 template <
typename Context>
853 constexpr
auto has_const_formatter_impl(...) ->
bool {
856 template <
typename T,
typename Context>
857 constexpr
auto has_const_formatter() ->
bool {
858 return has_const_formatter_impl<Context>(
static_cast<T *
>(
nullptr));
862 template <
typename Container>
863 inline auto get_container(std::back_insert_iterator<Container> it)
865 using base = std::back_insert_iterator<Container>;
866 struct accessor : base {
867 accessor(base b) : base(b) {}
868 using base::container;
870 return *accessor(it).container;
873 template <
typename Char,
typename InputIt,
typename OutputIt>
874 FMT_CONSTEXPR
auto copy_str(InputIt begin, InputIt end, OutputIt out)
877 *out++ =
static_cast<Char
>(*begin++);
881 template <
typename Char,
typename T,
typename U,
884 FMT_CONSTEXPR
auto copy_str(T *begin, T *end, U *out) -> U * {
885 if (is_constant_evaluated())
886 return copy_str<Char, T *, U *>(begin, end, out);
887 auto size = to_unsigned(end - begin);
889 memcpy(out, begin, size *
sizeof(U));
907 FMT_MSC_WARNING(suppress : 26495)
908 buffer(
size_t sz) noexcept : size_(sz), capacity_(sz) {}
910 FMT_CONSTEXPR20
buffer(T *p =
nullptr,
size_t sz = 0,
size_t cap = 0) noexcept
911 : ptr_(p), size_(sz), capacity_(cap) {}
913 FMT_CONSTEXPR20 ~
buffer() =
default;
917 FMT_CONSTEXPR
void set(T *buf_data,
size_t buf_capacity) noexcept {
919 capacity_ = buf_capacity;
926 using value_type = T;
927 using const_reference =
const T &;
930 void operator=(
const buffer &) =
delete;
932 FMT_INLINE
auto begin() noexcept -> T * {
return ptr_; }
933 FMT_INLINE
auto end() noexcept -> T * {
return ptr_ + size_; }
935 FMT_INLINE
auto begin() const noexcept -> const T * {
return ptr_; }
936 FMT_INLINE
auto end() const noexcept -> const T * {
return ptr_ + size_; }
939 constexpr
auto size() const noexcept ->
size_t {
return size_; }
942 constexpr
auto capacity() const noexcept ->
size_t {
return capacity_; }
945 FMT_CONSTEXPR
auto data() noexcept -> T * {
return ptr_; }
948 FMT_CONSTEXPR
auto data() const noexcept -> const T * {
return ptr_; }
955 FMT_CONSTEXPR20
void try_resize(
size_t count) {
957 size_ = count <= capacity_ ? count : capacity_;
964 FMT_CONSTEXPR20
void try_reserve(
size_t new_capacity) {
965 if (new_capacity > capacity_)
969 FMT_CONSTEXPR20
void push_back(
const T &value) {
970 try_reserve(size_ + 1);
971 ptr_[size_++] = value;
975 template <
typename U>
void append(
const U *begin,
const U *end);
977 template <
typename Idx> FMT_CONSTEXPR
auto operator[](Idx index) -> T & {
980 template <
typename Idx>
981 FMT_CONSTEXPR
auto operator[](Idx index)
const ->
const T & {
986 struct buffer_traits {
987 explicit buffer_traits(
size_t) {}
988 auto count() const ->
size_t {
return 0; }
989 auto limit(
size_t size) ->
size_t {
return size; }
992 class fixed_buffer_traits {
998 explicit fixed_buffer_traits(
size_t limit) : limit_(limit) {}
999 auto count() const ->
size_t {
return count_; }
1000 auto limit(
size_t size) ->
size_t {
1001 size_t n = limit_ > count_ ? limit_ - count_ : 0;
1003 return size < n ? size : n;
1008 template <
typename OutputIt,
typename T,
typename Traits = buffer_traits>
1009 class iterator_buffer final :
public Traits,
public buffer<T> {
1012 enum { buffer_size = 256 };
1013 T data_[buffer_size];
1016 FMT_CONSTEXPR20
void grow(
size_t)
override {
1017 if (this->
size() == buffer_size)
1024 out_ = copy_str<T>(data_, data_ + this->limit(size), out_);
1028 explicit iterator_buffer(OutputIt out,
size_t n = buffer_size)
1029 : Traits(n),
buffer<T>(data_, 0, buffer_size), out_(out) {}
1030 iterator_buffer(iterator_buffer &&other)
1031 : Traits(other),
buffer<T>(data_, 0, buffer_size), out_(other.out_) {}
1032 ~iterator_buffer() { flush(); }
1034 auto out() -> OutputIt {
1038 auto count() const ->
size_t {
return Traits::count() + this->
size(); }
1041 template <
typename T>
1042 class iterator_buffer<T *, T, fixed_buffer_traits> final
1043 :
public fixed_buffer_traits,
1047 enum { buffer_size = 256 };
1048 T data_[buffer_size];
1051 FMT_CONSTEXPR20
void grow(
size_t)
override {
1052 if (this->size() == this->capacity())
1057 size_t n = this->limit(this->size());
1058 if (this->data() == out_) {
1060 this->set(data_, buffer_size);
1066 explicit iterator_buffer(T *out,
size_t n = buffer_size)
1067 : fixed_buffer_traits(n),
buffer<T>(out, 0, n), out_(out) {}
1068 iterator_buffer(iterator_buffer &&other)
1069 : fixed_buffer_traits(other),
1070 buffer<T>(std::move(other)),
1072 if (this->data() != out_) {
1073 this->set(data_, buffer_size);
1077 ~iterator_buffer() { flush(); }
1083 auto count() const ->
size_t {
1084 return fixed_buffer_traits::count() + this->size();
1088 template <
typename T>
class iterator_buffer<T *, T> final :
public buffer<T> {
1090 FMT_CONSTEXPR20
void grow(
size_t)
override {}
1093 explicit iterator_buffer(T *out,
size_t = 0) :
buffer<T>(out, 0, ~size_t()) {}
1095 auto out() -> T * {
return &*this->end(); }
1099 template <
typename Container>
1100 class iterator_buffer<std::back_insert_iterator<Container>,
1101 enable_if_t<is_contiguous<Container>::value,
1102 typename Container::value_type>>
1103 final :
public buffer<typename Container::value_type> {
1105 Container &container_;
1108 FMT_CONSTEXPR20
void grow(
size_t capacity)
override {
1109 container_.resize(capacity);
1110 this->
set(&container_[0], capacity);
1114 explicit iterator_buffer(Container &c)
1115 :
buffer<typename Container::value_type>(
c.
size()), container_(
c) {}
1116 explicit iterator_buffer(std::back_insert_iterator<Container> out,
size_t = 0)
1117 : iterator_buffer(get_container(out)) {}
1119 auto out() -> std::back_insert_iterator<Container> {
1120 return std::back_inserter(container_);
1125 template <
typename T =
char>
class counting_buffer final :
public buffer<T> {
1127 enum { buffer_size = 256 };
1128 T data_[buffer_size];
1132 FMT_CONSTEXPR20
void grow(
size_t)
override {
1133 if (this->
size() != buffer_size)
1135 count_ += this->
size();
1140 counting_buffer() :
buffer<T>(data_, 0, buffer_size) {}
1142 auto count() ->
size_t {
return count_ + this->
size(); }
1145 template <
typename T>
1146 using buffer_appender = conditional_t<std::is_same<T, char>::value, appender,
1147 std::back_insert_iterator<buffer<T>>>;
1150 template <
typename T,
typename OutputIt>
1151 auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
1152 return iterator_buffer<OutputIt, T>(out);
1154 template <
typename T,
typename Buf,
1155 FMT_ENABLE_IF(std::is_base_of<
buffer<char>, Buf>::value)>
1156 auto get_buffer(std::back_insert_iterator<Buf> out) ->
buffer<char> & {
1157 return get_container(out);
1160 template <
typename Buf,
typename OutputIt>
1161 FMT_INLINE
auto get_iterator(Buf &buf, OutputIt) -> decltype(buf.out()) {
1164 template <
typename T,
typename OutputIt>
1165 auto get_iterator(
buffer<T> &, OutputIt out) -> OutputIt {
1169 template <
typename T,
typename Char =
char,
typename Enable =
void>
1170 struct fallback_formatter {
1171 fallback_formatter() =
delete;
1175 template <
typename T,
typename Char>
1176 using has_fallback_formatter =
1177 #ifdef FMT_DEPRECATED_OSTREAM
1178 std::is_constructible<fallback_formatter<T, Char>>;
1185 template <
typename Char,
typename T>
struct named_arg : view {
1188 named_arg(
const Char *n,
const T &v) : name(n), value(v) {}
1191 template <
typename Char>
struct named_arg_info {
1196 template <
typename T,
typename Char,
size_t NUM_ARGS,
size_t NUM_NAMED_ARGS>
1200 T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)];
1201 named_arg_info<Char> named_args_[NUM_NAMED_ARGS];
1203 template <
typename... U>
1204 arg_data(
const U &...init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {}
1205 arg_data(
const arg_data &other) =
delete;
1206 auto args() const -> const T * {
return args_ + 1; }
1207 auto named_args() -> named_arg_info<Char> * {
return named_args_; }
1210 template <
typename T,
typename Char,
size_t NUM_ARGS>
1211 struct arg_data<T, Char, NUM_ARGS, 0> {
1213 T args_[NUM_ARGS != 0 ? NUM_ARGS : +1];
1215 template <
typename... U>
1216 FMT_CONSTEXPR FMT_INLINE arg_data(
const U &...init) : args_{init...} {}
1217 FMT_CONSTEXPR FMT_INLINE
auto args() const -> const T * {
return args_; }
1218 FMT_CONSTEXPR FMT_INLINE
auto named_args() -> std::nullptr_t {
1223 template <
typename Char>
1224 inline void init_named_args(named_arg_info<Char> *,
int,
int) {}
1226 template <
typename T>
struct is_named_arg : std::false_type {};
1227 template <
typename T>
struct is_statically_named_arg : std::false_type {};
1229 template <
typename T,
typename Char>
1230 struct is_named_arg<named_arg<Char, T>> : std::true_type {};
1232 template <
typename Char,
typename T,
typename... Tail,
1233 FMT_ENABLE_IF(!is_named_arg<T>::value)>
1234 void init_named_args(named_arg_info<Char> *named_args,
int arg_count,
1235 int named_arg_count,
const T &,
const Tail &...args) {
1236 init_named_args(named_args, arg_count + 1, named_arg_count, args...);
1239 template <
typename Char,
typename T,
typename... Tail,
1240 FMT_ENABLE_IF(is_named_arg<T>::value)>
1241 void init_named_args(named_arg_info<Char> *named_args,
int arg_count,
1242 int named_arg_count,
const T &arg,
const Tail &...args) {
1243 named_args[named_arg_count++] = {arg.name, arg_count};
1244 init_named_args(named_args, arg_count + 1, named_arg_count, args...);
1247 template <
typename... Args>
1248 FMT_CONSTEXPR FMT_INLINE
void init_named_args(std::nullptr_t,
int,
int,
1251 template <
bool B = false> constexpr
auto count() ->
size_t {
return B ? 1 : 0; }
1252 template <
bool B1,
bool B2,
bool... Tail> constexpr
auto count() ->
size_t {
1253 return (B1 ? 1 : 0) + count<B2, Tail...>();
1256 template <
typename... Args> constexpr
auto count_named_args() ->
size_t {
1257 return count<is_named_arg<Args>::value...>();
1260 template <
typename... Args>
1261 constexpr
auto count_statically_named_args() ->
size_t {
1262 return count<is_statically_named_arg<Args>::value...>();
1265 struct unformattable {};
1266 struct unformattable_char : unformattable {};
1267 struct unformattable_const : unformattable {};
1268 struct unformattable_pointer : unformattable {};
1270 template <
typename Char>
struct string_value {
1275 template <
typename Char>
struct named_arg_value {
1276 const named_arg_info<Char> *data;
1280 template <
typename Context>
struct custom_value {
1281 using parse_context =
typename Context::parse_context_type;
1283 void (*format)(
void *arg, parse_context &parse_ctx, Context &ctx);
1287 template <
typename Context>
class value {
1289 using char_type =
typename Context::char_type;
1294 unsigned uint_value;
1295 long long long_long_value;
1296 unsigned long long ulong_long_value;
1297 int128_opt int128_value;
1298 uint128_opt uint128_value;
1300 char_type char_value;
1302 double double_value;
1303 long double long_double_value;
1304 const void *pointer;
1305 string_value<char_type> string;
1306 custom_value<Context> custom;
1307 named_arg_value<char_type> named_args;
1310 constexpr FMT_INLINE value() : no_value() {}
1311 constexpr FMT_INLINE value(
int val) : int_value(val) {}
1312 constexpr FMT_INLINE value(
unsigned val) : uint_value(val) {}
1313 constexpr FMT_INLINE value(
long long val) : long_long_value(val) {}
1314 constexpr FMT_INLINE value(
unsigned long long val) : ulong_long_value(val) {}
1315 FMT_INLINE value(int128_opt val) : int128_value(val) {}
1316 FMT_INLINE value(uint128_opt val) : uint128_value(val) {}
1317 constexpr FMT_INLINE value(
float val) : float_value(val) {}
1318 constexpr FMT_INLINE value(
double val) : double_value(val) {}
1319 FMT_INLINE value(
long double val) : long_double_value(val) {}
1320 constexpr FMT_INLINE value(
bool val) : bool_value(val) {}
1321 constexpr FMT_INLINE value(char_type val) : char_value(val) {}
1322 FMT_CONSTEXPR FMT_INLINE value(
const char_type *val) {
1324 if (is_constant_evaluated())
1328 string.data = val.
data();
1329 string.size = val.
size();
1331 FMT_INLINE value(
const void *val) : pointer(val) {}
1332 FMT_INLINE value(
const named_arg_info<char_type> *args,
size_t size)
1333 : named_args{args, size} {}
1335 template <
typename T> FMT_CONSTEXPR FMT_INLINE value(T &val) {
1336 using value_type = remove_cvref_t<T>;
1337 custom.value =
const_cast<value_type *
>(&val);
1341 custom.format = format_custom_arg<
1343 conditional_t<has_formatter<value_type, Context>::value,
1344 typename Context::template formatter_type<value_type>,
1345 fallback_formatter<value_type, char_type>>>;
1347 value(unformattable);
1348 value(unformattable_char);
1349 value(unformattable_const);
1350 value(unformattable_pointer);
1354 template <
typename T,
typename Formatter>
1355 static void format_custom_arg(
void *arg,
1356 typename Context::parse_context_type &parse_ctx,
1358 auto f = Formatter();
1359 parse_ctx.advance_to(
f.parse(parse_ctx));
1360 using qualified_type =
1361 conditional_t<has_const_formatter<T, Context>(),
const T, T>;
1362 ctx.advance_to(
f.format(*
static_cast<qualified_type *
>(arg), ctx));
1366 template <
typename Context,
typename T>
1367 FMT_CONSTEXPR
auto make_arg(T &&value) -> basic_format_arg<Context>;
1371 enum { long_short =
sizeof(long) ==
sizeof(
int) };
1372 using long_type = conditional_t<long_short, int, long long>;
1373 using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
1375 #ifdef __cpp_lib_byte
1376 inline auto format_as(std::byte b) ->
unsigned char {
1377 return static_cast<unsigned char>(b);
1381 template <
typename T>
struct convertible_to {
1382 operator const T &()
const;
1385 template <
typename T>
struct has_format_as {
1386 template <
typename U,
typename V = decltype(format_as(U())),
1387 FMT_ENABLE_IF(std::is_enum<U>::value)>
1388 static auto check(U *) -> std::true_type;
1390 template <typename U, typename V = decltype(format_as(convertible_to<U>())),
1391 FMT_ENABLE_IF(std::is_class<U>::value)>
1392 static auto check(U *) -> std::true_type;
1393 static auto check(...) -> std::false_type;
1395 enum { value = decltype(check(
static_cast<T *
>(
nullptr)))::value };
1401 template <
typename Context>
struct arg_mapper {
1402 using char_type =
typename Context::char_type;
1404 FMT_CONSTEXPR FMT_INLINE
auto map(
signed char val) ->
int {
return val; }
1405 FMT_CONSTEXPR FMT_INLINE
auto map(
unsigned char val) ->
unsigned {
1408 FMT_CONSTEXPR FMT_INLINE
auto map(
short val) ->
int {
return val; }
1409 FMT_CONSTEXPR FMT_INLINE
auto map(
unsigned short val) ->
unsigned {
1412 FMT_CONSTEXPR FMT_INLINE
auto map(
int val) ->
int {
return val; }
1413 FMT_CONSTEXPR FMT_INLINE
auto map(
unsigned val) ->
unsigned {
return val; }
1414 FMT_CONSTEXPR FMT_INLINE
auto map(
long val) -> long_type {
return val; }
1415 FMT_CONSTEXPR FMT_INLINE
auto map(
unsigned long val) -> ulong_type {
1418 FMT_CONSTEXPR FMT_INLINE
auto map(
long long val) ->
long long {
return val; }
1419 FMT_CONSTEXPR FMT_INLINE
auto map(
unsigned long long val)
1420 ->
unsigned long long {
1423 FMT_CONSTEXPR FMT_INLINE
auto map(int128_opt val) -> int128_opt {
1426 FMT_CONSTEXPR FMT_INLINE
auto map(uint128_opt val) -> uint128_opt {
1429 FMT_CONSTEXPR FMT_INLINE
auto map(
bool val) ->
bool {
return val; }
1431 template <
typename T, FMT_ENABLE_IF(std::is_same<T,
char>::value ||
1432 std::is_same<T,
char_type>::value)>
1433 FMT_CONSTEXPR FMT_INLINE
auto map(T val) -> char_type {
1436 template <
typename T, enable_if_t<(std::is_same<T,
wchar_t>::value ||
1437 #ifdef __cpp_
char8_t
1438 std::is_same<T,
char8_t>::value ||
1440 std::is_same<T,
char16_t>::value ||
1441 std::is_same<T,
char32_t>::value) &&
1442 !std::is_same<T,
char_type>::value,
1444 FMT_CONSTEXPR FMT_INLINE
auto map(T) -> unformattable_char {
1448 FMT_CONSTEXPR FMT_INLINE
auto map(
float val) ->
float {
return val; }
1449 FMT_CONSTEXPR FMT_INLINE
auto map(
double val) ->
double {
return val; }
1450 FMT_CONSTEXPR FMT_INLINE
auto map(
long double val) ->
long double {
1454 FMT_CONSTEXPR FMT_INLINE
auto map(char_type *val) ->
const char_type * {
1457 FMT_CONSTEXPR FMT_INLINE
auto map(
const char_type *val) ->
const char_type * {
1460 template <
typename T,
1461 FMT_ENABLE_IF(is_string<T>::value && !std::is_pointer<T>::value &&
1462 std::is_same<char_type, char_t<T>>::value)>
1463 FMT_CONSTEXPR FMT_INLINE
auto map(
const T &val)
1465 return to_string_view(val);
1467 template <
typename T,
1468 FMT_ENABLE_IF(is_string<T>::value && !std::is_pointer<T>::value &&
1469 !std::is_same<char_type, char_t<T>>::value)>
1470 FMT_CONSTEXPR FMT_INLINE
auto map(
const T &) -> unformattable_char {
1474 FMT_CONSTEXPR FMT_INLINE
auto map(
void *val) ->
const void * {
return val; }
1475 FMT_CONSTEXPR FMT_INLINE
auto map(
const void *val) ->
const void * {
1478 FMT_CONSTEXPR FMT_INLINE
auto map(std::nullptr_t val) ->
const void * {
1487 std::is_pointer<T>::value || std::is_member_pointer<T>::value ||
1488 std::is_function<
typename std::remove_pointer<T>::type>::value ||
1489 (std::is_convertible<const T &, const void *>::value &&
1490 !std::is_convertible<const T &, const char_type *>::value &&
1491 !has_formatter<T, Context>::value))>
1492 FMT_CONSTEXPR
auto map(
const T &) -> unformattable_pointer {
1496 template <
typename T, std::size_t N,
1497 FMT_ENABLE_IF(!std::is_same<T, wchar_t>::value)>
1498 FMT_CONSTEXPR FMT_INLINE
auto map(
const T (&values)[N]) ->
const T (&)[N] {
1502 #ifdef FMT_DEPRECATED_IMPLICIT_ENUMS
1503 template <
typename T,
1505 std::is_enum<T>::value &&std::is_convertible<T, int>::value &&
1506 !has_format_as<T>::value && !has_formatter<T, Context>::value &&
1507 !has_fallback_formatter<T, char_type>::value)>
1508 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE
auto map(
const T &val)
1509 -> decltype(this->map(
static_cast<underlying_t<T>
>(val))) {
1510 return map(
static_cast<underlying_t<T>
>(val));
1514 template <
typename T, FMT_ENABLE_IF(has_format_as<T>::value &&
1515 !has_formatter<T, Context>::value)>
1516 FMT_CONSTEXPR FMT_INLINE
auto map(
const T &val)
1517 -> decltype(this->map(format_as(T()))) {
1518 return map(format_as(val));
1521 template <
typename T,
typename U = remove_cvref_t<T>>
1523 : bool_constant<has_const_formatter<U, Context>() ||
1524 !std::is_const<remove_reference_t<T>>::value ||
1525 has_fallback_formatter<U, char_type>::value> {};
1527 #if (FMT_MSC_VERSION != 0 && FMT_MSC_VERSION < 1910) || \
1528 FMT_ICC_VERSION != 0 || defined(__NVCC__)
1530 template <
typename T> FMT_CONSTEXPR FMT_INLINE
auto do_map(T &&val) -> T & {
1534 template <
typename T, FMT_ENABLE_IF(formattable<T>::value)>
1535 FMT_CONSTEXPR FMT_INLINE
auto do_map(T &&val) -> T & {
1538 template <
typename T, FMT_ENABLE_IF(!formattable<T>::value)>
1539 FMT_CONSTEXPR FMT_INLINE
auto do_map(T &&) -> unformattable_const {
1544 template <
typename T,
typename U = remove_cvref_t<T>,
1545 FMT_ENABLE_IF(!is_
string<U>::value && !is_
char<U>::value &&
1546 !std::is_array<U>::value &&
1547 !std::is_po
inter<U>::value &&
1548 !has_format_as<U>::value &&
1549 (has_formatter<U, Context>::value ||
1550 has_fallback_formatter<U,
char_type>::value))>
1551 FMT_CONSTEXPR FMT_INLINE
auto map(T &&val)
1552 -> decltype(this->do_map(std::forward<T>(val))) {
1553 return do_map(std::forward<T>(val));
1556 template <
typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
1557 FMT_CONSTEXPR FMT_INLINE
auto map(
const T &named_arg)
1558 -> decltype(this->map(named_arg.value)) {
1559 return map(named_arg.value);
1562 auto map(...) -> unformattable {
return {}; }
1566 template <
typename T,
typename Context>
1567 using mapped_type_constant = type_constant<decltype(arg_mapper<Context>().map(
1568 std::declval<const T &>())),
1569 typename Context::char_type>;
1571 enum { packed_arg_bits = 4 };
1573 enum { max_packed_args = 62 / packed_arg_bits };
1574 enum :
unsigned long long { is_unpacked_bit = 1ULL << 63 };
1575 enum :
unsigned long long { has_named_args_bit = 1ULL << 62 };
1577 FMT_END_DETAIL_NAMESPACE
1581 class appender :
public std::back_insert_iterator<detail::buffer<char>> {
1582 using base = std::back_insert_iterator<detail::buffer<char>>;
1585 using std::back_insert_iterator<detail::buffer<char>>::back_insert_iterator;
1586 appender(base it) noexcept : base(it) {}
1587 FMT_UNCHECKED_ITERATOR(appender);
1589 auto operator++() noexcept -> appender & {
return *
this; }
1590 auto operator++(
int) noexcept -> appender {
return *
this; }
1595 template <
typename Context>
class basic_format_arg {
1597 detail::value<Context> value_;
1600 template <
typename ContextType,
typename T>
1601 friend FMT_CONSTEXPR
auto detail::make_arg(T &&value)
1602 -> basic_format_arg<ContextType>;
1604 template <
typename Visitor,
typename Ctx>
1605 friend FMT_CONSTEXPR
auto visit_format_arg(Visitor &&vis,
1606 const basic_format_arg<Ctx> &arg)
1607 -> decltype(vis(0));
1612 using char_type =
typename Context::char_type;
1614 template <
typename T,
typename Char,
size_t NUM_ARGS,
size_t NUM_NAMED_ARGS>
1615 friend struct detail::arg_data;
1617 basic_format_arg(
const detail::named_arg_info<char_type> *args,
size_t size)
1618 : value_(args, size) {}
1623 explicit handle(detail::custom_value<Context> custom) : custom_(custom) {}
1625 void format(
typename Context::parse_context_type &parse_ctx,
1626 Context &ctx)
const {
1627 custom_.format(custom_.value, parse_ctx, ctx);
1631 detail::custom_value<Context> custom_;
1634 constexpr basic_format_arg() : type_(detail::type::none_type) {}
1636 constexpr
explicit operator bool() const noexcept {
1637 return type_ != detail::type::none_type;
1640 auto type() const -> detail::type {
return type_; }
1642 auto is_integral() const ->
bool {
return detail::is_integral_type(type_); }
1643 auto is_arithmetic() const ->
bool {
1644 return detail::is_arithmetic_type(type_);
1655 template <
typename Visitor,
typename Context>
1656 FMT_CONSTEXPR FMT_INLINE
auto
1657 visit_format_arg(Visitor &&vis,
const basic_format_arg<Context> &arg)
1658 -> decltype(vis(0)) {
1659 switch (arg.type_) {
1660 case detail::type::none_type:
1662 case detail::type::int_type:
1663 return vis(arg.value_.int_value);
1664 case detail::type::uint_type:
1665 return vis(arg.value_.uint_value);
1666 case detail::type::long_long_type:
1667 return vis(arg.value_.long_long_value);
1668 case detail::type::ulong_long_type:
1669 return vis(arg.value_.ulong_long_value);
1670 case detail::type::int128_type:
1671 return vis(detail::convert_for_visit(arg.value_.int128_value));
1672 case detail::type::uint128_type:
1673 return vis(detail::convert_for_visit(arg.value_.uint128_value));
1674 case detail::type::bool_type:
1675 return vis(arg.value_.bool_value);
1676 case detail::type::char_type:
1677 return vis(arg.value_.char_value);
1678 case detail::type::float_type:
1679 return vis(arg.value_.float_value);
1680 case detail::type::double_type:
1681 return vis(arg.value_.double_value);
1682 case detail::type::long_double_type:
1683 return vis(arg.value_.long_double_value);
1684 case detail::type::cstring_type:
1685 return vis(arg.value_.string.data);
1686 case detail::type::string_type:
1688 return vis(sv(arg.value_.string.data, arg.value_.string.size));
1689 case detail::type::pointer_type:
1690 return vis(arg.value_.pointer);
1691 case detail::type::custom_type:
1692 return vis(
typename basic_format_arg<Context>::handle(arg.value_.custom));
1694 return vis(monostate());
1697 FMT_BEGIN_DETAIL_NAMESPACE
1699 template <
typename Char,
typename InputIt>
1700 auto copy_str(InputIt begin, InputIt end, appender out) -> appender {
1701 get_container(out).append(begin, end);
1705 template <
typename Char,
typename R,
typename OutputIt>
1706 FMT_CONSTEXPR
auto copy_str(R &&rng, OutputIt out) -> OutputIt {
1707 return detail::copy_str<Char>(rng.begin(), rng.end(), out);
1710 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
1712 template <
typename...>
struct void_t_impl {
1715 template <
typename... T>
using void_t =
typename void_t_impl<T...>::type;
1717 template <
typename...>
using void_t = void;
1720 template <
typename It,
typename T,
typename Enable =
void>
1721 struct is_output_iterator : std::false_type {};
1723 template <
typename It,
typename T>
1724 struct is_output_iterator<
1726 void_t<typename std::iterator_traits<It>::iterator_category,
1727 decltype(*std::declval<It>() = std::declval<T>())>>
1728 : std::true_type {};
1730 template <
typename It>
struct is_back_insert_iterator : std::false_type {};
1731 template <
typename Container>
1732 struct is_back_insert_iterator<std::back_insert_iterator<Container>>
1733 : std::true_type {};
1735 template <
typename It>
1736 struct is_contiguous_back_insert_iterator : std::false_type {};
1737 template <
typename Container>
1738 struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
1739 : is_contiguous<Container> {};
1741 struct is_contiguous_back_insert_iterator<appender> : std::true_type {};
1746 const void *locale_;
1749 constexpr FMT_INLINE locale_ref() : locale_(nullptr) {}
1750 template <
typename Locale>
explicit locale_ref(
const Locale &loc);
1752 explicit operator bool() const noexcept {
return locale_ !=
nullptr; }
1754 template <
typename Locale>
auto get() const -> Locale;
1757 template <typename> constexpr auto encode_types() ->
unsigned long long {
1761 template <
typename Context,
typename Arg,
typename... Args>
1762 constexpr
auto encode_types() ->
unsigned long long {
1763 return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) |
1764 (encode_types<Context, Args...>() << packed_arg_bits);
1767 template <
typename Context,
typename T>
1768 FMT_CONSTEXPR FMT_INLINE
auto make_value(T &&val) -> value<Context> {
1769 const auto &arg = arg_mapper<Context>().map(FMT_FORWARD(val));
1771 constexpr
bool formattable_char =
1772 !std::is_same<decltype(arg),
const unformattable_char &>::value;
1773 static_assert(formattable_char,
"Mixing character types is disallowed.");
1775 constexpr
bool formattable_const =
1776 !std::is_same<decltype(arg),
const unformattable_const &>::value;
1777 static_assert(formattable_const,
"Cannot format a const argument.");
1782 constexpr
bool formattable_pointer =
1783 !std::is_same<decltype(arg),
const unformattable_pointer &>::value;
1784 static_assert(formattable_pointer,
1785 "Formatting of non-void pointers is disallowed.");
1787 constexpr
bool formattable =
1788 !std::is_same<decltype(arg),
const unformattable &>::value;
1791 "Cannot format an argument. To make type T formattable provide a "
1792 "formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
1796 template <
typename Context,
typename T>
1797 FMT_CONSTEXPR
auto make_arg(T &&value) -> basic_format_arg<Context> {
1798 auto arg = basic_format_arg<Context>();
1799 arg.type_ = mapped_type_constant<T, Context>::value;
1800 arg.value_ = make_value<Context>(value);
1807 template <
bool IS_PACKED,
typename Context, type,
typename T,
1808 FMT_ENABLE_IF(IS_PACKED)>
1809 FMT_CONSTEXPR FMT_INLINE
auto make_arg(T &&val) -> value<Context> {
1810 return make_value<Context>(val);
1813 template <
bool IS_PACKED,
typename Context, type,
typename T,
1814 FMT_ENABLE_IF(!IS_PACKED)>
1815 FMT_CONSTEXPR
inline auto make_arg(T &&value) -> basic_format_arg<Context> {
1816 return make_arg<Context>(value);
1818 FMT_END_DETAIL_NAMESPACE
1821 template <
typename OutputIt,
typename Char>
class basic_format_context {
1825 detail::locale_ref loc_;
1828 using iterator = OutputIt;
1829 using format_arg = basic_format_arg<basic_format_context>;
1832 template <
typename T>
using formatter_type = formatter<T, Char>;
1835 using char_type = Char;
1837 basic_format_context(basic_format_context &&) =
default;
1838 basic_format_context(
const basic_format_context &) =
delete;
1839 void operator=(
const basic_format_context &) =
delete;
1844 constexpr basic_format_context(OutputIt out,
format_args ctx_args,
1845 detail::locale_ref loc = {})
1846 : out_(out), args_(ctx_args), loc_(loc) {}
1848 constexpr
auto arg(
int id)
const -> format_arg {
return args_.
get(
id); }
1850 return args_.
get(name);
1853 return args_.get_id(name);
1855 auto args() const -> const
format_args & {
return args_; }
1857 FMT_CONSTEXPR
auto error_handler() -> detail::error_handler {
return {}; }
1858 void on_error(
const char *message) { error_handler().on_error(message); }
1861 FMT_CONSTEXPR
auto out() -> iterator {
return out_; }
1864 void advance_to(iterator it) {
1865 if (!detail::is_back_insert_iterator<iterator>())
1869 FMT_CONSTEXPR
auto locale() -> detail::locale_ref {
return loc_; }
1872 template <
typename Char>
1873 using buffer_context =
1874 basic_format_context<detail::buffer_appender<Char>, Char>;
1875 using format_context = buffer_context<char>;
1877 template <
typename T,
typename Char =
char>
1878 using is_formattable = bool_constant<
1879 !std::is_base_of<detail::unformattable,
1880 decltype(detail::arg_mapper<buffer_context<Char>>().map(
1881 std::declval<T>()))>::value &&
1882 !detail::has_fallback_formatter<T, Char>::value>;
1891 template <
typename Context,
typename... Args>
1893 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1899 static const size_t num_args =
sizeof...(Args);
1900 static const size_t num_named_args = detail::count_named_args<Args...>();
1901 static const bool is_packed = num_args <= detail::max_packed_args;
1903 using value_type = conditional_t<is_packed, detail::value<Context>,
1904 basic_format_arg<Context>>;
1906 detail::arg_data<value_type,
typename Context::char_type, num_args,
1912 static constexpr
unsigned long long desc =
1913 (is_packed ? detail::encode_types<Context, Args...>() :
1914 detail::is_unpacked_bit | num_args) |
1915 (num_named_args != 0 ?
1916 static_cast<unsigned long long>(detail::has_named_args_bit) :
1920 template <
typename... T>
1923 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1926 data_{detail::make_arg<
1928 detail::mapped_type_constant<remove_cvref_t<T>, Context>::value>(
1929 FMT_FORWARD(args))...} {
1930 detail::init_named_args(data_.named_args(), 0, 0, args...);
1942 template <
typename Context = format_context,
typename... T>
1943 constexpr
auto make_format_args(T &&...args)
1945 return {FMT_FORWARD(args)...};
1959 template <
typename Char,
typename T>
1960 inline auto arg(
const Char *name,
const T &arg) -> detail::named_arg<Char, T> {
1961 static_assert(!detail::is_named_arg<T>(),
"nested named arguments");
1977 using size_type = int;
1978 using format_arg = basic_format_arg<Context>;
1985 unsigned long long desc_;
1992 const detail::value<Context> *values_;
1993 const format_arg *args_;
1996 constexpr
auto is_packed()
const ->
bool {
1997 return (desc_ & detail::is_unpacked_bit) == 0;
1999 auto has_named_args()
const ->
bool {
2000 return (desc_ & detail::has_named_args_bit) != 0;
2003 FMT_CONSTEXPR
auto type(
int index)
const -> detail::type {
2004 int shift = index * detail::packed_arg_bits;
2005 unsigned int mask = (1 << detail::packed_arg_bits) - 1;
2006 return static_cast<detail::type
>((desc_ >> shift) & mask);
2010 const detail::value<Context> *values)
2011 : desc_(desc), values_(values) {}
2013 : desc_(desc), args_(args) {}
2023 template <
typename... Args>
2024 constexpr FMT_INLINE
2027 store.data_.args()) {}
2035 constexpr FMT_INLINE
2049 FMT_CONSTEXPR
auto get(
int id)
const -> format_arg {
2052 if (
id < max_size())
2056 if (
id >= detail::max_packed_args)
2058 arg.type_ = type(
id);
2059 if (arg.type_ == detail::type::none_type)
2061 arg.value_ = values_[id];
2065 template <
typename Char>
2067 int id = get_id(name);
2068 return id >= 0 ? get(
id) : format_arg();
2071 template <
typename Char>
2073 if (!has_named_args())
2075 const auto &named_args =
2076 (is_packed() ? values_[-1] : args_[-1].value_).named_args;
2077 for (
size_t i = 0; i < named_args.size; ++i) {
2078 if (named_args.data[i].name == name)
2079 return named_args.data[i].id;
2084 auto max_size() const ->
int {
2085 unsigned long long max_packed = detail::max_packed_args;
2086 return static_cast<int>(is_packed() ? max_packed :
2087 desc_ & ~detail::is_unpacked_bit);
2100 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 903
2101 #define FMT_ENUM_UNDERLYING_TYPE(type)
2103 #define FMT_ENUM_UNDERLYING_TYPE(type) : type
2106 enum type FMT_ENUM_UNDERLYING_TYPE(
unsigned char){none, left, right, center,
2109 using align_t = align::type;
2111 enum type FMT_ENUM_UNDERLYING_TYPE(
unsigned char){none, minus, plus, space};
2113 using sign_t = sign::type;
2115 FMT_BEGIN_DETAIL_NAMESPACE
2118 template <
typename Char>
struct fill_t {
2120 enum { max_size = 4 };
2121 Char data_[max_size] = {Char(
' '), Char(0), Char(0), Char(0)};
2122 unsigned char size_ = 1;
2126 auto size = s.
size();
2127 FMT_ASSERT(size <= max_size,
"invalid fill");
2128 for (
size_t i = 0; i < size; ++i)
2130 size_ =
static_cast<unsigned char>(size);
2133 constexpr
auto size() const ->
size_t {
return size_; }
2134 constexpr
auto data() const -> const Char * {
return data_; }
2136 FMT_CONSTEXPR
auto operator[](
size_t index) -> Char & {
return data_[index]; }
2137 FMT_CONSTEXPR
auto operator[](
size_t index)
const ->
const Char & {
2138 return data_[index];
2141 FMT_END_DETAIL_NAMESPACE
2143 enum class presentation_type : unsigned char {
2167 template <
typename Char =
char>
struct format_specs {
2170 presentation_type type;
2175 detail::fill_t<Char> fill;
2177 constexpr format_specs()
2180 type(presentation_type::none),
2187 FMT_BEGIN_DETAIL_NAMESPACE
2189 enum class arg_id_kind { none, index, name };
2192 template <
typename Char>
struct arg_ref {
2193 FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {}
2195 FMT_CONSTEXPR
explicit arg_ref(
int index)
2196 : kind(arg_id_kind::index), val(index) {}
2198 : kind(arg_id_kind::name), val(name) {}
2200 FMT_CONSTEXPR
auto operator=(
int idx) -> arg_ref & {
2201 kind = arg_id_kind::index;
2208 FMT_CONSTEXPR value(
int idx = 0) : index(idx) {}
2219 template <
typename Char =
char>
2220 struct dynamic_format_specs : format_specs<Char> {
2221 arg_ref<Char> width_ref;
2222 arg_ref<Char> precision_ref;
2226 template <
typename Char, FMT_ENABLE_IF(std::is_
integral<Char>::value)>
2227 constexpr
auto to_ascii(Char c) ->
char {
2228 return c <= 0xff ? static_cast<char>(c) :
'\0';
2230 template <
typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
2231 constexpr
auto to_ascii(Char c) ->
char {
2232 return c <= 0xff ? static_cast<char>(c) :
'\0';
2235 FMT_CONSTEXPR
inline auto code_point_length_impl(
char c) ->
int {
2236 return "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4"
2237 [
static_cast<unsigned char>(
c) >> 3];
2240 template <
typename Char>
2241 FMT_CONSTEXPR
auto code_point_length(
const Char *begin) ->
int {
2242 if (const_check(
sizeof(Char) != 1))
2244 int len = code_point_length_impl(
static_cast<char>(*begin));
2253 template <
bool IS_CONSTEXPR,
typename T,
typename Ptr = const T *>
2254 FMT_CONSTEXPR
auto find(Ptr first, Ptr last, T value, Ptr &out) ->
bool {
2255 for (out = first; out != last; ++out) {
2263 inline auto find<false, char>(
const char *first,
const char *last,
char value,
2264 const char *&out) ->
bool {
2265 out =
static_cast<const char *
>(
2266 std::memchr(first, value, to_unsigned(last - first)));
2267 return out !=
nullptr;
2272 template <
typename Char>
2273 FMT_CONSTEXPR
auto parse_nonnegative_int(
const Char *&begin,
const Char *end,
2274 int error_value) noexcept ->
int {
2275 FMT_ASSERT(begin != end &&
'0' <= *begin && *begin <=
'9',
"");
2276 unsigned value = 0, prev = 0;
2280 value = value * 10 + unsigned(*p -
'0');
2282 }
while (p != end &&
'0' <= *p && *p <=
'9');
2283 auto num_digits = p - begin;
2285 if (num_digits <= std::numeric_limits<int>::digits10)
2286 return static_cast<int>(value);
2288 const unsigned max = to_unsigned((std::numeric_limits<int>::max)());
2289 return num_digits == std::numeric_limits<int>::digits10 + 1 &&
2290 prev * 10ull + unsigned(p[-1] -
'0') <=
max ?
2291 static_cast<int>(value) :
2295 FMT_CONSTEXPR
inline auto parse_align(
char c) -> align_t {
2300 return align::right;
2302 return align::center;
2307 template <
typename Char> constexpr
auto is_name_start(Char c) ->
bool {
2308 return (
'a' <= c && c <=
'z') || (
'A' <=
c &&
c <=
'Z') || c ==
'_';
2311 template <
typename Char,
typename Handler>
2312 FMT_CONSTEXPR
auto do_parse_arg_id(
const Char *begin,
const Char *end,
2313 Handler &&handler) ->
const Char * {
2315 if (c >=
'0' && c <=
'9') {
2317 constexpr
int max = (std::numeric_limits<int>::max)();
2319 index = parse_nonnegative_int(begin, end, max);
2322 if (begin == end || (*begin !=
'}' && *begin !=
':'))
2323 throw_format_error(
"invalid format string");
2325 handler.on_index(index);
2328 if (!is_name_start(c)) {
2329 throw_format_error(
"invalid format string");
2335 }
while (it != end && (is_name_start(*it) || (
'0' <= *it && *it <=
'9')));
2336 handler.on_name({begin, to_unsigned(it - begin)});
2340 template <
typename Char,
typename Handler>
2341 FMT_CONSTEXPR FMT_INLINE
auto parse_arg_id(
const Char *begin,
const Char *end,
2342 Handler &&handler) ->
const Char * {
2343 FMT_ASSERT(begin != end,
"");
2345 if (c !=
'}' && c !=
':')
2346 return do_parse_arg_id(begin, end, handler);
2351 template <
typename Char>
struct dynamic_spec_id_handler {
2355 FMT_CONSTEXPR
void on_auto() {
2357 ref = arg_ref<Char>(
id);
2358 ctx.check_dynamic_spec(
id);
2360 FMT_CONSTEXPR
void on_index(
int id) {
2361 ref = arg_ref<Char>(
id);
2363 ctx.check_dynamic_spec(
id);
2366 ref = arg_ref<Char>(
id);
2372 template <
typename Char>
2373 FMT_CONSTEXPR
auto parse_dynamic_spec(
const Char *begin,
const Char *end,
2374 int &value, arg_ref<Char> &ref,
2377 FMT_ASSERT(begin != end,
"");
2378 if (
'0' <= *begin && *begin <=
'9') {
2379 int val = parse_nonnegative_int(begin, end, -1);
2383 throw_format_error(
"number is too big");
2384 }
else if (*begin ==
'{') {
2386 auto handler = dynamic_spec_id_handler<Char>{ctx, ref};
2388 begin = parse_arg_id(begin, end, handler);
2389 if (begin != end && *begin ==
'}')
2391 throw_format_error(
"invalid format string");
2396 template <
typename Char>
2397 FMT_CONSTEXPR
auto parse_precision(
const Char *begin,
const Char *end,
2398 int &value, arg_ref<Char> &ref,
2402 if (begin == end || *begin ==
'}') {
2403 throw_format_error(
"invalid precision");
2406 return parse_dynamic_spec(begin, end, value, ref, ctx);
2409 enum class state { start, align, sign, hash, zero, width, precision, locale };
2412 template <
typename Char>
2413 FMT_CONSTEXPR FMT_INLINE
auto
2414 parse_format_specs(
const Char *begin,
const Char *end,
2415 dynamic_format_specs<Char> &specs,
2419 if (end - begin > 1) {
2420 auto next = to_ascii(begin[1]);
2421 c = parse_align(next) == align::none ? to_ascii(*begin) :
'\0';
2425 c = to_ascii(*begin);
2429 state current_state = state::start;
2430 FMT_CONSTEXPR
void operator()(state s,
bool valid =
true) {
2431 if (current_state >= s || !valid)
2432 throw_format_error(
"invalid format specifier");
2437 using pres = presentation_type;
2438 constexpr
auto integral_set = sint_set | uint_set | bool_set | char_set;
2441 dynamic_format_specs<Char> &specs;
2444 FMT_CONSTEXPR
auto operator()(pres type,
int set) ->
const Char * {
2445 if (!in(arg_type, set))
2446 throw_format_error(
"invalid format specifier");
2450 } parse_presentation_type{begin, specs, arg_type};
2457 enter_state(state::align);
2458 specs.align = parse_align(c);
2464 enter_state(state::sign, in(arg_type, sint_set | float_set));
2467 specs.sign = sign::plus;
2470 specs.sign = sign::minus;
2473 specs.sign = sign::space;
2479 enter_state(state::hash, is_arithmetic_type(arg_type));
2484 enter_state(state::zero);
2485 if (!is_arithmetic_type(arg_type))
2486 throw_format_error(
"format specifier requires numeric argument");
2487 if (specs.align == align::none) {
2489 specs.align = align::numeric;
2490 specs.fill[0] = Char(
'0');
2504 enter_state(state::width);
2505 begin = parse_dynamic_spec(begin, end, specs.width, specs.width_ref, ctx);
2508 enter_state(state::precision,
2509 in(arg_type, float_set | string_set | cstring_set));
2510 begin = parse_precision(begin, end, specs.precision, specs.precision_ref,
2514 enter_state(state::locale, is_arithmetic_type(arg_type));
2515 specs.localized =
true;
2519 return parse_presentation_type(pres::dec, integral_set);
2521 return parse_presentation_type(pres::oct, integral_set);
2523 return parse_presentation_type(pres::hex_lower, integral_set);
2525 return parse_presentation_type(pres::hex_upper, integral_set);
2527 return parse_presentation_type(pres::bin_lower, integral_set);
2529 return parse_presentation_type(pres::bin_upper, integral_set);
2531 return parse_presentation_type(pres::hexfloat_lower, float_set);
2533 return parse_presentation_type(pres::hexfloat_upper, float_set);
2535 return parse_presentation_type(pres::exp_lower, float_set);
2537 return parse_presentation_type(pres::exp_upper, float_set);
2539 return parse_presentation_type(pres::fixed_lower, float_set);
2541 return parse_presentation_type(pres::fixed_upper, float_set);
2543 return parse_presentation_type(pres::general_lower, float_set);
2545 return parse_presentation_type(pres::general_upper, float_set);
2547 return parse_presentation_type(pres::chr, integral_set);
2549 return parse_presentation_type(pres::string,
2550 bool_set | string_set | cstring_set);
2552 return parse_presentation_type(pres::pointer, pointer_set | cstring_set);
2554 return parse_presentation_type(pres::debug,
2555 char_set | string_set | cstring_set);
2562 auto fill_end = begin + code_point_length(begin);
2563 if (end - fill_end <= 0) {
2564 throw_format_error(
"invalid format specifier");
2567 if (*begin ==
'{') {
2568 throw_format_error(
"invalid fill character '{'");
2571 auto align = parse_align(to_ascii(*fill_end));
2572 enter_state(state::align, align != align::none);
2573 specs.fill = {begin, to_unsigned(fill_end - begin)};
2574 specs.align = align;
2575 begin = fill_end + 1;
2580 c = to_ascii(*begin);
2584 template <
typename Char,
typename Handler>
2585 FMT_CONSTEXPR
auto parse_replacement_field(
const Char *begin,
const Char *end,
2586 Handler &&handler) ->
const Char * {
2591 FMT_CONSTEXPR
void on_auto() { arg_id = handler.on_arg_id(); }
2592 FMT_CONSTEXPR
void on_index(
int id) { arg_id = handler.on_arg_id(
id); }
2594 arg_id = handler.on_arg_id(
id);
2600 return handler.on_error(
"invalid format string"), end;
2601 if (*begin ==
'}') {
2602 handler.on_replacement_field(handler.on_arg_id(), begin);
2603 }
else if (*begin ==
'{') {
2604 handler.on_text(begin, begin + 1);
2606 auto adapter = id_adapter{handler, 0};
2607 begin = parse_arg_id(begin, end, adapter);
2608 Char
c = begin != end ? *begin : Char();
2610 handler.on_replacement_field(adapter.arg_id, begin);
2611 }
else if (c ==
':') {
2612 begin = handler.on_format_specs(adapter.arg_id, begin + 1, end);
2613 if (begin == end || *begin !=
'}')
2614 return handler.on_error(
"unknown format specifier"), end;
2616 return handler.on_error(
"missing '}' in format string"), end;
2622 template <
bool IS_CONSTEXPR,
typename Char,
typename Handler>
2623 FMT_CONSTEXPR FMT_INLINE
void
2628 auto begin = format_str.
data();
2629 auto end = begin + format_str.
size();
2630 if (end - begin < 32) {
2632 const Char *p = begin;
2636 handler.on_text(begin, p - 1);
2637 begin = p = parse_replacement_field(p - 1, end, handler);
2638 }
else if (c ==
'}') {
2639 if (p == end || *p !=
'}')
2640 return handler.on_error(
"unmatched '}' in format string");
2641 handler.on_text(begin, p);
2645 handler.on_text(begin, end);
2649 FMT_CONSTEXPR
void operator()(
const Char *from,
const Char *to) {
2653 const Char *p =
nullptr;
2654 if (!find<IS_CONSTEXPR>(from, to, Char(
'}'), p))
2655 return handler_.on_text(from, to);
2657 if (p == to || *p !=
'}')
2658 return handler_.on_error(
"unmatched '}' in format string");
2659 handler_.on_text(from, p);
2664 } write = {handler};
2665 while (begin != end) {
2668 const Char *p = begin;
2669 if (*begin !=
'{' && !find<IS_CONSTEXPR>(begin + 1, end, Char(
'{'), p))
2670 return write(begin, end);
2672 begin = parse_replacement_field(p, end, handler);
2676 template <typename T, bool = is_named_arg<T>::value>
struct strip_named_arg {
2679 template <
typename T>
struct strip_named_arg<T, true> {
2680 using type = remove_cvref_t<decltype(T::value)>;
2683 template <
typename T,
typename ParseContext>
2684 FMT_CONSTEXPR
auto parse_format_specs(ParseContext &ctx)
2685 -> decltype(ctx.
begin()) {
2686 using char_type =
typename ParseContext::char_type;
2687 using context = buffer_context<char_type>;
2688 using stripped_type =
typename strip_named_arg<T>::type;
2689 using mapped_type = conditional_t<
2690 mapped_type_constant<T, context>::value != type::custom_type,
2691 decltype(arg_mapper<context>().map(std::declval<const T &>())),
2693 auto f = conditional_t<has_formatter<mapped_type, context>::value,
2694 formatter<mapped_type, char_type>,
2695 fallback_formatter<stripped_type, char_type>>();
2696 return f.parse(ctx);
2700 template <
typename Char>
2701 FMT_CONSTEXPR
auto check_char_specs(
const format_specs<Char> &specs) ->
bool {
2702 if (specs.type != presentation_type::none &&
2703 specs.type != presentation_type::chr &&
2704 specs.type != presentation_type::debug) {
2707 if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
2708 throw_format_error(
"invalid format specifier for char");
2712 constexpr
int invalid_arg_index = -1;
2714 #if FMT_USE_NONTYPE_TEMPLATE_ARGS
2715 template <
int N,
typename T,
typename... Args,
typename Char>
2717 if constexpr (is_statically_named_arg<T>()) {
2718 if (name == T::name)
2721 if constexpr (
sizeof...(Args) > 0)
2722 return get_arg_index_by_name<N + 1, Args...>(name);
2724 return invalid_arg_index;
2728 template <
typename... Args,
typename Char>
2730 #if FMT_USE_NONTYPE_TEMPLATE_ARGS
2731 if constexpr (
sizeof...(Args) > 0)
2732 return get_arg_index_by_name<0, Args...>(name);
2735 return invalid_arg_index;
2738 template <
typename Char,
typename... Args>
class format_string_checker {
2740 using parse_context_type = compile_parse_context<Char>;
2741 static constexpr
int num_args =
sizeof...(Args);
2747 using parse_func =
const Char *(*)(parse_context_type &);
2749 parse_context_type context_;
2750 parse_func parse_funcs_[num_args > 0 ?
static_cast<size_t>(num_args) : 1];
2751 type types_[num_args > 0 ?
static_cast<size_t>(num_args) : 1];
2755 : context_(fmt, num_args, types_),
2756 parse_funcs_{&parse_format_specs<Args, parse_context_type>...},
2757 types_{mapped_type_constant<Args, buffer_context<Char>>::value...} {}
2759 FMT_CONSTEXPR
void on_text(
const Char *,
const Char *) {}
2761 FMT_CONSTEXPR
auto on_arg_id() ->
int {
return context_.next_arg_id(); }
2762 FMT_CONSTEXPR
auto on_arg_id(
int id) ->
int {
2763 return context_.check_arg_id(
id), id;
2766 #if FMT_USE_NONTYPE_TEMPLATE_ARGS
2767 auto index = get_arg_index_by_name<Args...>(id);
2768 if (index == invalid_arg_index)
2769 on_error(
"named argument is not found");
2773 on_error(
"compile-time checks for named arguments require C++20 support");
2778 FMT_CONSTEXPR
void on_replacement_field(
int,
const Char *) {}
2780 FMT_CONSTEXPR
auto on_format_specs(
int id,
const Char *begin,
const Char *)
2782 context_.advance_to(begin);
2784 return id >= 0 &&
id < num_args ? parse_funcs_[id](context_) : begin;
2787 FMT_CONSTEXPR
void on_error(
const char *message) {
2788 throw_format_error(message);
2793 template <
typename...,
typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
2794 FMT_INLINE
void check_format_string(
const S &) {
2795 #ifdef FMT_ENFORCE_COMPILE_STRING
2796 static_assert(is_compile_string<S>::value,
2797 "FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
2801 template <
typename... Args,
typename S,
2802 FMT_ENABLE_IF(is_compile_string<S>::value)>
2803 void check_format_string(S format_str) {
2804 using char_t =
typename S::char_type;
2806 using checker = format_string_checker<char_t, remove_cvref_t<Args>...>;
2807 FMT_CONSTEXPR
bool error = (parse_format_string<true>(s, checker(s)),
true);
2808 ignore_unused(error);
2811 template <
typename Char =
char>
struct vformat_args {
2813 basic_format_context<std::back_insert_iterator<buffer<Char>>, Char>>;
2815 template <>
struct vformat_args<char> {
2820 template <
typename Char>
2828 FMT_END_DETAIL_NAMESPACE
2831 template <
typename T,
typename Char>
2832 struct formatter<T, Char,
2833 enable_if_t<detail::type_constant<T, Char>::value !=
2834 detail::type::custom_type>> {
2836 detail::dynamic_format_specs<Char> specs_;
2839 template <
typename ParseContext>
2840 FMT_CONSTEXPR
auto parse(ParseContext &ctx) ->
const Char * {
2841 auto type = detail::type_constant<T, Char>::value;
2843 detail::parse_format_specs(ctx.
begin(), ctx.
end(), specs_, ctx, type);
2844 if (type == detail::type::char_type)
2845 detail::check_char_specs(specs_);
2849 template <detail::type U = detail::type_constant<T, Char>::value,
2850 FMT_ENABLE_IF(U == detail::type::string_type ||
2851 U == detail::type::cstring_type ||
2852 U == detail::type::char_type)>
2853 FMT_CONSTEXPR
void set_debug_format(
bool set =
true) {
2854 specs_.type = set ? presentation_type::debug : presentation_type::none;
2857 template <
typename FormatContext>
2858 FMT_CONSTEXPR
auto format(
const T &val, FormatContext &ctx)
const
2859 -> decltype(ctx.out());
2862 #define FMT_FORMAT_AS(Type, Base) \
2863 template <typename Char> \
2864 struct formatter<Type, Char> : formatter<Base, Char> { \
2865 template <typename FormatContext> \
2866 auto format(const Type &val, FormatContext &ctx) const \
2867 -> decltype(ctx.out()) { \
2868 return formatter<Base, Char>::format(static_cast<Base>(val), ctx); \
2872 FMT_FORMAT_AS(
signed char,
int);
2873 FMT_FORMAT_AS(
unsigned char,
unsigned);
2874 FMT_FORMAT_AS(
short,
int);
2875 FMT_FORMAT_AS(
unsigned short,
unsigned);
2876 FMT_FORMAT_AS(
long,
long long);
2877 FMT_FORMAT_AS(
unsigned long,
unsigned long long);
2878 FMT_FORMAT_AS(Char *,
const Char *);
2880 FMT_FORMAT_AS(std::nullptr_t,
const void *);
2883 template <
typename Char =
char>
struct runtime_format_string {
2893 template <
typename S,
2899 (std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
2900 std::is_reference<Args>::value)...>() == 0,
2901 "passing views as lvalues is disallowed");
2902 #ifdef FMT_HAS_CONSTEVAL
2903 if constexpr (detail::count_named_args<Args...>() ==
2904 detail::count_statically_named_args<Args...>()) {
2906 detail::format_string_checker<Char, remove_cvref_t<Args>...>;
2907 detail::parse_format_string<true>(str_, checker(s));
2910 detail::check_format_string<Args...>(s);
2919 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
2924 template <
typename... Args>
2936 inline auto runtime(
string_view s) -> runtime_format_string<> {
return {{s}}; }
2952 template <
typename... T>
2955 return vformat(fmt, fmt::make_format_args(args...));
2959 template <
typename OutputIt,
2960 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
2962 auto &&buf = detail::get_buffer<char>(out);
2963 detail::vformat_to(buf, fmt, args, {});
2964 return detail::get_iterator(buf, out);
2979 template <
typename OutputIt,
typename... T,
2980 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
2983 return vformat_to(out, fmt, fmt::make_format_args(args...));
2986 template <
typename OutputIt>
struct format_to_n_result {
2993 template <
typename OutputIt,
typename... T,
2994 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
2996 -> format_to_n_result<OutputIt> {
2997 using traits = detail::fixed_buffer_traits;
2998 auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
2999 detail::vformat_to(buf, fmt, args, {});
3000 return {buf.out(), buf.count()};
3011 template <
typename OutputIt,
typename... T,
3012 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3014 T &&...args) -> format_to_n_result<OutputIt> {
3015 return vformat_to_n(out, n, fmt, fmt::make_format_args(args...));
3019 template <
typename... T>
3021 T &&...args) ->
size_t {
3022 auto buf = detail::counting_buffer<>();
3023 detail::vformat_to<char>(buf, fmt, fmt::make_format_args(args...), {});
3040 template <
typename... T>
3042 const auto &vargs = fmt::make_format_args(args...);
3043 return detail::is_utf8() ? vprint(fmt, vargs) :
3044 detail::vprint_mojibake(stdout, fmt, vargs);
3057 template <
typename... T>
3059 const auto &vargs = fmt::make_format_args(args...);
3060 return detail::is_utf8() ? vprint(f, fmt, vargs) :
3061 detail::vprint_mojibake(
f, fmt, vargs);
3068 template <
typename... T>
3070 return fmt::print(f,
"{}\n", fmt::format(fmt, std::forward<T>(args)...));
3077 template <
typename... T>
3079 return fmt::println(stdout, fmt, std::forward<T>(args)...);
3082 FMT_MODULE_EXPORT_END
3083 FMT_GCC_PRAGMA(
"GCC pop_options")
3086 #ifdef FMT_HEADER_ONLY
FMT_CONSTEXPR auto next_arg_id() -> int
Definition: core.h:725
constexpr auto end() const noexcept -> iterator
Definition: core.h:714
FMT_CONSTEXPR void check_arg_id(int id)
Definition: core.h:740
FMT_CONSTEXPR void advance_to(iterator it)
Definition: core.h:717
constexpr auto begin() const noexcept -> iterator
Definition: core.h:707
FMT_CONSTEXPR basic_string_view(const std::basic_string< Char, Traits, Alloc > &s) noexcept
Definition: core.h:468
constexpr auto size() const noexcept -> size_t
Definition: core.h:480
constexpr auto data() const noexcept -> const Char *
Definition: core.h:477
FMT_CONSTEXPR_CHAR_TRAITS FMT_INLINE basic_string_view(const Char *s)
Definition: core.h:458
constexpr basic_string_view(const Char *s, size_t count) noexcept
Definition: core.h:447
constexpr auto capacity() const noexcept -> size_t
Definition: core.h:942
void clear()
Definition: core.h:951
FMT_CONSTEXPR auto data() noexcept -> T *
Definition: core.h:945
void append(const U *begin, const U *end)
virtual FMT_CONSTEXPR20 void grow(size_t capacity)=0
FMT_CONSTEXPR auto data() const noexcept -> const T *
Definition: core.h:948
FMT_CONSTEXPR void set(T *buf_data, size_t buf_capacity) noexcept
Definition: core.h:917
constexpr auto size() const noexcept -> size_t
Definition: core.h:939
double f(RaB r, PrincipalQN n, DiracQN k, Zeff z, AlphaFS a)
Upper radial component.
Definition: DiracHydrogen.cpp:71
double B(double Z, int l=0)
Bl(Z) fitting function [PRA 93, 052509 (2016)].
Definition: FGRadPot.cpp:132
constexpr double c
speed of light in a.u. (=1/alpha)
Definition: PhysConst_constants.hpp:17
T max(T first, Args... rest)
Returns maximum of any number of parameters (variadic function)
Definition: Maths.hpp:22