18# include <type_traits>
24#define FMT_VERSION 100202
27#if defined(__clang__) && !defined(__ibmxl__)
28# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
30# define FMT_CLANG_VERSION 0
32#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
33# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
35# define FMT_GCC_VERSION 0
38# define FMT_ICC_VERSION __ICL
39#elif defined(__INTEL_COMPILER)
40# define FMT_ICC_VERSION __INTEL_COMPILER
42# define FMT_ICC_VERSION 0
45# define FMT_MSC_VERSION _MSC_VER
47# define FMT_MSC_VERSION 0
51#ifdef _GLIBCXX_RELEASE
52# define FMT_GLIBCXX_RELEASE _GLIBCXX_RELEASE
54# define FMT_GLIBCXX_RELEASE 0
57# define FMT_LIBCPP_VERSION _LIBCPP_VERSION
59# define FMT_LIBCPP_VERSION 0
63# define FMT_CPLUSPLUS _MSVC_LANG
65# define FMT_CPLUSPLUS __cplusplus
70# define FMT_HAS_FEATURE(x) __has_feature(x)
72# define FMT_HAS_FEATURE(x) 0
75# define FMT_HAS_INCLUDE(x) __has_include(x)
77# define FMT_HAS_INCLUDE(x) 0
79#ifdef __has_cpp_attribute
80# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
82# define FMT_HAS_CPP_ATTRIBUTE(x) 0
85#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
86 (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
88#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
89 (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
92#ifdef FMT_USE_CONSTEXPR
94#elif FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L
97# define FMT_USE_CONSTEXPR 1
99# define FMT_USE_CONSTEXPR 0
100#elif FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912
101# define FMT_USE_CONSTEXPR 1
103# define FMT_USE_CONSTEXPR 0
106# define FMT_CONSTEXPR constexpr
108# define FMT_CONSTEXPR
112#if !defined(__cpp_lib_is_constant_evaluated)
113# define FMT_USE_CONSTEVAL 0
114#elif FMT_CPLUSPLUS < 201709L
115# define FMT_USE_CONSTEVAL 0
116#elif FMT_GLIBCXX_RELEASE && FMT_GLIBCXX_RELEASE < 10
117# define FMT_USE_CONSTEVAL 0
118#elif FMT_LIBCPP_VERSION && FMT_LIBCPP_VERSION < 10000
119# define FMT_USE_CONSTEVAL 0
120#elif defined(__apple_build_version__) && __apple_build_version__ < 14000029L
121# define FMT_USE_CONSTEVAL 0
122#elif FMT_MSC_VERSION && FMT_MSC_VERSION < 1929
123# define FMT_USE_CONSTEVAL 0
124#elif defined(__cpp_consteval)
125# define FMT_USE_CONSTEVAL 1
126#elif FMT_GCC_VERSION >= 1002 || FMT_CLANG_VERSION >= 1101
127# define FMT_USE_CONSTEVAL 1
129# define FMT_USE_CONSTEVAL 0
132# define FMT_CONSTEVAL consteval
133# define FMT_CONSTEXPR20 constexpr
135# define FMT_CONSTEVAL
136# define FMT_CONSTEXPR20
139#if defined(FMT_USE_NONTYPE_TEMPLATE_ARGS)
141#elif defined(__NVCOMPILER)
142# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0
143#elif FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L
144# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1
145#elif defined(__cpp_nontype_template_args) && \
146 __cpp_nontype_template_args >= 201911L
147# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1
149# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0
155#elif defined(__GNUC__) && !defined(__EXCEPTIONS)
156# define FMT_EXCEPTIONS 0
157#elif FMT_MSC_VERSION && !_HAS_EXCEPTIONS
158# define FMT_EXCEPTIONS 0
160# define FMT_EXCEPTIONS 1
164# define FMT_CATCH(x) catch (x)
166# define FMT_TRY if (true)
167# define FMT_CATCH(x) if (false)
170#if FMT_HAS_CPP17_ATTRIBUTE(fallthrough)
171# define FMT_FALLTHROUGH [[fallthrough]]
172#elif defined(__clang__)
173# define FMT_FALLTHROUGH [[clang::fallthrough]]
174#elif FMT_GCC_VERSION >= 700 && \
175 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
176# define FMT_FALLTHROUGH [[gnu::fallthrough]]
178# define FMT_FALLTHROUGH
182#if FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && !defined(__NVCC__)
183# define FMT_NORETURN [[noreturn]]
189# if FMT_HAS_CPP17_ATTRIBUTE(nodiscard)
190# define FMT_NODISCARD [[nodiscard]]
192# define FMT_NODISCARD
198#elif FMT_HAS_CPP14_ATTRIBUTE(deprecated)
199# define FMT_DEPRECATED [[deprecated]]
201# define FMT_DEPRECATED
206#elif FMT_GCC_VERSION || FMT_CLANG_VERSION
207# define FMT_ALWAYS_INLINE inline __attribute__((always_inline))
209# define FMT_ALWAYS_INLINE inline
213# define FMT_INLINE FMT_ALWAYS_INLINE
215# define FMT_INLINE inline
218#if FMT_GCC_VERSION || FMT_CLANG_VERSION
219# define FMT_VISIBILITY(value) __attribute__((visibility(value)))
221# define FMT_VISIBILITY(value)
224#ifndef FMT_GCC_PRAGMA
227# if FMT_GCC_VERSION >= 504 && !defined(__NVCOMPILER)
228# define FMT_GCC_PRAGMA(arg) _Pragma(arg)
230# define FMT_GCC_PRAGMA(arg)
235#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
236# define FMT_DECLTYPE_THIS this->
238# define FMT_DECLTYPE_THIS
242# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__))
243# define FMT_UNCHECKED_ITERATOR(It) \
244 using _Unchecked_type = It
246# define FMT_MSC_WARNING(...)
247# define FMT_UNCHECKED_ITERATOR(It) using unchecked_type = It
250#ifndef FMT_BEGIN_NAMESPACE
251# define FMT_BEGIN_NAMESPACE \
253 inline namespace v10 {
254# define FMT_END_NAMESPACE \
261# define FMT_BEGIN_EXPORT
262# define FMT_END_EXPORT
265#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
266# if defined(FMT_LIB_EXPORT)
267# define FMT_API __declspec(dllexport)
268# elif defined(FMT_SHARED)
269# define FMT_API __declspec(dllimport)
271#elif defined(FMT_LIB_EXPORT) || defined(FMT_SHARED)
272# define FMT_API FMT_VISIBILITY("default")
279# define FMT_UNICODE 1
282#define FMT_FWD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
285FMT_GCC_PRAGMA(
"GCC push_options")
286#if !defined(__OPTIMIZE__) && !defined(__CUDACC__)
287FMT_GCC_PRAGMA(
"GCC optimize(\"Og\")")
293template <
bool B,
typename T =
void>
294using enable_if_t =
typename std::enable_if<B, T>::type;
295template <
bool B,
typename T,
typename F>
296using conditional_t =
typename std::conditional<B, T, F>::type;
297template <
bool B>
using bool_constant = std::integral_constant<bool, B>;
299using remove_reference_t =
typename std::remove_reference<T>::type;
301using remove_const_t =
typename std::remove_const<T>::type;
303using remove_cvref_t =
typename std::remove_cv<remove_reference_t<T>>::type;
307template <
typename T>
using type_identity_t =
typename type_identity<T>::type;
309using make_unsigned_t =
typename std::make_unsigned<T>::type;
311using underlying_t =
typename std::underlying_type<T>::type;
313#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
315template <
typename...>
struct void_t_impl {
318template <
typename... T>
using void_t =
typename void_t_impl<T...>::type;
320template <
typename...>
using void_t = void;
331# define FMT_ENABLE_IF(...)
333# define FMT_ENABLE_IF(...) fmt::enable_if_t<(__VA_ARGS__), int> = 0
339template <
typename T, FMT_ENABLE_IF(std::is_same<T, std::
byte>::value)>
340inline auto format_as(T b) ->
unsigned char {
341 return static_cast<unsigned char>(b);
349template <
typename... T> FMT_CONSTEXPR
void ignore_unused(
const T&...) {}
351constexpr auto is_constant_evaluated(
bool default_value =
false) noexcept
356#if FMT_CPLUSPLUS >= 202002L && FMT_GLIBCXX_RELEASE >= 12 && \
357 (FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500)
358 ignore_unused(default_value);
359 return __builtin_is_constant_evaluated();
360#elif defined(__cpp_lib_is_constant_evaluated)
361 ignore_unused(default_value);
362 return std::is_constant_evaluated();
364 return default_value;
369template <
typename T>
constexpr auto const_check(T value) -> T {
return value; }
371FMT_NORETURN FMT_API
void assert_fail(
const char* file,
int line,
372 const char* message);
374#if defined(FMT_ASSERT)
378# define FMT_ASSERT(condition, message) \
379 fmt::detail::ignore_unused((condition), (message))
381# define FMT_ASSERT(condition, message) \
384 : fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
389#elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \
390 !(FMT_CLANG_VERSION && FMT_MSC_VERSION)
391# define FMT_USE_INT128 1
392using int128_opt = __int128_t;
393using uint128_opt = __uint128_t;
394template <
typename T>
inline auto convert_for_visit(T value) -> T {
398# define FMT_USE_INT128 0
401enum class int128_opt {};
402enum class uint128_opt {};
404template <
typename T>
auto convert_for_visit(T) ->
monostate {
return {}; }
408template <
typename Int>
409FMT_CONSTEXPR
auto to_unsigned(Int value) -> make_unsigned_t<Int> {
410 FMT_ASSERT(std::is_unsigned<Int>::value || value >= 0,
"negative value");
411 return static_cast<make_unsigned_t<Int>
>(value);
416template <
typename T,
typename Enable =
void>
420 typename T::value_type(), 0))>>
424constexpr auto is_utf8_enabled() ->
bool {
426 using uchar =
unsigned char;
427 return sizeof(
"\u00A7") == 3 && uchar(
"\u00A7"[0]) == 0xC2 &&
428 uchar(
"\u00A7"[1]) == 0xA7;
430constexpr auto use_utf8() ->
bool {
431 return !FMT_MSC_VERSION || is_utf8_enabled();
434static_assert(!FMT_UNICODE || use_utf8(),
435 "Unicode support requires compiling with /utf-8");
437template <
typename Char> FMT_CONSTEXPR
auto length(
const Char* s) ->
size_t {
443template <
typename Char>
444FMT_CONSTEXPR
auto compare(
const Char* s1,
const Char* s2, std::size_t n)
446 for (; n != 0; ++s1, ++s2, --n) {
447 if (*s1 < *s2)
return -1;
448 if (*s1 > *s2)
return 1;
453template <
typename It,
typename Enable = std::true_type>
455template <
typename It>
458 bool_constant<std::is_same<
459 decltype(back_inserter(std::declval<typename It::container_type&>())),
460 It>::value>> : std::true_type {};
463template <
typename OutputIt>
464inline auto get_container(OutputIt it) ->
typename OutputIt::container_type& {
465 struct accessor : OutputIt {
466 accessor(OutputIt base) : OutputIt(base) {}
467 using OutputIt::container;
469 return *accessor(it).container;
490 using value_type = Char;
491 using iterator =
const Char*;
497 : data_(s), size_(count) {}
507 size_(detail::const_check(std::is_same<Char, char>::value &&
508 !detail::is_constant_evaluated(false))
509 ? strlen(reinterpret_cast<const char*>(s))
510 : detail::length(s)) {}
516 template <
typename S,
518 typename S::value_type, Char>::value)>
520 : data_(s.data()), size_(s.size()) {}
523 constexpr auto data() const noexcept -> const Char* {
return data_; }
526 constexpr auto size() const noexcept ->
size_t {
return size_; }
528 constexpr auto begin() const noexcept -> iterator {
return data_; }
529 constexpr auto end() const noexcept -> iterator {
return data_ + size_; }
531 constexpr auto operator[](
size_t pos)
const noexcept ->
const Char& {
535 FMT_CONSTEXPR
void remove_prefix(
size_t n)
noexcept {
542 return size_ >= sv.size_ && detail::compare(data_, sv.data_, sv.size_) == 0;
544 FMT_CONSTEXPR
auto starts_with(Char c)
const noexcept ->
bool {
545 return size_ >= 1 && *data_ == c;
547 FMT_CONSTEXPR
auto starts_with(
const Char* s)
const ->
bool {
553 size_t str_size = size_ < other.size_ ? size_ : other.size_;
554 int result = detail::compare(data_, other.data_, str_size);
556 result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
562 return lhs.compare(rhs) == 0;
565 return lhs.compare(rhs) != 0;
568 return lhs.compare(rhs) < 0;
571 return lhs.compare(rhs) <= 0;
574 return lhs.compare(rhs) > 0;
577 return lhs.compare(rhs) >= 0;
586template <
typename T>
struct is_char : std::false_type {};
587template <>
struct is_char<char> : std::true_type {};
594template <
typename Char, FMT_ENABLE_IF(is_
char<Char>::value)>
598template <
typename T, FMT_ENABLE_IF(is_std_
string_like<T>::value)>
602template <
typename Char>
608template <
typename T,
typename Enable =
void>
613 T, void_t<decltype(detail::to_string_view(std::declval<T>()))>>
617 static constexpr Char
value[
sizeof...(C)] = {C...};
619 return {
value,
sizeof...(C)};
622#if FMT_CPLUSPLUS < 201703L
623template <
typename Char, Char... C>
638 last_integer_type = char_type,
643 last_numeric_type = long_double_type,
651template <
typename T,
typename Char>
654#define FMT_TYPE_CONSTANT(Type, constant) \
655 template <typename Char> \
656 struct type_constant<Type, Char> \
657 : std::integral_constant<type, type::constant> {}
659FMT_TYPE_CONSTANT(
int, int_type);
660FMT_TYPE_CONSTANT(
unsigned, uint_type);
661FMT_TYPE_CONSTANT(
long long, long_long_type);
662FMT_TYPE_CONSTANT(
unsigned long long, ulong_long_type);
663FMT_TYPE_CONSTANT(int128_opt, int128_type);
664FMT_TYPE_CONSTANT(uint128_opt, uint128_type);
665FMT_TYPE_CONSTANT(
bool, bool_type);
666FMT_TYPE_CONSTANT(Char, char_type);
667FMT_TYPE_CONSTANT(
float, float_type);
668FMT_TYPE_CONSTANT(
double, double_type);
669FMT_TYPE_CONSTANT(
long double, long_double_type);
670FMT_TYPE_CONSTANT(
const Char*, cstring_type);
672FMT_TYPE_CONSTANT(
const void*, pointer_type);
674constexpr auto is_integral_type(type t) ->
bool {
675 return t > type::none_type && t <= type::last_integer_type;
677constexpr auto is_arithmetic_type(type t) ->
bool {
678 return t > type::none_type && t <= type::last_numeric_type;
681constexpr auto set(type rhs) ->
int {
return 1 <<
static_cast<int>(rhs); }
682constexpr auto in(type t,
int set) ->
bool {
683 return ((set >>
static_cast<int>(t)) & 1) != 0;
689 set(type::int_type) | set(type::long_long_type) | set(type::int128_type),
690 uint_set = set(type::uint_type) | set(type::ulong_long_type) |
691 set(type::uint128_type),
692 bool_set = set(type::bool_type),
693 char_set = set(type::char_type),
694 float_set = set(type::float_type) | set(type::double_type) |
695 set(type::long_double_type),
696 string_set = set(type::string_type),
697 cstring_set = set(type::cstring_type),
698 pointer_set = set(type::pointer_type)
707FMT_NORETURN FMT_API
void report_error(
const char* message);
709FMT_DEPRECATED FMT_NORETURN
inline void throw_format_error(
710 const char* message) {
711 report_error(message);
716 typename V =
decltype(detail::to_string_view(std::declval<S>()))>
717using char_t =
typename V::value_type;
732 FMT_CONSTEXPR
void do_check_arg_id(
int id);
735 using char_type = Char;
736 using iterator =
const Char*;
740 : format_str_(format_str), next_arg_id_(next_arg_id) {}
746 constexpr auto begin() const noexcept -> iterator {
747 return format_str_.begin();
753 constexpr auto end() const noexcept -> iterator {
return format_str_.end(); }
757 format_str_.remove_prefix(detail::to_unsigned(it - begin()));
765 if (next_arg_id_ < 0) {
766 report_error(
"cannot switch from manual to automatic argument indexing");
769 int id = next_arg_id_++;
779 if (next_arg_id_ > 0) {
780 report_error(
"cannot switch from automatic to manual argument indexing");
789 FMT_CONSTEXPR
void check_dynamic_spec(
int arg_id);
797template <
typename Char>
808 :
base(format_str, next_arg_id), num_args_(num_args), types_(types) {}
810 constexpr auto num_args()
const ->
int {
return num_args_; }
811 constexpr auto arg_type(
int id)
const -> type {
return types_[id]; }
813 FMT_CONSTEXPR
auto next_arg_id() ->
int {
814 int id = base::next_arg_id();
815 if (
id >= num_args_) report_error(
"argument not found");
819 FMT_CONSTEXPR
void check_arg_id(
int id) {
820 base::check_arg_id(
id);
821 if (
id >= num_args_) report_error(
"argument not found");
823 using base::check_arg_id;
825 FMT_CONSTEXPR
void check_dynamic_spec(
int arg_id) {
826 detail::ignore_unused(arg_id);
827 if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
828 report_error(
"width/precision is not integer");
844 using grow_fun = void (*)(
buffer& buf,
size_t capacity);
849 FMT_MSC_WARNING(suppress : 26495)
850 FMT_CONSTEXPR20
buffer(grow_fun grow,
size_t sz) noexcept
851 : size_(sz), capacity_(sz), grow_(grow) {}
853 constexpr buffer(grow_fun grow, T* p =
nullptr,
size_t sz = 0,
854 size_t cap = 0) noexcept
855 : ptr_(p), size_(sz), capacity_(cap), grow_(grow) {}
857 FMT_CONSTEXPR20
~buffer() =
default;
861 FMT_CONSTEXPR
void set(T* buf_data,
size_t buf_capacity)
noexcept {
863 capacity_ = buf_capacity;
867 using value_type = T;
868 using const_reference =
const T&;
871 void operator=(
const buffer&) =
delete;
873 auto begin() noexcept -> T* {
return ptr_; }
874 auto end() noexcept -> T* {
return ptr_ + size_; }
876 auto begin() const noexcept -> const T* {
return ptr_; }
877 auto end() const noexcept -> const T* {
return ptr_ + size_; }
880 constexpr auto size() const noexcept ->
size_t {
return size_; }
883 constexpr auto capacity() const noexcept ->
size_t {
return capacity_; }
886 FMT_CONSTEXPR
auto data() noexcept -> T* {
return ptr_; }
887 FMT_CONSTEXPR
auto data() const noexcept -> const T* {
return ptr_; }
894 FMT_CONSTEXPR
void try_resize(
size_t count) {
896 size_ = count <= capacity_ ? count : capacity_;
903 FMT_CONSTEXPR
void try_reserve(
size_t new_capacity) {
904 if (new_capacity > capacity_) grow_(*
this, new_capacity);
907 FMT_CONSTEXPR
void push_back(
const T& value) {
908 try_reserve(size_ + 1);
909 ptr_[size_++] = value;
913 template <
typename U>
void append(
const U* begin,
const U* end) {
914 while (begin != end) {
915 auto count = to_unsigned(end - begin);
916 try_reserve(size_ + count);
917 auto free_cap = capacity_ - size_;
918 if (free_cap < count) count = free_cap;
919 if (std::is_same<T, U>::value) {
920 memcpy(ptr_ + size_, begin, count *
sizeof(T));
922 T* out = ptr_ + size_;
923 for (
size_t i = 0; i < count; ++i) out[i] = begin[i];
930 template <
typename Idx> FMT_CONSTEXPR
auto operator[](Idx index) -> T& {
933 template <
typename Idx>
934 FMT_CONSTEXPR
auto operator[](Idx index)
const ->
const T& {
941 auto count()
const ->
size_t {
return 0; }
942 auto limit(
size_t size) ->
size_t {
return size; }
952 auto count()
const ->
size_t {
return count_; }
953 auto limit(
size_t size) ->
size_t {
954 size_t n = limit_ > count_ ? limit_ - count_ : 0;
956 return size < n ? size : n;
961template <
typename OutputIt,
typename T,
typename Traits = buffer_traits>
965 enum { buffer_size = 256 };
966 T data_[buffer_size];
968 static FMT_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
973 auto size = this->size();
975 const T* begin = data_;
976 const T* end = begin + this->limit(size);
977 while (begin != end) *out_++ = *begin++;
982 : Traits(n),
buffer<T>(grow, data_, 0, buffer_size), out_(out) {}
993 auto out() -> OutputIt {
997 auto count()
const ->
size_t {
return Traits::count() + this->size(); }
1000template <
typename T>
1005 enum { buffer_size = 256 };
1006 T data_[buffer_size];
1008 static FMT_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
1014 size_t n = this->limit(this->size());
1015 if (this->data() == out_) {
1017 this->set(data_, buffer_size);
1029 if (this->data() != out_) {
1030 this->set(data_, buffer_size);
1040 auto count()
const ->
size_t {
1041 return fixed_buffer_traits::count() + this->size();
1050 auto out() -> T* {
return &*this->end(); }
1054template <
typename OutputIt>
1059 typename OutputIt::container_type::value_type>>
1060 :
public buffer<typename OutputIt::container_type::value_type> {
1062 using container_type =
typename OutputIt::container_type;
1063 using value_type =
typename container_type::value_type;
1064 container_type& container_;
1068 self.container_.resize(capacity);
1069 self.
set(&self.container_[0], capacity);
1078 auto out() -> OutputIt {
return back_inserter(container_); }
1084 enum { buffer_size = 256 };
1085 T data_[buffer_size];
1088 static FMT_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
1089 if (buf.
size() != buffer_size)
return;
1097 auto count() ->
size_t {
return count_ + this->size(); }
1101template <
typename Char>
1105 if (detail::is_constant_evaluated() &&
1106 (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) {
1108 if (
id >=
static_cast<context*
>(
this)->num_args())
1109 report_error(
"argument not found");
1113template <
typename Char>
1116 if (detail::is_constant_evaluated() &&
1117 (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) {
1119 static_cast<context*
>(
this)->check_dynamic_spec(arg_id);
1129template <
typename T,
typename Char =
char,
typename Enable =
void>
1137template <
typename T,
typename Context>
1138using has_formatter =
1139 std::is_constructible<typename Context::template formatter_type<T>>;
1148 return *app.buffer_;
1152 using iterator_category = int;
1153 using value_type = T;
1154 using difference_type = ptrdiff_t;
1156 using reference = T&;
1162 buffer_->push_back(c);
1174template <
typename T,
typename Enable =
void>
1176template <
typename T>
1178 : std::false_type {};
1180template <
typename T =
int> FMT_CONSTEXPR
inline auto is_locking() ->
bool {
1183template <
typename T1,
typename T2,
typename... Tail>
1184FMT_CONSTEXPR
inline auto is_locking() ->
bool {
1185 return locking<T1>::value || is_locking<T2, Tail...>();
1189template <
typename T,
typename InputIt>
1191 get_container(out).append(begin, end);
1195template <
typename T,
typename InputIt,
typename OutputIt,
1196 FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value)>
1197auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
1198 get_container(out).append(begin, end);
1202template <
typename T,
typename InputIt,
typename OutputIt,
1203 FMT_ENABLE_IF(!is_back_insert_iterator<OutputIt>::value)>
1204FMT_CONSTEXPR
auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
1205 while (begin != end) *out++ =
static_cast<T
>(*begin++);
1209template <
typename T>
1210FMT_CONSTEXPR
auto copy(
const T* begin,
const T* end, T* out) -> T* {
1211 if (is_constant_evaluated())
return copy<T, const T*, T*>(begin, end, out);
1212 auto size = to_unsigned(end - begin);
1213 if (size > 0) memcpy(out, begin, size *
sizeof(T));
1217template <
typename T,
typename V,
typename OutputIt>
1219 return copy<T>(s.begin(), s.end(), out);
1222template <
typename Context,
typename T>
1223constexpr auto has_const_formatter_impl(T*)
1224 ->
decltype(
typename Context::template formatter_type<T>().format(
1225 std::declval<const T&>(), std::declval<Context&>()),
1229template <
typename Context>
1230constexpr auto has_const_formatter_impl(...) ->
bool {
1233template <
typename T,
typename Context>
1234constexpr auto has_const_formatter() ->
bool {
1235 return has_const_formatter_impl<Context>(
static_cast<T*
>(
nullptr));
1239template <
typename T,
typename OutputIt>
1240auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
1241 return iterator_buffer<OutputIt, T>(out);
1244 return get_container(out);
1247template <
typename Buf,
typename OutputIt>
1248auto get_iterator(Buf& buf, OutputIt) ->
decltype(buf.out()) {
1251template <
typename T,
typename OutputIt>
1252auto get_iterator(buffer<T>&, OutputIt out) -> OutputIt {
1272template <
typename T,
typename Char>
1275template <
bool B = false>
constexpr auto count() ->
size_t {
return B ? 1 : 0; }
1276template <
bool B1,
bool B2,
bool... Tail>
constexpr auto count() ->
size_t {
1277 return (B1 ? 1 : 0) + count<B2, Tail...>();
1280template <
typename... Args>
constexpr auto count_named_args() ->
size_t {
1281 return count<is_named_arg<Args>::value...>();
1284template <
typename... Args>
1285constexpr auto count_statically_named_args() ->
size_t {
1286 return count<is_statically_named_arg<Args>::value...>();
1304 using parse_context =
typename Context::parse_context_type;
1306 void (*format)(
void* arg, parse_context& parse_ctx, Context& ctx);
1310template <
typename Context>
class value {
1312 using char_type =
typename Context::char_type;
1317 unsigned uint_value;
1318 long long long_long_value;
1319 unsigned long long ulong_long_value;
1320 int128_opt int128_value;
1321 uint128_opt uint128_value;
1323 char_type char_value;
1325 double double_value;
1326 long double long_double_value;
1327 const void* pointer;
1333 constexpr FMT_ALWAYS_INLINE
value() : no_value() {}
1334 constexpr FMT_ALWAYS_INLINE
value(
int val) : int_value(val) {}
1335 constexpr FMT_ALWAYS_INLINE
value(
unsigned val) : uint_value(val) {}
1336 constexpr FMT_ALWAYS_INLINE
value(
long long val) : long_long_value(val) {}
1337 constexpr FMT_ALWAYS_INLINE
value(
unsigned long long val)
1338 : ulong_long_value(val) {}
1339 FMT_ALWAYS_INLINE
value(int128_opt val) : int128_value(val) {}
1340 FMT_ALWAYS_INLINE
value(uint128_opt val) : uint128_value(val) {}
1341 constexpr FMT_ALWAYS_INLINE
value(
float val) : float_value(val) {}
1342 constexpr FMT_ALWAYS_INLINE
value(
double val) : double_value(val) {}
1343 FMT_ALWAYS_INLINE
value(
long double val) : long_double_value(val) {}
1344 constexpr FMT_ALWAYS_INLINE
value(
bool val) : bool_value(val) {}
1345 constexpr FMT_ALWAYS_INLINE
value(char_type val) : char_value(val) {}
1346 FMT_CONSTEXPR FMT_ALWAYS_INLINE
value(
const char_type* val) {
1348 if (is_constant_evaluated())
string.size = {};
1351 string.data = val.
data();
1352 string.size = val.
size();
1354 FMT_ALWAYS_INLINE
value(
const void* val) : pointer(val) {}
1356 : named_args{args, size} {}
1358 template <
typename T> FMT_CONSTEXPR20 FMT_ALWAYS_INLINE
value(T& val) {
1359 using value_type = remove_const_t<T>;
1361#if defined(__cpp_if_constexpr)
1362 if constexpr (std::is_same<
decltype(&val), T*>::value)
1363 custom.value =
const_cast<value_type*
>(&val);
1365 if (!is_constant_evaluated())
1366 custom.value =
const_cast<char*
>(&
reinterpret_cast<const char&
>(val));
1370 custom.format = format_custom_arg<
1371 value_type,
typename Context::template formatter_type<value_type>>;
1379 template <
typename T,
typename Formatter>
1380 static void format_custom_arg(
void* arg,
1381 typename Context::parse_context_type& parse_ctx,
1383 auto f = Formatter();
1384 parse_ctx.advance_to(f.parse(parse_ctx));
1385 using qualified_type =
1386 conditional_t<has_const_formatter<T, Context>(),
const T, T>;
1389 ctx.advance_to(cf.format(*
static_cast<qualified_type*
>(arg), ctx));
1395enum { long_short =
sizeof(long) ==
sizeof(
int) };
1396using long_type = conditional_t<long_short, int, long long>;
1397using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
1400 template <
typename U,
1401 FMT_ENABLE_IF(std::is_enum<U>::value || std::is_class<U>::value)>
1402 static auto map(U*) -> remove_cvref_t<decltype(format_as(std::declval<U>()))>;
1403 static auto map(...) -> void;
1405 using type =
decltype(map(
static_cast<T*
>(
nullptr)));
1407template <
typename T>
using format_as_t =
typename format_as_result<T>::type;
1409template <
typename T>
1411 : bool_constant<!std::is_same<format_as_t<T>, void>::value> {};
1413#define FMT_MAP_API FMT_CONSTEXPR FMT_ALWAYS_INLINE
1419 using char_type =
typename Context::char_type;
1421 FMT_MAP_API
auto map(
signed char val) ->
int {
return val; }
1422 FMT_MAP_API
auto map(
unsigned char val) ->
unsigned {
return val; }
1423 FMT_MAP_API
auto map(
short val) ->
int {
return val; }
1424 FMT_MAP_API
auto map(
unsigned short val) ->
unsigned {
return val; }
1425 FMT_MAP_API
auto map(
int val) ->
int {
return val; }
1426 FMT_MAP_API
auto map(
unsigned val) ->
unsigned {
return val; }
1427 FMT_MAP_API
auto map(
long val) -> long_type {
return val; }
1428 FMT_MAP_API
auto map(
unsigned long val) -> ulong_type {
return val; }
1429 FMT_MAP_API
auto map(
long long val) ->
long long {
return val; }
1430 FMT_MAP_API
auto map(
unsigned long long val) ->
unsigned long long {
1433 FMT_MAP_API
auto map(int128_opt val) -> int128_opt {
return val; }
1434 FMT_MAP_API
auto map(uint128_opt val) -> uint128_opt {
return val; }
1435 FMT_MAP_API
auto map(
bool val) ->
bool {
return val; }
1437 template <
typename T, FMT_ENABLE_IF(std::is_same<T,
char>::value ||
1438 std::is_same<T,
char_type>::value)>
1439 FMT_MAP_API
auto map(T val) -> char_type {
1442 template <
typename T, enable_if_t<(std::is_same<T,
wchar_t>::value ||
1444 std::is_same<T,
char8_t>::value ||
1446 std::is_same<T,
char16_t>::value ||
1447 std::is_same<T,
char32_t>::value) &&
1448 !std::is_same<T,
char_type>::value,
1454 FMT_MAP_API
auto map(
float val) ->
float {
return val; }
1455 FMT_MAP_API
auto map(
double val) ->
double {
return val; }
1456 FMT_MAP_API
auto map(
long double val) ->
long double {
return val; }
1458 FMT_MAP_API
auto map(char_type* val) ->
const char_type* {
return val; }
1459 FMT_MAP_API
auto map(
const char_type* val) ->
const char_type* {
return val; }
1460 template <
typename T,
typename Char =
char_t<T>,
1461 FMT_ENABLE_IF(std::is_same<Char,
char_type>::value &&
1462 !std::is_po
inter<T>::value)>
1464 return to_string_view(val);
1466 template <
typename T,
typename Char =
char_t<T>,
1467 FMT_ENABLE_IF(!std::is_same<Char,
char_type>::value &&
1468 !std::is_po
inter<T>::value)>
1473 FMT_MAP_API
auto map(
void* val) ->
const void* {
return val; }
1474 FMT_MAP_API
auto map(
const void* val) ->
const void* {
return val; }
1475 FMT_MAP_API
auto map(std::nullptr_t val) ->
const void* {
return val; }
1482 std::is_pointer<T>::value || std::is_member_pointer<T>::value ||
1483 std::is_function<
typename std::remove_pointer<T>::type>::value ||
1484 (std::is_array<T>::value &&
1485 !std::is_convertible<T, const char_type*>::value))>
1490 template <
typename T, std::size_t N,
1491 FMT_ENABLE_IF(!std::is_same<T, wchar_t>::value)>
1492 FMT_MAP_API
auto map(
const T (&values)[N]) ->
const T (&)[N] {
1497 template <
typename T,
typename U = format_as_t<T>,
1498 FMT_ENABLE_IF(std::is_arithmetic<U>::value)>
1499 FMT_MAP_API
auto map(
const T& val) ->
decltype(FMT_DECLTYPE_THIS map(U())) {
1500 return map(format_as(val));
1503 template <
typename T,
typename U = remove_const_t<T>>
1504 struct formattable : bool_constant<has_const_formatter<U, Context>() ||
1505 (has_formatter<U, Context>::value &&
1506 !std::is_const<T>::value)> {};
1508 template <
typename T, FMT_ENABLE_IF(formattable<T>::value)>
1509 FMT_MAP_API
auto do_map(T& val) -> T& {
1512 template <
typename T, FMT_ENABLE_IF(!formattable<T>::value)>
1518 template <
typename T,
typename U = remove_const_t<T>,
1520 (std::is_
class<U>::value || std::is_enum<U>::value ||
1521 std::is_union<U>::value || std::is_fundamental<U>::value) &&
1522 !has_to_
string_view<U>::value && !is_
char<U>::value &&
1523 !is_named_arg<U>::value && !std::is_
integral<U>::value &&
1524 !std::is_arithmetic<format_as_t<U>>::value)>
1525 FMT_MAP_API
auto map(T& val) ->
decltype(FMT_DECLTYPE_THIS do_map(val)) {
1529 template <
typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
1530 FMT_MAP_API
auto map(
const T& named_arg)
1531 ->
decltype(FMT_DECLTYPE_THIS map(named_arg.value)) {
1532 return map(named_arg.value);
1535 auto map(...) -> unformattable {
return {}; }
1539template <
typename T,
typename Context>
1540using mapped_type_constant =
1541 type_constant<decltype(arg_mapper<Context>().map(std::declval<const T&>())),
1542 typename Context::char_type>;
1544enum { packed_arg_bits = 4 };
1546enum { max_packed_args = 62 / packed_arg_bits };
1547enum :
unsigned long long { is_unpacked_bit = 1ULL << 63 };
1548enum :
unsigned long long { has_named_args_bit = 1ULL << 62 };
1550template <
typename It,
typename T,
typename Enable =
void>
1555template <
typename It,
typename T>
1557 It, T, void_t<decltype(*std::declval<It&>()++ = std::declval<T>())>>
1558 : std::true_type {};
1563 const void* locale_;
1567 template <
typename Locale>
explicit locale_ref(
const Locale& loc);
1569 explicit operator bool()
const noexcept {
return locale_ !=
nullptr; }
1571 template <
typename Locale>
auto get()
const -> Locale;
1574template <
typename>
constexpr auto encode_types() ->
unsigned long long {
1578template <
typename Context,
typename Arg,
typename... Args>
1579constexpr auto encode_types() ->
unsigned long long {
1580 return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) |
1581 (encode_types<Context, Args...>() << packed_arg_bits);
1584template <
typename Context,
typename... T,
size_t NUM_ARGS =
sizeof...(T)>
1585constexpr unsigned long long make_descriptor() {
1586 return NUM_ARGS <= max_packed_args ? encode_types<Context, T...>()
1587 : is_unpacked_bit | NUM_ARGS;
1591template <
typename T,
typename Char>
1592#if FMT_CLANG_VERSION && FMT_CLANG_VERSION <= 1500
1594struct type_is_unformattable_for {
1600template <
bool PACKED,
typename Context,
typename T, FMT_ENABLE_IF(PACKED)>
1602 using arg_type = remove_cvref_t<decltype(arg_mapper<Context>().map(val))>;
1606 formattable_char = !std::is_same<arg_type, unformattable_char>::value
1608 static_assert(formattable_char,
"Mixing character types is disallowed.");
1614 formattable_pointer = !std::is_same<arg_type, unformattable_pointer>::value
1616 static_assert(formattable_pointer,
1617 "Formatting of non-void pointers is disallowed.");
1619 enum { formattable = !std::is_same<arg_type, unformattable>::value };
1620#if defined(__cpp_if_constexpr)
1621 if constexpr (!formattable)
1626 "Cannot format an argument. To make type T formattable provide a "
1627 "formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
1631template <
typename Context,
typename T>
1635 arg.value_ = make_arg<true, Context>(val);
1639template <
bool PACKED,
typename Context,
typename T, FMT_ENABLE_IF(!PACKED)>
1641 return make_arg<Context>(val);
1644template <
typename Context,
size_t NUM_ARGS>
1645using arg_t = conditional_t<NUM_ARGS <= max_packed_args, value<Context>,
1648template <
typename Char,
typename T, FMT_ENABLE_IF(!is_named_arg<T>::value)>
1649void init_named_arg(named_arg_info<Char>*,
int& arg_index,
int&,
const T&) {
1652template <
typename Char,
typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
1653void init_named_arg(named_arg_info<Char>* named_args,
int& arg_index,
1654 int& named_arg_index,
const T& arg) {
1655 named_args[named_arg_index++] = {arg.name, arg_index++};
1661template <
typename Context,
size_t NUM_ARGS,
size_t NUM_NAMED_ARGS,
1662 unsigned long long DESC>
1666 static constexpr size_t ARGS_ARR_SIZE = 1 + (NUM_ARGS != 0 ? NUM_ARGS : +1);
1668 arg_t<Context, NUM_ARGS> args[ARGS_ARR_SIZE];
1671 template <
typename... T>
1673 : args{{named_args, NUM_NAMED_ARGS},
1674 make_arg<NUM_ARGS <= max_packed_args, Context>(values)...} {
1675 using dummy =
int[];
1676 int arg_index = 0, named_arg_index = 0;
1679 (init_named_arg(named_args, arg_index, named_arg_index, values), 0)...};
1683 args[0] = {named_args, NUM_NAMED_ARGS};
1684 for (
size_t i = 1; i < ARGS_ARR_SIZE; ++i) args[i] = rhs.args[i];
1685 for (
size_t i = 0; i < NUM_NAMED_ARGS; ++i)
1686 named_args[i] = rhs.named_args[i];
1696template <
typename Context,
size_t NUM_ARGS,
unsigned long long DESC>
1699 arg_t<Context, NUM_ARGS> args[NUM_ARGS != 0 ? NUM_ARGS : +1];
1712 template <
typename ContextType,
typename T>
1713 friend FMT_CONSTEXPR
auto detail::make_arg(T& value)
1719 using char_type =
typename Context::char_type;
1721 template <
typename,
size_t,
size_t,
unsigned long long>
1725 : value_(args, size) {}
1732 void format(
typename Context::parse_context_type& parse_ctx,
1733 Context& ctx)
const {
1734 custom_.format(custom_.value, parse_ctx, ctx);
1743 constexpr explicit operator bool() const noexcept {
1744 return type_ != detail::type::none_type;
1747 auto type() const -> detail::type {
return type_; }
1749 auto is_integral() const ->
bool {
return detail::is_integral_type(type_); }
1750 auto is_arithmetic() const ->
bool {
1751 return detail::is_arithmetic_type(type_);
1761 template <
typename Visitor>
1762 FMT_CONSTEXPR
auto visit(Visitor&& vis) ->
decltype(vis(0)) {
1764 case detail::type::none_type:
1766 case detail::type::int_type:
1767 return vis(value_.int_value);
1768 case detail::type::uint_type:
1769 return vis(value_.uint_value);
1770 case detail::type::long_long_type:
1771 return vis(value_.long_long_value);
1772 case detail::type::ulong_long_type:
1773 return vis(value_.ulong_long_value);
1774 case detail::type::int128_type:
1775 return vis(detail::convert_for_visit(value_.int128_value));
1776 case detail::type::uint128_type:
1777 return vis(detail::convert_for_visit(value_.uint128_value));
1778 case detail::type::bool_type:
1779 return vis(value_.bool_value);
1780 case detail::type::char_type:
1781 return vis(value_.char_value);
1782 case detail::type::float_type:
1783 return vis(value_.float_value);
1784 case detail::type::double_type:
1785 return vis(value_.double_value);
1786 case detail::type::long_double_type:
1787 return vis(value_.long_double_value);
1788 case detail::type::cstring_type:
1789 return vis(value_.string.data);
1790 case detail::type::string_type:
1792 return vis(sv(value_.string.data, value_.string.size));
1793 case detail::type::pointer_type:
1794 return vis(value_.pointer);
1795 case detail::type::custom_type:
1801 auto format_custom(
const char_type* parse_begin,
1802 typename Context::parse_context_type& parse_ctx,
1803 Context& ctx) ->
bool {
1804 if (type_ != detail::type::custom_type)
return false;
1805 parse_ctx.advance_to(parse_begin);
1806 value_.custom.format(value_.custom.value, parse_ctx, ctx);
1811template <
typename Visitor,
typename Context>
1812FMT_DEPRECATED FMT_CONSTEXPR
auto visit_format_arg(
1814 return arg.visit(
static_cast<Visitor&&
>(vis));
1829 using size_type = int;
1837 unsigned long long desc_;
1848 constexpr auto is_packed()
const ->
bool {
1849 return (desc_ & detail::is_unpacked_bit) == 0;
1851 constexpr auto has_named_args()
const ->
bool {
1852 return (desc_ & detail::has_named_args_bit) != 0;
1855 FMT_CONSTEXPR
auto type(
int index)
const -> detail::type {
1856 int shift = index * detail::packed_arg_bits;
1857 unsigned int mask = (1 << detail::packed_arg_bits) - 1;
1858 return static_cast<detail::type
>((desc_ >> shift) & mask);
1869 template <
size_t NUM_ARGS,
size_t NUM_NAMED_ARGS,
unsigned long long DESC,
1870 FMT_ENABLE_IF(NUM_ARGS <= detail::max_packed_args)>
1874 : desc_(DESC), values_(store.args + (NUM_NAMED_ARGS != 0 ? 1 : 0)) {}
1876 template <
size_t NUM_ARGS,
size_t NUM_NAMED_ARGS,
unsigned long long DESC,
1877 FMT_ENABLE_IF(NUM_ARGS > detail::max_packed_args)>
1881 : desc_(DESC), args_(store.args + (NUM_NAMED_ARGS != 0 ? 1 : 0)) {}
1890 : desc_(store.get_types()), args_(store.data()) {}
1898 : desc_(detail::is_unpacked_bit | detail::to_unsigned(count)),
1905 if (
id < max_size()) arg = args_[id];
1908 if (
static_cast<unsigned>(
id) >= detail::max_packed_args)
return arg;
1909 arg.type_ = type(
id);
1910 if (arg.type_ == detail::type::none_type)
return arg;
1911 arg.value_ = values_[id];
1915 template <
typename Char>
1917 int id = get_id(name);
1918 return id >= 0 ? get(
id) : format_arg();
1921 template <
typename Char>
1923 if (!has_named_args())
return -1;
1924 const auto& named_args =
1925 (is_packed() ? values_[-1] : args_[-1].value_).named_args;
1926 for (
size_t i = 0; i < named_args.size; ++i) {
1927 if (named_args.data[i].name == name)
return named_args.data[i].id;
1932 auto max_size() const ->
int {
1933 unsigned long long max_packed = detail::max_packed_args;
1934 return static_cast<int>(is_packed() ? max_packed
1935 : desc_ & ~detail::is_unpacked_bit);
1961 : out_(out), args_(ctx_args), loc_(loc) {}
1964 void operator=(
const context&) =
delete;
1966 FMT_CONSTEXPR
auto arg(
int id)
const -> format_arg {
return args_.
get(
id); }
1967 auto arg(
string_view name) -> format_arg {
return args_.
get(name); }
1968 FMT_CONSTEXPR
auto arg_id(
string_view name) ->
int {
1969 return args_.get_id(name);
1974 FMT_CONSTEXPR
auto out() -> iterator {
return out_; }
1977 void advance_to(iterator) {}
1985template <
typename OutputIt,
typename Char>
1986using basic_format_context =
1987 conditional_t<std::is_same<OutputIt, appender>::value,
context,
1991template <
typename Char>
1992using buffered_context = basic_format_context<basic_appender<Char>, Char>;
1994template <
typename T,
typename Char =
char>
1995using is_formattable = bool_constant<!std::is_base_of<
1997 .map(std::declval<T&>()))>::value>;
2010 size_t NUM_ARGS =
sizeof...(T),
2011 size_t NUM_NAMED_ARGS = detail::count_named_args<T...>(),
2012 unsigned long long DESC = detail::make_descriptor<Context, T...>(),
2013 FMT_ENABLE_IF(NUM_NAMED_ARGS == 0)>
2014constexpr FMT_ALWAYS_INLINE
auto make_format_args(T&... args)
2016 return {{detail::make_arg<NUM_ARGS <= detail::max_packed_args, Context>(
2022 size_t NUM_NAMED_ARGS = detail::count_named_args<T...>(),
2023 unsigned long long DESC =
2024 detail::make_descriptor<Context, T...>() |
2025 static_cast<unsigned long long>(detail::has_named_args_bit),
2026 FMT_ENABLE_IF(NUM_NAMED_ARGS != 0)>
2027constexpr auto make_format_args(T&... args)
2044template <
typename Char,
typename T>
2060#if FMT_GCC_VERSION && FMT_GCC_VERSION < 903
2061# define FMT_ENUM_UNDERLYING_TYPE(type)
2063# define FMT_ENUM_UNDERLYING_TYPE(type) : type
2066enum type FMT_ENUM_UNDERLYING_TYPE(
unsigned char){none, left, right, center,
2069using align_t = align::type;
2071enum type FMT_ENUM_UNDERLYING_TYPE(
unsigned char){none, minus, plus, space};
2073using sign_t = sign::type;
2077template <
typename Char>
2078using unsigned_char =
typename conditional_t<std::is_integral<Char>::value,
2079 std::make_unsigned<Char>,
2085 enum { max_size = 4 };
2086 char data_[max_size] = {
' '};
2087 unsigned char size_ = 1;
2090 template <
typename Char>
2092 auto size = s.size();
2093 size_ =
static_cast<unsigned char>(size);
2095 unsigned uchar =
static_cast<unsigned_char<Char>
>(s[0]);
2096 data_[0] =
static_cast<char>(uchar);
2097 data_[1] =
static_cast<char>(uchar >> 8);
2100 FMT_ASSERT(size <= max_size,
"invalid fill");
2101 for (
size_t i = 0; i < size; ++i) data_[i] = static_cast<char>(s[i]);
2104 FMT_CONSTEXPR
void operator=(
char c) {
2109 constexpr auto size()
const ->
size_t {
return size_; }
2111 template <
typename Char>
constexpr auto get()
const -> Char {
2112 using uchar =
unsigned char;
2113 return static_cast<Char
>(
static_cast<uchar
>(data_[0]) |
2114 (
static_cast<uchar
>(data_[1]) << 8));
2117 template <
typename Char, FMT_ENABLE_IF(std::is_same<Char,
char>::value)>
2118 constexpr auto data()
const ->
const Char* {
2121 template <
typename Char, FMT_ENABLE_IF(!std::is_same<Char,
char>::value)>
2122 constexpr auto data()
const ->
const Char* {
2128enum class presentation_type :
unsigned char {
2155 presentation_type type;
2166 type(presentation_type::none),
2176enum class arg_id_kind { none, index, name };
2180 FMT_CONSTEXPR
arg_ref() : kind(arg_id_kind::none), val() {}
2182 FMT_CONSTEXPR
explicit arg_ref(
int index)
2183 : kind(arg_id_kind::index), val(index) {}
2185 : kind(arg_id_kind::name), val(name) {}
2187 FMT_CONSTEXPR
auto operator=(
int idx) ->
arg_ref& {
2188 kind = arg_id_kind::index;
2195 FMT_CONSTEXPR
value(
int idx = 0) : index(idx) {}
2212template <
typename Char, FMT_ENABLE_IF(std::is_
integral<Char>::value)>
2213constexpr auto to_ascii(Char c) ->
char {
2214 return c <= 0xff ? static_cast<char>(c) :
'\0';
2218template <
typename Char>
2219FMT_CONSTEXPR
auto code_point_length(
const Char* begin) ->
int {
2220 if (const_check(
sizeof(Char) != 1))
return 1;
2221 auto c =
static_cast<unsigned char>(*begin);
2222 return static_cast<int>((0x3a55000000000000ull >> (2 * (c >> 3))) & 0x3) + 1;
2226template <
bool IS_CONSTEXPR,
typename T,
typename Ptr = const T*>
2227FMT_CONSTEXPR
auto find(Ptr first, Ptr last, T value, Ptr& out) ->
bool {
2228 for (out = first; out != last; ++out) {
2229 if (*out == value)
return true;
2235inline auto find<false, char>(
const char* first,
const char* last,
char value,
2236 const char*& out) ->
bool {
2238 static_cast<const char*
>(memchr(first, value, to_unsigned(last - first)));
2239 return out !=
nullptr;
2244template <
typename Char>
2245FMT_CONSTEXPR
auto parse_nonnegative_int(
const Char*& begin,
const Char* end,
2246 int error_value)
noexcept ->
int {
2247 FMT_ASSERT(begin != end &&
'0' <= *begin && *begin <=
'9',
"");
2248 unsigned value = 0, prev = 0;
2252 value = value * 10 + unsigned(*p -
'0');
2254 }
while (p != end &&
'0' <= *p && *p <=
'9');
2255 auto num_digits = p - begin;
2257 int digits10 =
static_cast<int>(
sizeof(int) * CHAR_BIT * 3 / 10);
2258 if (num_digits <= digits10)
return static_cast<int>(value);
2260 unsigned max = INT_MAX;
2261 return num_digits == digits10 + 1 &&
2262 prev * 10ull + unsigned(p[-1] -
'0') <= max
2263 ?
static_cast<int>(value)
2267FMT_CONSTEXPR
inline auto parse_align(
char c) -> align_t {
2272 return align::right;
2274 return align::center;
2279template <
typename Char>
constexpr auto is_name_start(Char c) ->
bool {
2280 return (
'a' <= c && c <=
'z') || (
'A' <= c && c <=
'Z') || c ==
'_';
2283template <
typename Char,
typename Handler>
2284FMT_CONSTEXPR
auto do_parse_arg_id(
const Char* begin,
const Char* end,
2285 Handler&& handler) ->
const Char* {
2287 if (c >=
'0' && c <=
'9') {
2290 index = parse_nonnegative_int(begin, end, INT_MAX);
2293 if (begin == end || (*begin !=
'}' && *begin !=
':'))
2294 report_error(
"invalid format string");
2296 handler.on_index(index);
2299 if (!is_name_start(c)) {
2300 report_error(
"invalid format string");
2306 }
while (it != end && (is_name_start(*it) || (
'0' <= *it && *it <=
'9')));
2307 handler.on_name({begin, to_unsigned(it - begin)});
2311template <
typename Char,
typename Handler>
2312FMT_CONSTEXPR
auto parse_arg_id(
const Char* begin,
const Char* end,
2313 Handler&& handler) ->
const Char* {
2314 FMT_ASSERT(begin != end,
"");
2316 if (c !=
'}' && c !=
':')
return do_parse_arg_id(begin, end, handler);
2325 FMT_CONSTEXPR
void on_auto() {
2328 ctx.check_dynamic_spec(
id);
2330 FMT_CONSTEXPR
void on_index(
int id) {
2333 ctx.check_dynamic_spec(
id);
2342template <
typename Char>
2343FMT_CONSTEXPR
auto parse_dynamic_spec(
const Char* begin,
const Char* end,
2347 FMT_ASSERT(begin != end,
"");
2348 if (
'0' <= *begin && *begin <=
'9') {
2349 int val = parse_nonnegative_int(begin, end, -1);
2353 report_error(
"number is too big");
2354 }
else if (*begin ==
'{') {
2356 auto handler = dynamic_spec_id_handler<Char>{ctx, ref};
2357 if (begin != end) begin = parse_arg_id(begin, end, handler);
2358 if (begin != end && *begin ==
'}')
return ++begin;
2359 report_error(
"invalid format string");
2364template <
typename Char>
2365FMT_CONSTEXPR
auto parse_precision(
const Char* begin,
const Char* end,
2366 int& value, arg_ref<Char>& ref,
2370 if (begin == end || *begin ==
'}') {
2371 report_error(
"invalid precision");
2374 return parse_dynamic_spec(begin, end, value, ref, ctx);
2377enum class state { start, align, sign, hash,
zero, width, precision, locale };
2380template <
typename Char>
2381FMT_CONSTEXPR
auto parse_format_specs(
const Char* begin,
const Char* end,
2382 dynamic_format_specs<Char>& specs,
2384 type arg_type) ->
const Char* {
2386 if (end - begin > 1) {
2387 auto next = to_ascii(begin[1]);
2388 c = parse_align(next) == align::none ? to_ascii(*begin) :
'\0';
2390 if (begin == end)
return begin;
2391 c = to_ascii(*begin);
2395 state current_state = state::start;
2396 FMT_CONSTEXPR
void operator()(state s,
bool valid =
true) {
2397 if (current_state >= s || !valid)
2398 report_error(
"invalid format specifier");
2403 using pres = presentation_type;
2404 constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
2407 dynamic_format_specs<Char>& specs;
2410 FMT_CONSTEXPR
auto operator()(pres pres_type,
int set) ->
const Char* {
2411 if (!in(arg_type, set)) {
2412 if (arg_type == type::none_type)
return begin;
2413 report_error(
"invalid format specifier");
2415 specs.type = pres_type;
2418 } parse_presentation_type{begin, specs, arg_type};
2425 enter_state(state::align);
2426 specs.align = parse_align(c);
2432 if (arg_type == type::none_type)
return begin;
2433 enter_state(state::sign, in(arg_type, sint_set | float_set));
2436 specs.sign = sign::plus;
2439 specs.sign = sign::minus;
2442 specs.sign = sign::space;
2448 if (arg_type == type::none_type)
return begin;
2449 enter_state(state::hash, is_arithmetic_type(arg_type));
2454 enter_state(state::zero);
2455 if (!is_arithmetic_type(arg_type)) {
2456 if (arg_type == type::none_type)
return begin;
2457 report_error(
"format specifier requires numeric argument");
2459 if (specs.align == align::none) {
2461 specs.align = align::numeric;
2476 enter_state(state::width);
2477 begin = parse_dynamic_spec(begin, end, specs.width, specs.width_ref, ctx);
2480 if (arg_type == type::none_type)
return begin;
2481 enter_state(state::precision,
2482 in(arg_type, float_set | string_set | cstring_set));
2483 begin = parse_precision(begin, end, specs.precision, specs.precision_ref,
2487 if (arg_type == type::none_type)
return begin;
2488 enter_state(state::locale, is_arithmetic_type(arg_type));
2489 specs.localized =
true;
2493 return parse_presentation_type(pres::dec, integral_set);
2498 return parse_presentation_type(pres::hex, integral_set);
2500 return parse_presentation_type(pres::oct, integral_set);
2505 return parse_presentation_type(pres::bin, integral_set);
2510 return parse_presentation_type(pres::exp, float_set);
2515 return parse_presentation_type(pres::fixed, float_set);
2520 return parse_presentation_type(pres::general, float_set);
2525 return parse_presentation_type(pres::hexfloat, float_set);
2527 if (arg_type == type::bool_type) report_error(
"invalid format specifier");
2528 return parse_presentation_type(pres::chr, integral_set);
2530 return parse_presentation_type(pres::string,
2531 bool_set | string_set | cstring_set);
2533 return parse_presentation_type(pres::pointer, pointer_set | cstring_set);
2535 return parse_presentation_type(pres::debug,
2536 char_set | string_set | cstring_set);
2540 if (*begin ==
'}')
return begin;
2542 auto fill_end = begin + code_point_length(begin);
2543 if (end - fill_end <= 0) {
2544 report_error(
"invalid format specifier");
2547 if (*begin ==
'{') {
2548 report_error(
"invalid fill character '{'");
2551 auto align = parse_align(to_ascii(*fill_end));
2552 enter_state(state::align, align != align::none);
2555 specs.align = align;
2556 begin = fill_end + 1;
2559 if (begin == end)
return begin;
2560 c = to_ascii(*begin);
2564template <
typename Char,
typename Handler>
2565FMT_CONSTEXPR
auto parse_replacement_field(
const Char* begin,
const Char* end,
2566 Handler&& handler) ->
const Char* {
2571 FMT_CONSTEXPR
void on_auto() { arg_id = handler.on_arg_id(); }
2572 FMT_CONSTEXPR
void on_index(
int id) { arg_id = handler.on_arg_id(
id); }
2574 arg_id = handler.on_arg_id(
id);
2579 if (begin == end)
return handler.on_error(
"invalid format string"), end;
2580 if (*begin ==
'}') {
2581 handler.on_replacement_field(handler.on_arg_id(), begin);
2582 }
else if (*begin ==
'{') {
2583 handler.on_text(begin, begin + 1);
2585 auto adapter = id_adapter{handler, 0};
2586 begin = parse_arg_id(begin, end, adapter);
2587 Char c = begin != end ? *begin : Char();
2589 handler.on_replacement_field(adapter.arg_id, begin);
2590 }
else if (c ==
':') {
2591 begin = handler.on_format_specs(adapter.arg_id, begin + 1, end);
2592 if (begin == end || *begin !=
'}')
2593 return handler.on_error(
"unknown format specifier"), end;
2595 return handler.on_error(
"missing '}' in format string"), end;
2601template <
bool IS_CONSTEXPR,
typename Char,
typename Handler>
2603 Handler&& handler) {
2604 auto begin = format_str.
data();
2605 auto end = begin + format_str.
size();
2606 if (end - begin < 32) {
2608 const Char* p = begin;
2612 handler.on_text(begin, p - 1);
2613 begin = p = parse_replacement_field(p - 1, end, handler);
2614 }
else if (c ==
'}') {
2615 if (p == end || *p !=
'}')
2616 return handler.on_error(
"unmatched '}' in format string");
2617 handler.on_text(begin, p);
2621 handler.on_text(begin, end);
2625 FMT_CONSTEXPR
void operator()(
const Char* from,
const Char* to) {
2626 if (from == to)
return;
2628 const Char* p =
nullptr;
2629 if (!find<IS_CONSTEXPR>(from, to, Char(
'}'), p))
2630 return handler_.on_text(from, to);
2632 if (p == to || *p !=
'}')
2633 return handler_.on_error(
"unmatched '}' in format string");
2634 handler_.on_text(from, p);
2639 } write = {handler};
2640 while (begin != end) {
2643 const Char* p = begin;
2644 if (*begin !=
'{' && !find<IS_CONSTEXPR>(begin + 1, end, Char(
'{'), p))
2645 return write(begin, end);
2647 begin = parse_replacement_field(p, end, handler);
2655 using type = remove_cvref_t<
decltype(T::value)>;
2658template <
typename T,
typename ParseContext>
2659FMT_VISIBILITY(
"hidden")
2660FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx)
2661 -> decltype(ctx.begin()) {
2662 using char_type =
typename ParseContext::char_type;
2663 using context = buffered_context<char_type>;
2664 using mapped_type = conditional_t<
2667 typename strip_named_arg<T>::type>;
2668#if defined(__cpp_if_constexpr)
2669 if constexpr (std::is_default_constructible<
2673 type_is_unformattable_for<T, char_type> _;
2682FMT_CONSTEXPR
inline auto check_char_specs(
const format_specs& specs) ->
bool {
2683 if (specs.type != presentation_type::none &&
2684 specs.type != presentation_type::chr &&
2685 specs.type != presentation_type::debug) {
2688 if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
2689 report_error(
"invalid format specifier for char");
2693#if FMT_USE_NONTYPE_TEMPLATE_ARGS
2694template <
int N,
typename T,
typename... Args,
typename Char>
2696 if constexpr (is_statically_named_arg<T>()) {
2697 if (name == T::name)
return N;
2699 if constexpr (
sizeof...(Args) > 0)
2700 return get_arg_index_by_name<N + 1, Args...>(name);
2706template <
typename... Args,
typename Char>
2708#if FMT_USE_NONTYPE_TEMPLATE_ARGS
2709 if constexpr (
sizeof...(Args) > 0)
2710 return get_arg_index_by_name<0, Args...>(name);
2719 static constexpr int num_args =
sizeof...(Args);
2727 type types_[num_args > 0 ?
static_cast<size_t>(num_args) : 1];
2729 parse_func parse_funcs_[num_args > 0 ?
static_cast<size_t>(num_args) : 1];
2734 context_(fmt, num_args, types_),
2735 parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}
2737 FMT_CONSTEXPR
void on_text(
const Char*,
const Char*) {}
2739 FMT_CONSTEXPR
auto on_arg_id() ->
int {
return context_.next_arg_id(); }
2740 FMT_CONSTEXPR
auto on_arg_id(
int id) ->
int {
2741 return context_.check_arg_id(
id), id;
2744#if FMT_USE_NONTYPE_TEMPLATE_ARGS
2745 auto index = get_arg_index_by_name<Args...>(id);
2746 if (index < 0) on_error(
"named argument is not found");
2750 on_error(
"compile-time checks for named arguments require C++20 support");
2755 FMT_CONSTEXPR
void on_replacement_field(
int id,
const Char* begin) {
2756 on_format_specs(
id, begin, begin);
2759 FMT_CONSTEXPR
auto on_format_specs(
int id,
const Char* begin,
const Char*)
2763 return id >= 0 &&
id < num_args ? parse_funcs_[id](context_) : begin;
2766 FMT_NORETURN FMT_CONSTEXPR
void on_error(
const char* message) {
2767 report_error(message);
2774template <
typename S>
2775using is_compile_string = std::is_base_of<compile_string, S>;
2778template <
typename...,
typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
2779FMT_ALWAYS_INLINE
void check_format_string(
const S&) {
2780#ifdef FMT_ENFORCE_COMPILE_STRING
2781 static_assert(is_compile_string<S>::value,
2782 "FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
2786template <
typename... Args,
typename S,
2787 FMT_ENABLE_IF(is_compile_string<S>::value)>
2788void check_format_string(S format_str) {
2789 using char_t =
typename S::char_type;
2791 using checker = format_string_checker<char_t, remove_cvref_t<Args>...>;
2792 FMT_CONSTEXPR
bool error = (parse_format_string<true>(s, checker(s)),
true);
2793 ignore_unused(error);
2805template <
typename Char>
2819 using nonlocking = void;
2821 template <
typename ParseContext>
2822 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
const Char* {
2823 if (ctx.begin() == ctx.end() || *ctx.begin() ==
'}')
return ctx.begin();
2824 auto end = parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, TYPE);
2825 if (const_check(TYPE == type::char_type)) check_char_specs(specs_);
2829 template <type U = TYPE,
2830 FMT_ENABLE_IF(U == type::string_type || U == type::cstring_type ||
2831 U == type::char_type)>
2832 FMT_CONSTEXPR
void set_debug_format(
bool set =
true) {
2833 specs_.type = set ? presentation_type::debug : presentation_type::none;
2836 template <
typename FormatContext>
2837 FMT_CONSTEXPR
auto format(
const T& val, FormatContext& ctx)
const
2838 ->
decltype(ctx.out());
2845template <
typename T,
typename Char>
2847 enable_if_t<detail::type_constant<T, Char>::value !=
2848 detail::type::custom_type>>
2866 (detail::is_compile_string<S>::value &&
2871 (std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
2872 std::is_reference<Args>::value)...>() == 0,
2873 "passing views as lvalues is disallowed");
2874#if FMT_USE_CONSTEVAL
2875 if constexpr (detail::count_named_args<Args...>() ==
2876 detail::count_statically_named_args<Args...>()) {
2879 detail::parse_format_string<true>(str_, checker(s));
2882 detail::check_format_string<Args...>(s);
2891#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
2896template <
typename... Args>
2912template <
typename OutputIt,
2916 -> remove_cvref_t<OutputIt> {
2917 auto&& buf = detail::get_buffer<char>(out);
2918 detail::vformat_to(buf, fmt, args, {});
2919 return detail::get_iterator(buf, out);
2934template <
typename OutputIt,
typename... T,
2938 -> remove_cvref_t<OutputIt> {
2939 return vformat_to(FMT_FWD(out), fmt, fmt::make_format_args(args...));
2949template <
typename OutputIt,
typename... T,
2955 detail::vformat_to(buf, fmt, args, {});
2956 return {buf.out(), buf.count()};
2967template <
typename OutputIt,
typename... T,
2971 return vformat_to_n(out, n, fmt, fmt::make_format_args(args...));
2974template <
typename OutputIt,
typename Sentinel = OutputIt>
2981 FMT_CONSTEXPR
operator OutputIt&() &
noexcept {
return out; }
2982 FMT_CONSTEXPR
operator const OutputIt&()
const&
noexcept {
return out; }
2983 FMT_CONSTEXPR
operator OutputIt&&() &&
noexcept {
2984 return static_cast<OutputIt&&
>(
out);
2991 auto result = vformat_to_n(out, N, fmt, args);
2992 return {result.out, result.size > N};
2995template <
size_t N,
typename... T>
2998 auto result = fmt::format_to_n(out, N, fmt,
static_cast<T&&
>(args)...);
2999 return {result.out, result.size > N};
3003template <
typename... T>
3005 T&&... args) ->
size_t {
3007 detail::vformat_to<char>(buf, fmt, fmt::make_format_args(args...), {});
3026template <
typename... T>
3028 const auto& vargs = fmt::make_format_args(args...);
3029 if (!detail::use_utf8())
return detail::vprint_mojibake(stdout, fmt, vargs);
3030 return detail::is_locking<T...>() ? vprint_buffered(stdout, fmt, vargs)
3031 : vprint(fmt, vargs);
3044template <
typename... T>
3046 const auto& vargs = fmt::make_format_args(args...);
3047 if (!detail::use_utf8())
return detail::vprint_mojibake(f, fmt, vargs);
3048 return detail::is_locking<T...>() ? vprint_buffered(f, fmt, vargs)
3049 : vprint(f, fmt, vargs);
3056template <
typename... T>
3058 const auto& vargs = fmt::make_format_args(args...);
3059 return detail::use_utf8() ? vprintln(f, fmt, vargs)
3060 : detail::vprint_mojibake(f, fmt, vargs, true);
3067template <
typename... T>
3069 return fmt::println(stdout, fmt,
static_cast<T&&
>(args)...);
3073FMT_GCC_PRAGMA(
"GCC pop_options")
3076#ifdef FMT_HEADER_ONLY
FMT_CONSTEXPR auto next_arg_id() -> int
Definition base.h:764
constexpr auto end() const noexcept -> iterator
Definition base.h:753
FMT_CONSTEXPR void check_arg_id(int id)
Definition base.h:778
FMT_CONSTEXPR void advance_to(iterator it)
Definition base.h:756
constexpr auto begin() const noexcept -> iterator
Definition base.h:746
constexpr auto size() const noexcept -> size_t
Definition base.h:526
FMT_CONSTEXPR basic_string_view(const S &s) noexcept
Definition base.h:519
constexpr auto data() const noexcept -> const Char *
Definition base.h:523
constexpr basic_string_view(const Char *s, size_t count) noexcept
Definition base.h:496
FMT_CONSTEXPR20 basic_string_view(const Char *s)
Definition base.h:505
char char_type
Definition base.h:1948
FMT_CONSTEXPR context(iterator out, basic_format_args< context > ctx_args, detail::locale_ref loc={})
Definition base.h:1959
void append(const U *begin, const U *end)
Definition base.h:913
FMT_CONSTEXPR void set(T *buf_data, size_t buf_capacity) noexcept
Definition base.h:861
void clear()
Definition base.h:890
constexpr auto size() const noexcept -> size_t
Definition base.h:880
constexpr auto capacity() const noexcept -> size_t
Definition base.h:883
FMT_CONSTEXPR auto data() noexcept -> T *
Definition base.h:886
GLM_FUNC_DECL GLM_CONSTEXPR genType zero()
Definition constants.inl:6