11 #if defined(FMT_IMPORT_STD) && !defined(FMT_MODULE) 20 # include <type_traits> 24 #define FMT_VERSION 120000 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 56 #ifdef _LIBCPP_VERSION 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 80 # define FMT_HAS_BUILTIN(x) __has_builtin(x) 82 # define FMT_HAS_BUILTIN(x) 0 84 #ifdef __has_cpp_attribute 85 # define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) 87 # define FMT_HAS_CPP_ATTRIBUTE(x) 0 90 #define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ 91 (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) 93 #define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ 94 (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) 97 #ifdef FMT_USE_CONSTEXPR 99 #elif FMT_GCC_VERSION >= 702 && FMT_CPLUSPLUS >= 201402L 102 # define FMT_USE_CONSTEXPR 1 103 #elif FMT_ICC_VERSION 104 # define FMT_USE_CONSTEXPR 0 // https://github.com/fmtlib/fmt/issues/1628 105 #elif FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912 106 # define FMT_USE_CONSTEXPR 1 108 # define FMT_USE_CONSTEXPR 0 110 #if FMT_USE_CONSTEXPR 111 # define FMT_CONSTEXPR constexpr 113 # define FMT_CONSTEXPR 117 #if !defined(__cpp_lib_is_constant_evaluated) 118 # define FMT_USE_CONSTEVAL 0 119 #elif FMT_CPLUSPLUS < 201709L 120 # define FMT_USE_CONSTEVAL 0 121 #elif FMT_GLIBCXX_RELEASE && FMT_GLIBCXX_RELEASE < 10 122 # define FMT_USE_CONSTEVAL 0 123 #elif FMT_LIBCPP_VERSION && FMT_LIBCPP_VERSION < 10000 124 # define FMT_USE_CONSTEVAL 0 125 #elif defined(__apple_build_version__) && __apple_build_version__ < 14000029L 126 # define FMT_USE_CONSTEVAL 0 // consteval is broken in Apple clang < 14. 127 #elif FMT_MSC_VERSION && FMT_MSC_VERSION < 1929 128 # define FMT_USE_CONSTEVAL 0 // consteval is broken in MSVC VS2019 < 16.10. 129 #elif defined(__cpp_consteval) 130 # define FMT_USE_CONSTEVAL 1 131 #elif FMT_GCC_VERSION >= 1002 || FMT_CLANG_VERSION >= 1101 132 # define FMT_USE_CONSTEVAL 1 134 # define FMT_USE_CONSTEVAL 0 136 #if FMT_USE_CONSTEVAL 137 # define FMT_CONSTEVAL consteval 138 # define FMT_CONSTEXPR20 constexpr 140 # define FMT_CONSTEVAL 141 # define FMT_CONSTEXPR20 145 #ifdef FMT_USE_EXCEPTIONS 147 #elif defined(__GNUC__) && !defined(__EXCEPTIONS) 148 # define FMT_USE_EXCEPTIONS 0 149 #elif defined(__clang__) && !defined(__cpp_exceptions) 150 # define FMT_USE_EXCEPTIONS 0 151 #elif FMT_MSC_VERSION && !_HAS_EXCEPTIONS 152 # define FMT_USE_EXCEPTIONS 0 154 # define FMT_USE_EXCEPTIONS 1 156 #if FMT_USE_EXCEPTIONS 158 # define FMT_CATCH(x) catch (x) 160 # define FMT_TRY if (true) 161 # define FMT_CATCH(x) if (false) 164 #ifdef FMT_NO_UNIQUE_ADDRESS 166 #elif FMT_CPLUSPLUS < 202002L 168 #elif FMT_HAS_CPP_ATTRIBUTE(no_unique_address) 169 # define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]] 171 #elif FMT_MSC_VERSION >= 1929 && !FMT_CLANG_VERSION 172 # define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] 174 #ifndef FMT_NO_UNIQUE_ADDRESS 175 # define FMT_NO_UNIQUE_ADDRESS 178 #if FMT_HAS_CPP17_ATTRIBUTE(fallthrough) 179 # define FMT_FALLTHROUGH [[fallthrough]] 180 #elif defined(__clang__) 181 # define FMT_FALLTHROUGH [[clang::fallthrough]] 182 #elif FMT_GCC_VERSION >= 700 && \ 183 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) 184 # define FMT_FALLTHROUGH [[gnu::fallthrough]] 186 # define FMT_FALLTHROUGH 190 #if FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && !defined(__NVCC__) 191 # define FMT_NORETURN [[noreturn]] 193 # define FMT_NORETURN 198 #elif FMT_HAS_CPP17_ATTRIBUTE(nodiscard) 199 # define FMT_NODISCARD [[nodiscard]] 201 # define FMT_NODISCARD 204 #if FMT_GCC_VERSION || FMT_CLANG_VERSION 205 # define FMT_VISIBILITY(value) __attribute__((visibility(value))) 207 # define FMT_VISIBILITY(value) 211 #define FMT_PRAGMA_IMPL(x) _Pragma(#x) 212 #if FMT_GCC_VERSION >= 504 && !defined(__NVCOMPILER) 215 # define FMT_PRAGMA_GCC(x) FMT_PRAGMA_IMPL(GCC x) 217 # define FMT_PRAGMA_GCC(x) 219 #if FMT_CLANG_VERSION 220 # define FMT_PRAGMA_CLANG(x) FMT_PRAGMA_IMPL(clang x) 222 # define FMT_PRAGMA_CLANG(x) 225 # define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) 227 # define FMT_MSC_WARNING(...) 231 FMT_PRAGMA_GCC(push_options)
232 #if !defined(__OPTIMIZE__) && !defined(__CUDACC__) && !defined(FMT_MODULE) 233 FMT_PRAGMA_GCC(optimize(
"Og"))
234 # define FMT_GCC_OPTIMIZED 236 FMT_PRAGMA_CLANG(diagnostic push)
238 #ifdef FMT_ALWAYS_INLINE 240 #elif FMT_GCC_VERSION || FMT_CLANG_VERSION 241 # define FMT_ALWAYS_INLINE inline __attribute__((always_inline)) 243 # define FMT_ALWAYS_INLINE inline 246 #if defined(NDEBUG) || defined(FMT_GCC_OPTIMIZED) 247 # define FMT_INLINE FMT_ALWAYS_INLINE 249 # define FMT_INLINE inline 252 #ifndef FMT_BEGIN_NAMESPACE 253 # define FMT_BEGIN_NAMESPACE \ 255 inline namespace v12 { 256 # define FMT_END_NAMESPACE \ 263 # define FMT_BEGIN_EXPORT 264 # define FMT_END_EXPORT 273 #if !defined(FMT_HEADER_ONLY) && FMT_WIN32 274 # if defined(FMT_LIB_EXPORT) 275 # define FMT_API __declspec(dllexport) 276 # elif defined(FMT_SHARED) 277 # define FMT_API __declspec(dllimport) 279 #elif defined(FMT_LIB_EXPORT) || defined(FMT_SHARED) 280 # define FMT_API FMT_VISIBILITY("default") 286 #ifndef FMT_OPTIMIZE_SIZE 287 # define FMT_OPTIMIZE_SIZE 0 292 #ifndef FMT_BUILTIN_TYPES 293 # define FMT_BUILTIN_TYPES 1 296 #define FMT_APPLY_VARIADIC(expr) \ 297 using unused = int[]; \ 298 (void)unused { 0, (expr, 0)... } 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>
315 using make_unsigned_t =
typename std::make_unsigned<T>::type;
316 template <
typename T>
317 using underlying_t =
typename std::underlying_type<T>::type;
318 template <
typename T>
using decay_t =
typename std::decay<T>::type;
319 using nullptr_t = decltype(
nullptr);
321 #if (FMT_GCC_VERSION && FMT_GCC_VERSION < 500) || FMT_MSC_VERSION 323 template <
typename...>
struct void_t_impl {
326 template <
typename... T>
using void_t =
typename void_t_impl<T...>::type;
328 template <
typename...>
using void_t = void;
332 constexpr monostate() {}
339 # define FMT_ENABLE_IF(...) 341 # define FMT_ENABLE_IF(...) fmt::enable_if_t<(__VA_ARGS__), int> = 0 344 template <
typename T> constexpr
auto min_of(T a, T b) -> T {
345 return a < b ? a : b;
347 template <
typename T> constexpr
auto max_of(T a, T b) -> T {
348 return a > b ? a : b;
351 FMT_NORETURN FMT_API
void assert_fail(
const char* file,
int line,
352 const char* message);
358 template <
typename... T> FMT_CONSTEXPR
void ignore_unused(
const T&...) {}
360 constexpr
auto is_constant_evaluated(
bool default_value =
false) noexcept
364 #if FMT_CPLUSPLUS >= 202002L && FMT_GLIBCXX_RELEASE >= 12 && \ 365 (FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500) 366 ignore_unused(default_value);
367 return __builtin_is_constant_evaluated();
368 #elif defined(__cpp_lib_is_constant_evaluated) 369 ignore_unused(default_value);
370 return std::is_constant_evaluated();
372 return default_value;
377 template <
typename T> FMT_ALWAYS_INLINE constexpr
auto const_check(T val) -> T {
381 FMT_NORETURN FMT_API
void assert_fail(
const char* file,
int line,
382 const char* message);
384 #if defined(FMT_ASSERT) 386 #elif defined(NDEBUG) 388 # define FMT_ASSERT(condition, message) \ 389 fmt::detail::ignore_unused((condition), (message)) 391 # define FMT_ASSERT(condition, message) \ 394 : ::fmt::assert_fail(__FILE__, __LINE__, (message))) 397 #ifdef FMT_USE_INT128 399 #elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \ 400 !(FMT_CLANG_VERSION && FMT_MSC_VERSION) 401 # define FMT_USE_INT128 1 402 using int128_opt = __int128_t;
403 using uint128_opt = __uint128_t;
404 inline auto map(int128_opt x) -> int128_opt {
return x; }
405 inline auto map(uint128_opt x) -> uint128_opt {
return x; }
407 # define FMT_USE_INT128 0 410 enum class int128_opt {};
411 enum class uint128_opt {};
413 inline auto map(int128_opt) -> monostate {
return {}; }
414 inline auto map(uint128_opt) -> monostate {
return {}; }
417 #ifndef FMT_USE_BITINT 418 # define FMT_USE_BITINT (FMT_CLANG_VERSION >= 1500) 422 FMT_PRAGMA_CLANG(diagnostic ignored
"-Wbit-int-extension")
423 template <
int N>
using bitint = _BitInt(N);
424 template <
int N>
using ubitint =
unsigned _BitInt(N);
426 template <
int N>
struct bitint {};
427 template <
int N>
struct ubitint {};
428 #endif // FMT_USE_BITINT 431 template <
typename Int>
432 FMT_CONSTEXPR
auto to_unsigned(Int value) -> make_unsigned_t<Int> {
433 FMT_ASSERT(std::is_unsigned<Int>::value || value >= 0,
"negative value");
434 return static_cast<make_unsigned_t<Int>
>(value);
437 template <
typename Char>
438 using unsigned_char = conditional_t<sizeof(Char) == 1, unsigned char, unsigned>;
442 template <
typename T,
typename Enable =
void>
443 struct is_std_string_like : std::false_type {};
444 template <
typename T>
445 struct is_std_string_like<T, void_t<decltype(
std::declval<T>().find_first_of(
446 typename T::value_type(), 0))>>
447 : std::is_convertible<decltype(std::declval<T>().data()),
448 const typename T::value_type*> {};
451 enum { is_utf8_enabled =
"\u00A7"[1] ==
'\xA7' };
452 enum { use_utf8 = !FMT_WIN32 || is_utf8_enabled };
455 # define FMT_UNICODE 1 458 static_assert(!FMT_UNICODE || use_utf8,
459 "Unicode support requires compiling with /utf-8");
461 template <
typename T> constexpr
auto narrow(T*) ->
char* {
return nullptr; }
462 constexpr FMT_ALWAYS_INLINE
auto narrow(
const char* s) ->
const char* {
466 template <
typename Char>
467 FMT_CONSTEXPR
auto compare(
const Char* s1,
const Char* s2,
size_t n) ->
int {
468 if (!is_constant_evaluated() &&
sizeof(Char) == 1)
return memcmp(s1, s2, n);
469 for (; n != 0; ++s1, ++s2, --n) {
470 if (*s1 < *s2)
return -1;
471 if (*s1 > *s2)
return 1;
479 template <
typename Container>
480 auto invoke_back_inserter()
481 -> decltype(back_inserter(std::declval<Container&>()));
484 template <
typename It,
typename Enable = std::true_type>
485 struct is_back_insert_iterator : std::false_type {};
487 template <
typename It>
488 struct is_back_insert_iterator<
489 It, bool_constant<
std::is_same<
490 decltype(adl::invoke_back_inserter<typename It::container_type>()),
491 It>::value>> : std::true_type {};
494 template <
typename OutputIt>
495 inline FMT_CONSTEXPR20
auto get_container(OutputIt it) ->
496 typename OutputIt::container_type& {
497 struct accessor : OutputIt {
498 FMT_CONSTEXPR20 accessor(OutputIt base) : OutputIt(base) {}
499 using OutputIt::container;
501 return *accessor(it).container;
521 using value_type = Char;
522 using iterator =
const Char*;
528 : data_(s), size_(count) {}
537 #if FMT_HAS_BUILTIN(__builtin_strlen) || FMT_GCC_VERSION || FMT_CLANG_VERSION 538 if (std::is_same<Char, char>::value && !detail::is_constant_evaluated()) {
539 size_ = __builtin_strlen(detail::narrow(s));
550 template <
typename S,
551 FMT_ENABLE_IF(detail::is_std_string_like<S>::value&& std::is_same<
552 typename S::value_type, Char>::value)>
554 : data_(s.data()), size_(s.size()) {}
557 constexpr
auto data() const noexcept -> const Char* {
return data_; }
560 constexpr
auto size() const noexcept ->
size_t {
return size_; }
562 constexpr
auto begin()
const noexcept -> iterator {
return data_; }
563 constexpr
auto end()
const noexcept -> iterator {
return data_ + size_; }
565 constexpr
auto operator[](
size_t pos)
const noexcept ->
const Char& {
569 FMT_CONSTEXPR
void remove_prefix(
size_t n) noexcept {
576 return size_ >= sv.size_ && detail::compare(data_, sv.data_, sv.size_) == 0;
578 FMT_CONSTEXPR
auto starts_with(Char c)
const noexcept ->
bool {
579 return size_ >= 1 && *data_ == c;
581 FMT_CONSTEXPR
auto starts_with(
const Char* s)
const ->
bool {
587 detail::compare(data_, other.data_, min_of(size_, other.size_));
588 if (result != 0)
return result;
589 return size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
594 return lhs.compare(rhs) == 0;
597 return lhs.compare(rhs) != 0;
600 return lhs.compare(rhs) < 0;
603 return lhs.compare(rhs) <= 0;
606 return lhs.compare(rhs) > 0;
609 return lhs.compare(rhs) >= 0;
615 template <
typename T>
class basic_appender;
616 using appender = basic_appender<char>;
619 template <
typename T>
struct is_contiguous : std::false_type {};
622 template <
typename OutputIt,
typename Char>
class generic_context;
628 template <
typename OutputIt,
typename Char>
629 using basic_format_context =
630 conditional_t<std::is_same<OutputIt, appender>::value, context,
631 generic_context<OutputIt, Char>>;
632 using format_context = context;
634 template <
typename Char>
635 using buffered_context =
636 conditional_t<std::is_same<Char, char>::value, context,
637 generic_context<basic_appender<Char>, Char>>;
639 template <
typename Context>
class basic_format_arg;
647 template <
typename T,
typename Char =
char,
typename Enable =
void>
650 formatter() =
delete;
656 FMT_NORETURN FMT_API
void report_error(
const char* message);
658 enum class presentation_type : unsigned char {
681 enum class align { none, left, right, center, numeric };
682 enum class sign { none, minus, plus, space };
683 enum class arg_id_kind { none, index, name };
707 align_mask = 0x00038,
708 width_mask = 0x000C0,
709 precision_mask = 0x00300,
711 uppercase_mask = 0x01000,
712 alternate_mask = 0x02000,
713 localized_mask = 0x04000,
714 fill_size_mask = 0x38000,
720 fill_size_shift = 15,
725 unsigned data_ = 1 << fill_size_shift;
726 static_assert(
sizeof(basic_specs::data_) * CHAR_BIT >= 18,
"");
729 char fill_data_[max_fill_size] = {
' '};
731 FMT_CONSTEXPR
void set_fill_size(
size_t size) {
732 data_ = (data_ & ~fill_size_mask) |
733 (static_cast<unsigned>(size) << fill_size_shift);
737 constexpr
auto type() const -> presentation_type {
738 return static_cast<presentation_type
>(data_ & type_mask);
740 FMT_CONSTEXPR
void set_type(presentation_type t) {
741 data_ = (data_ & ~type_mask) | static_cast<unsigned>(t);
744 constexpr
auto align() const -> align {
745 return static_cast<fmt::align
>((data_ & align_mask) >> align_shift);
747 FMT_CONSTEXPR
void set_align(fmt::align a) {
748 data_ = (data_ & ~align_mask) | (static_cast<unsigned>(a) << align_shift);
751 constexpr
auto dynamic_width() const -> arg_id_kind {
752 return static_cast<arg_id_kind
>((data_ & width_mask) >> width_shift);
754 FMT_CONSTEXPR
void set_dynamic_width(arg_id_kind w) {
755 data_ = (data_ & ~width_mask) | (static_cast<unsigned>(w) << width_shift);
758 FMT_CONSTEXPR
auto dynamic_precision() const -> arg_id_kind {
759 return static_cast<arg_id_kind
>((data_ & precision_mask) >>
762 FMT_CONSTEXPR
void set_dynamic_precision(arg_id_kind p) {
763 data_ = (data_ & ~precision_mask) |
764 (static_cast<unsigned>(p) << precision_shift);
767 constexpr
auto dynamic() const ->
bool {
768 return (data_ & (width_mask | precision_mask)) != 0;
771 constexpr
auto sign() const -> sign {
772 return static_cast<fmt::sign
>((data_ & sign_mask) >> sign_shift);
774 FMT_CONSTEXPR
void set_sign(fmt::sign s) {
775 data_ = (data_ & ~sign_mask) | (static_cast<unsigned>(s) << sign_shift);
778 constexpr
auto upper() const ->
bool {
return (data_ & uppercase_mask) != 0; }
779 FMT_CONSTEXPR
void set_upper() { data_ |= uppercase_mask; }
781 constexpr
auto alt() const ->
bool {
return (data_ & alternate_mask) != 0; }
782 FMT_CONSTEXPR
void set_alt() { data_ |= alternate_mask; }
783 FMT_CONSTEXPR
void clear_alt() { data_ &= ~alternate_mask; }
785 constexpr
auto localized() const ->
bool {
786 return (data_ & localized_mask) != 0;
788 FMT_CONSTEXPR
void set_localized() { data_ |= localized_mask; }
790 constexpr
auto fill_size() const ->
size_t {
791 return (data_ & fill_size_mask) >> fill_size_shift;
794 template <typename Char, FMT_ENABLE_IF(std::is_same<Char, char>::value)>
795 constexpr
auto fill()
const ->
const Char* {
798 template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
799 constexpr
auto fill()
const ->
const Char* {
803 template <
typename Char> constexpr
auto fill_unit() const -> Char {
804 using uchar =
unsigned char;
805 return static_cast<Char
>(
static_cast<uchar
>(fill_data_[0]) |
806 (static_cast<uchar>(fill_data_[1]) << 8) |
807 (static_cast<uchar>(fill_data_[2]) << 16));
810 FMT_CONSTEXPR
void set_fill(
char c) {
815 template <
typename Char>
817 auto size = s.
size();
820 unsigned uchar =
static_cast<detail::unsigned_char<Char>
>(s[0]);
821 fill_data_[0] =
static_cast<char>(uchar);
822 fill_data_[1] =
static_cast<char>(uchar >> 8);
823 fill_data_[2] =
static_cast<char>(uchar >> 16);
826 FMT_ASSERT(size <= max_fill_size,
"invalid fill");
827 for (
size_t i = 0; i < size; ++i)
828 fill_data_[i & 3] = static_cast<char>(s[i]);
831 FMT_CONSTEXPR
void copy_fill_from(
const basic_specs& specs) {
832 set_fill_size(specs.fill_size());
833 for (
size_t i = 0; i < max_fill_size; ++i)
834 fill_data_[i] = specs.fill_data_[i];
839 struct format_specs : basic_specs {
843 constexpr format_specs() : width(0), precision(-1) {}
855 enum { use_constexpr_cast = !FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200 };
857 FMT_CONSTEXPR
void do_check_arg_id(
int arg_id);
860 using char_type = Char;
861 using iterator =
const Char*;
865 : fmt_(fmt), next_arg_id_(next_arg_id) {}
869 constexpr
auto begin() const noexcept -> iterator {
return fmt_.begin(); }
872 constexpr
auto end() const noexcept -> iterator {
return fmt_.end(); }
876 fmt_.remove_prefix(detail::to_unsigned(it - begin()));
882 if (next_arg_id_ < 0) {
883 report_error(
"cannot switch from manual to automatic argument indexing");
886 int id = next_arg_id_++;
894 if (next_arg_id_ > 0) {
895 report_error(
"cannot switch from automatic to manual argument indexing");
904 FMT_CONSTEXPR
void check_dynamic_spec(
int arg_id);
907 #ifndef FMT_USE_LOCALE 908 # define FMT_USE_LOCALE (FMT_OPTIMIZE_SIZE <= 1) 918 constexpr locale_ref() : locale_(
nullptr) {}
920 template <
typename Locale, FMT_ENABLE_IF(sizeof(Locale::collate) != 0)>
921 locale_ref(
const Locale& loc);
923 inline explicit operator bool()
const noexcept {
return locale_ !=
nullptr; }
924 #endif // FMT_USE_LOCALE 927 template <
typename Locale>
auto get()
const -> Locale;
935 template <
typename T>
struct is_code_unit : std::false_type {};
936 template <>
struct is_code_unit<char> : std::true_type {};
937 template <>
struct is_code_unit<wchar_t> : std::true_type {};
938 template <>
struct is_code_unit<char16_t> : std::true_type {};
939 template <>
struct is_code_unit<char32_t> : std::true_type {};
941 template <>
struct is_code_unit<char8_t> : bool_constant<is_utf8_enabled> {};
947 template <typename Char, FMT_ENABLE_IF(is_code_unit<Char>::value)>
951 template <typename T, FMT_ENABLE_IF(is_std_string_like<T>::value)>
952 constexpr
auto to_string_view(
const T& s)
956 template <
typename Char>
962 template <
typename T,
typename Enable =
void>
963 struct has_to_string_view : std::false_type {};
965 template <
typename T>
966 struct has_to_string_view<
967 T, void_t<decltype(detail::to_string_view(std::declval<T>()))>>
971 template <
typename S,
972 typename V = decltype(detail::to_string_view(std::declval<S>()))>
986 last_integer_type = char_type,
991 last_numeric_type = long_double_type,
999 template <
typename T,
typename Char>
1000 struct type_constant : std::integral_constant<type, type::custom_type> {};
1002 #define FMT_TYPE_CONSTANT(Type, constant) \ 1003 template <typename Char> \ 1004 struct type_constant<Type, Char> \ 1005 : std::integral_constant<type, type::constant> {} 1007 FMT_TYPE_CONSTANT(
int, int_type);
1008 FMT_TYPE_CONSTANT(
unsigned, uint_type);
1009 FMT_TYPE_CONSTANT(
long long, long_long_type);
1010 FMT_TYPE_CONSTANT(
unsigned long long, ulong_long_type);
1011 FMT_TYPE_CONSTANT(int128_opt, int128_type);
1012 FMT_TYPE_CONSTANT(uint128_opt, uint128_type);
1013 FMT_TYPE_CONSTANT(
bool, bool_type);
1014 FMT_TYPE_CONSTANT(Char, char_type);
1015 FMT_TYPE_CONSTANT(
float, float_type);
1016 FMT_TYPE_CONSTANT(
double, double_type);
1017 FMT_TYPE_CONSTANT(
long double, long_double_type);
1018 FMT_TYPE_CONSTANT(
const Char*, cstring_type);
1020 FMT_TYPE_CONSTANT(
const void*, pointer_type);
1022 constexpr
auto is_integral_type(type t) ->
bool {
1023 return t > type::none_type && t <= type::last_integer_type;
1025 constexpr
auto is_arithmetic_type(type t) ->
bool {
1026 return t > type::none_type && t <= type::last_numeric_type;
1029 constexpr
auto set(type rhs) ->
int {
return 1 <<
static_cast<int>(rhs); }
1030 constexpr
auto in(type t,
int set) ->
bool {
1031 return ((
set >> static_cast<int>(t)) & 1) != 0;
1037 set(type::int_type) |
set(type::long_long_type) |
set(type::int128_type),
1038 uint_set =
set(type::uint_type) |
set(type::ulong_long_type) |
1039 set(type::uint128_type),
1040 bool_set =
set(type::bool_type),
1041 char_set =
set(type::char_type),
1042 float_set =
set(type::float_type) |
set(type::double_type) |
1043 set(type::long_double_type),
1044 string_set =
set(type::string_type),
1045 cstring_set =
set(type::cstring_type),
1046 pointer_set =
set(type::pointer_type)
1051 template <
typename T,
typename Enable = std::true_type>
1052 struct is_view : std::false_type {};
1053 template <
typename T>
1054 struct is_view<T, bool_constant<sizeof(T) != 0>> : std::is_base_of<view, T> {};
1056 template <
typename Char,
typename T>
struct named_arg;
1057 template <
typename T>
struct is_named_arg : std::false_type {};
1058 template <
typename T>
struct is_static_named_arg : std::false_type {};
1060 template <
typename Char,
typename T>
1061 struct is_named_arg<named_arg<Char, T>> : std::true_type {};
1063 template <
typename Char,
typename T>
struct named_arg : view {
1067 named_arg(
const Char* n,
const T& v) : name(n), value(v) {}
1068 static_assert(!is_named_arg<T>::value,
"nested named arguments");
1071 template <
bool B = false> constexpr
auto count() ->
int {
return B ? 1 : 0; }
1072 template <
bool B1,
bool B2,
bool... Tail> constexpr
auto count() ->
int {
1073 return (B1 ? 1 : 0) + count<B2, Tail...>();
1076 template <
typename... T> constexpr
auto count_named_args() ->
int {
1077 return count<is_named_arg<T>::value...>();
1079 template <
typename... T> constexpr
auto count_static_named_args() ->
int {
1080 return count<is_static_named_arg<T>::value...>();
1083 template <
typename Char>
struct named_arg_info {
1089 template <
typename Char>
1090 FMT_CONSTEXPR
void check_for_duplicate(named_arg_info<Char>* named_args,
1091 int named_arg_index,
1093 for (
int i = 0; i < named_arg_index; ++i) {
1094 if (named_args[i].name == arg_name) report_error(
"duplicate named arg");
1098 template <typename Char, typename T, FMT_ENABLE_IF(!is_named_arg<T>::value)>
1099 void init_named_arg(named_arg_info<Char>*,
int& arg_index,
int&,
const T&) {
1102 template <typename Char, typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
1103 void init_named_arg(named_arg_info<Char>* named_args,
int& arg_index,
1104 int& named_arg_index,
const T& arg) {
1105 check_for_duplicate<Char>(named_args, named_arg_index, arg.name);
1106 named_args[named_arg_index++] = {arg.name, arg_index++};
1109 template <
typename T,
typename Char,
1110 FMT_ENABLE_IF(!is_static_named_arg<T>::value)>
1111 FMT_CONSTEXPR
void init_static_named_arg(named_arg_info<Char>*,
int& arg_index,
1115 template <
typename T,
typename Char,
1116 FMT_ENABLE_IF(is_static_named_arg<T>::value)>
1117 FMT_CONSTEXPR
void init_static_named_arg(named_arg_info<Char>* named_args,
1118 int& arg_index,
int& named_arg_index) {
1119 check_for_duplicate<Char>(named_args, named_arg_index, T::name);
1120 named_args[named_arg_index++] = {T::name, arg_index++};
1125 enum { long_short =
sizeof(long) ==
sizeof(
int) && FMT_BUILTIN_TYPES };
1126 using long_type = conditional_t<long_short, int, long long>;
1127 using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
1129 template <
typename T>
1130 using format_as_result =
1131 remove_cvref_t<decltype(format_as(std::declval<const T&>()))>;
1132 template <
typename T>
1133 using format_as_member_result =
1134 remove_cvref_t<decltype(formatter<T>::format_as(std::declval<const T&>()))>;
1136 template <
typename T,
typename Enable = std::true_type>
1137 struct use_format_as : std::false_type {};
1139 template <
typename T,
typename Enable = std::true_type>
1140 struct use_format_as_member : std::false_type {};
1143 template <
typename T>
1144 struct use_format_as<
1145 T, bool_constant<std::is_arithmetic<format_as_result<T>>::value>>
1146 : std::true_type {};
1147 template <
typename T>
1148 struct use_format_as_member<
1149 T, bool_constant<std::is_arithmetic<format_as_member_result<T>>::value>>
1150 : std::true_type {};
1152 template <
typename T,
typename U = remove_const_t<T>>
1153 using use_formatter =
1154 bool_constant<(std::is_class<T>::value || std::is_enum<T>::value ||
1155 std::is_union<T>::value || std::is_array<T>::value) &&
1156 !has_to_string_view<T>::value && !is_named_arg<T>::value &&
1157 !use_format_as<T>::value && !use_format_as_member<U>::value>;
1159 template <
typename Char,
typename T,
typename U = remove_const_t<T>>
1160 auto has_formatter_impl(T* p, buffered_context<Char>* ctx =
nullptr)
1161 -> decltype(formatter<U, Char>().format(*p, *ctx), std::true_type());
1162 template <
typename Char>
auto has_formatter_impl(...) -> std::false_type;
1165 template <
typename T,
typename Char> constexpr
auto has_formatter() ->
bool {
1166 return decltype(has_formatter_impl<Char>(static_cast<T*>(
nullptr)))::value;
1171 template <
typename Char>
struct type_mapper {
1172 static auto map(
signed char) -> int;
1173 static auto map(
unsigned char) -> unsigned;
1174 static auto map(
short) -> int;
1175 static auto map(
unsigned short) -> unsigned;
1176 static auto map(
int) -> int;
1177 static auto map(
unsigned) -> unsigned;
1178 static auto map(
long) -> long_type;
1179 static auto map(
unsigned long) -> ulong_type;
1180 static auto map(
long long) ->
long long;
1181 static auto map(
unsigned long long) ->
unsigned long long;
1182 static auto map(int128_opt) -> int128_opt;
1183 static auto map(uint128_opt) -> uint128_opt;
1184 static auto map(
bool) -> bool;
1187 static auto map(bitint<N>) -> conditional_t<N <= 64, long long, void>;
1189 static auto map(ubitint<N>)
1190 -> conditional_t<N <= 64, unsigned long long, void>;
1192 template <typename T, FMT_ENABLE_IF(is_code_unit<T>::value)>
1193 static auto map(T) -> conditional_t<
1194 std::is_same<T, char>::value || std::is_same<T, Char>::value, Char,
void>;
1196 static auto map(
float) -> float;
1197 static auto map(
double) -> double;
1198 static auto map(
long double) ->
long double;
1200 static auto map(Char*) ->
const Char*;
1201 static auto map(
const Char*) ->
const Char*;
1202 template <
typename T,
typename C =
char_t<T>,
1203 FMT_ENABLE_IF(!std::is_po
inter<T>::value)>
1204 static auto map(
const T&) -> conditional_t<std::is_same<C, Char>::value,
1207 static auto map(
void*) ->
const void*;
1208 static auto map(
const void*) ->
const void*;
1209 static auto map(
volatile void*) ->
const void*;
1210 static auto map(
const volatile void*) ->
const void*;
1211 static auto map(nullptr_t) ->
const void*;
1212 template <typename T, FMT_ENABLE_IF(std::is_pointer<T>::value ||
1213 std::is_member_pointer<T>::value)>
1214 static auto map(
const T&) -> void;
1216 template <typename T, FMT_ENABLE_IF(use_format_as<T>::value)>
1217 static auto map(
const T& x) -> decltype(map(format_as(x)));
1218 template <typename T, FMT_ENABLE_IF(use_format_as_member<T>::value)>
1219 static auto map(
const T& x) -> decltype(map(formatter<T>::format_as(x)));
1221 template <typename T, FMT_ENABLE_IF(use_formatter<T>::value)>
1222 static auto map(T&) -> conditional_t<has_formatter<T, Char>(), T&,
void>;
1224 template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
1225 static auto map(
const T& named_arg) -> decltype(map(named_arg.value));
1229 template <
typename T,
typename Char>
1230 using mapped_t = decltype(detail::type_mapper<Char>::map(std::declval<T&>()));
1233 template <
typename T,
typename Char =
char>
1234 using mapped_type_constant = type_constant<mapped_t<T, Char>, Char>;
1236 template <
typename T,
typename Context,
1238 mapped_type_constant<T, typename Context::char_type>::value>
1239 using stored_type_constant = std::integral_constant<
1240 type, Context::builtin_types || TYPE == type::int_type ? TYPE
1241 : type::custom_type>;
1243 template <
typename Char>
1252 int num_args,
const type* types,
1253 int next_arg_id = 0)
1254 : base(fmt, next_arg_id), num_args_(num_args), types_(types) {}
1256 constexpr
auto num_args()
const ->
int {
return num_args_; }
1257 constexpr
auto arg_type(
int id)
const -> type {
return types_[id]; }
1259 FMT_CONSTEXPR
auto next_arg_id() ->
int {
1260 int id = base::next_arg_id();
1261 if (
id >= num_args_) report_error(
"argument not found");
1265 FMT_CONSTEXPR
void check_arg_id(
int id) {
1266 base::check_arg_id(
id);
1267 if (
id >= num_args_) report_error(
"argument not found");
1269 using base::check_arg_id;
1271 FMT_CONSTEXPR
void check_dynamic_spec(
int arg_id) {
1272 ignore_unused(arg_id);
1273 if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
1274 report_error(
"width/precision is not integer");
1279 template <
typename Char>
union arg_ref {
1280 FMT_CONSTEXPR arg_ref(
int idx = 0) : index(idx) {}
1290 template <
typename Char =
char>
struct dynamic_format_specs : format_specs {
1291 arg_ref<Char> width_ref;
1292 arg_ref<Char> precision_ref;
1296 template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
1297 constexpr
auto to_ascii(Char c) ->
char {
1298 return c <= 0xff ? static_cast<char>(c) :
'\0';
1302 template <
typename Char>
1303 FMT_CONSTEXPR
auto code_point_length(
const Char* begin) ->
int {
1304 if (const_check(
sizeof(Char) != 1))
return 1;
1305 auto c =
static_cast<unsigned char>(*begin);
1306 return static_cast<int>((0x3a55000000000000ull >> (2 * (c >> 3))) & 3) + 1;
1311 template <
typename Char>
1312 FMT_CONSTEXPR
auto parse_nonnegative_int(
const Char*& begin,
const Char* end,
1313 int error_value) noexcept ->
int {
1314 FMT_ASSERT(begin != end &&
'0' <= *begin && *begin <=
'9',
"");
1315 unsigned value = 0, prev = 0;
1319 value = value * 10 + unsigned(*p -
'0');
1321 }
while (p != end &&
'0' <= *p && *p <=
'9');
1322 auto num_digits = p - begin;
1324 int digits10 =
static_cast<int>(
sizeof(int) * CHAR_BIT * 3 / 10);
1325 if (num_digits <= digits10)
return static_cast<int>(value);
1327 unsigned max = INT_MAX;
1328 return num_digits == digits10 + 1 &&
1329 prev * 10ull + unsigned(p[-1] -
'0') <= max
1330 ?
static_cast<int>(value)
1334 FMT_CONSTEXPR
inline auto parse_align(
char c) -> align {
1336 case '<':
return align::left;
1337 case '>':
return align::right;
1338 case '^':
return align::center;
1343 template <
typename Char> constexpr
auto is_name_start(Char c) ->
bool {
1344 return (
'a' <= c && c <=
'z') || (
'A' <= c && c <=
'Z') || c ==
'_';
1347 template <
typename Char,
typename Handler>
1348 FMT_CONSTEXPR
auto parse_arg_id(
const Char* begin,
const Char* end,
1349 Handler&& handler) ->
const Char* {
1351 if (c >=
'0' && c <=
'9') {
1354 index = parse_nonnegative_int(begin, end, INT_MAX);
1357 if (begin == end || (*begin !=
'}' && *begin !=
':'))
1358 report_error(
"invalid format string");
1360 handler.on_index(index);
1363 if (FMT_OPTIMIZE_SIZE > 1 || !is_name_start(c)) {
1364 report_error(
"invalid format string");
1370 }
while (it != end && (is_name_start(*it) || (
'0' <= *it && *it <=
'9')));
1371 handler.on_name({begin, to_unsigned(it - begin)});
1375 template <
typename Char>
struct dynamic_spec_handler {
1380 FMT_CONSTEXPR
void on_index(
int id) {
1382 kind = arg_id_kind::index;
1384 ctx.check_dynamic_spec(
id);
1388 kind = arg_id_kind::name;
1393 template <
typename Char>
struct parse_dynamic_spec_result {
1399 template <
typename Char>
1400 FMT_CONSTEXPR
auto parse_dynamic_spec(
const Char* begin,
const Char* end,
1401 int& value, arg_ref<Char>& ref,
1403 -> parse_dynamic_spec_result<Char> {
1404 FMT_ASSERT(begin != end,
"");
1405 auto kind = arg_id_kind::none;
1406 if (
'0' <= *begin && *begin <=
'9') {
1407 int val = parse_nonnegative_int(begin, end, -1);
1408 if (val == -1) report_error(
"number is too big");
1411 if (*begin ==
'{') {
1415 if (c ==
'}' || c ==
':') {
1418 kind = arg_id_kind::index;
1419 ctx.check_dynamic_spec(
id);
1421 begin = parse_arg_id(begin, end,
1422 dynamic_spec_handler<Char>{ctx, ref, kind});
1425 if (begin != end && *begin ==
'}')
return {++begin, kind};
1427 report_error(
"invalid format string");
1429 return {begin, kind};
1432 template <
typename Char>
1433 FMT_CONSTEXPR
auto parse_width(
const Char* begin,
const Char* end,
1434 format_specs& specs, arg_ref<Char>& width_ref,
1436 auto result = parse_dynamic_spec(begin, end, specs.width, width_ref, ctx);
1437 specs.set_dynamic_width(result.kind);
1441 template <
typename Char>
1442 FMT_CONSTEXPR
auto parse_precision(
const Char* begin,
const Char* end,
1443 format_specs& specs,
1444 arg_ref<Char>& precision_ref,
1448 report_error(
"invalid precision");
1452 parse_dynamic_spec(begin, end, specs.precision, precision_ref, ctx);
1453 specs.set_dynamic_precision(result.kind);
1457 enum class state { start, align, sign, hash, zero, width, precision, locale };
1460 template <
typename Char>
1461 FMT_CONSTEXPR
auto parse_format_specs(
const Char* begin,
const Char* end,
1462 dynamic_format_specs<Char>& specs,
1466 if (end - begin > 1) {
1467 auto next = to_ascii(begin[1]);
1468 c = parse_align(
next) == align::none ? to_ascii(*begin) :
'\0';
1470 if (begin == end)
return begin;
1471 c = to_ascii(*begin);
1475 state current_state = state::start;
1476 FMT_CONSTEXPR
void operator()(state s,
bool valid =
true) {
1477 if (current_state >= s || !valid)
1478 report_error(
"invalid format specifier");
1483 using pres = presentation_type;
1484 constexpr
auto integral_set = sint_set | uint_set | bool_set | char_set;
1487 format_specs& specs;
1490 FMT_CONSTEXPR
auto operator()(pres pres_type,
int set) ->
const Char* {
1491 if (!in(arg_type,
set)) report_error(
"invalid format specifier");
1492 specs.set_type(pres_type);
1495 } parse_presentation_type{begin, specs, arg_type};
1502 enter_state(state::align);
1503 specs.set_align(parse_align(c));
1508 specs.set_sign(c ==
' ' ? sign::space : sign::plus);
1511 enter_state(state::sign, in(arg_type, sint_set | float_set));
1515 enter_state(state::hash, is_arithmetic_type(arg_type));
1520 enter_state(state::zero);
1521 if (!is_arithmetic_type(arg_type))
1522 report_error(
"format specifier requires numeric argument");
1523 if (specs.align() == align::none) {
1525 specs.set_align(align::numeric);
1526 specs.set_fill(
'0');
1531 case '1':
case '2':
case '3':
case '4':
case '5':
1532 case '6':
case '7':
case '8':
case '9':
case '{':
1534 enter_state(state::width);
1535 begin = parse_width(begin, end, specs, specs.width_ref, ctx);
1538 enter_state(state::precision,
1539 in(arg_type, float_set | string_set | cstring_set));
1540 begin = parse_precision(begin, end, specs, specs.precision_ref, ctx);
1543 enter_state(state::locale, is_arithmetic_type(arg_type));
1544 specs.set_localized();
1547 case 'd':
return parse_presentation_type(pres::dec, integral_set);
1548 case 'X': specs.set_upper(); FMT_FALLTHROUGH;
1549 case 'x':
return parse_presentation_type(pres::hex, integral_set);
1550 case 'o':
return parse_presentation_type(pres::oct, integral_set);
1551 case 'B': specs.set_upper(); FMT_FALLTHROUGH;
1552 case 'b':
return parse_presentation_type(pres::bin, integral_set);
1553 case 'E': specs.set_upper(); FMT_FALLTHROUGH;
1554 case 'e':
return parse_presentation_type(pres::exp, float_set);
1555 case 'F': specs.set_upper(); FMT_FALLTHROUGH;
1556 case 'f':
return parse_presentation_type(pres::fixed, float_set);
1557 case 'G': specs.set_upper(); FMT_FALLTHROUGH;
1558 case 'g':
return parse_presentation_type(pres::general, float_set);
1559 case 'A': specs.set_upper(); FMT_FALLTHROUGH;
1560 case 'a':
return parse_presentation_type(pres::hexfloat, float_set);
1562 if (arg_type == type::bool_type) report_error(
"invalid format specifier");
1563 return parse_presentation_type(pres::chr, integral_set);
1565 return parse_presentation_type(pres::string,
1566 bool_set | string_set | cstring_set);
1568 return parse_presentation_type(pres::pointer, pointer_set | cstring_set);
1570 return parse_presentation_type(pres::debug,
1571 char_set | string_set | cstring_set);
1572 case '}':
return begin;
1574 if (*begin ==
'}')
return begin;
1576 auto fill_end = begin + code_point_length(begin);
1577 if (end - fill_end <= 0) {
1578 report_error(
"invalid format specifier");
1581 if (*begin ==
'{') {
1582 report_error(
"invalid fill character '{'");
1585 auto alignment = parse_align(to_ascii(*fill_end));
1586 enter_state(state::align, alignment != align::none);
1589 specs.set_align(alignment);
1590 begin = fill_end + 1;
1593 if (begin == end)
return begin;
1594 c = to_ascii(*begin);
1598 template <
typename Char,
typename Handler>
1599 FMT_CONSTEXPR FMT_INLINE
auto parse_replacement_field(
const Char* begin,
1605 handler.on_error(
"invalid format string");
1611 handler.on_replacement_field(handler.on_arg_id(), begin);
1613 case '{': handler.on_text(begin, begin + 1);
return begin + 1;
1614 case ':': arg_id = handler.on_arg_id();
break;
1620 FMT_CONSTEXPR
void on_index(
int id) { arg_id = handler.on_arg_id(
id); }
1622 arg_id = handler.on_arg_id(
id);
1624 } adapter = {handler, 0};
1625 begin = parse_arg_id(begin, end, adapter);
1626 arg_id = adapter.arg_id;
1627 Char c = begin != end ? *begin : Char();
1629 handler.on_replacement_field(arg_id, begin);
1633 handler.on_error(
"missing '}' in format string");
1639 begin = handler.on_format_specs(arg_id, begin + 1, end);
1640 if (begin == end || *begin !=
'}')
1641 return handler.on_error(
"unknown format specifier"), end;
1645 template <
typename Char,
typename Handler>
1647 Handler&& handler) {
1648 auto begin = fmt.
data(), end = begin + fmt.
size();
1653 handler.on_text(begin, p - 1);
1654 begin = p = parse_replacement_field(p - 1, end, handler);
1655 }
else if (c ==
'}') {
1656 if (p == end || *p !=
'}')
1657 return handler.on_error(
"unmatched '}' in format string");
1658 handler.on_text(begin, p);
1662 handler.on_text(begin, end);
1666 FMT_CONSTEXPR
inline auto check_char_specs(
const format_specs& specs) ->
bool {
1667 auto type = specs.type();
1668 if (type != presentation_type::none && type != presentation_type::chr &&
1669 type != presentation_type::debug) {
1672 if (specs.align() == align::numeric || specs.sign() != sign::none ||
1674 report_error(
"invalid format specifier for char");
1680 struct compile_string {};
1682 template <
typename T,
typename Char>
1683 FMT_VISIBILITY(
"hidden")
1685 using mapped_type = remove_cvref_t<mapped_t<T, Char>>;
1686 constexpr
bool formattable =
1687 std::is_constructible<formatter<mapped_type, Char>>::value;
1688 if (!formattable)
return ctx.
begin();
1689 using formatted_type = conditional_t<formattable, mapped_type, int>;
1690 return formatter<formatted_type, Char>().parse(ctx);
1693 template <
typename... T>
struct arg_pack {};
1695 template <
typename Char,
int NUM_ARGS,
int NUM_NAMED_ARGS,
bool DYNAMIC_NAMES>
1696 class format_string_checker {
1698 type types_[max_of<size_t>(1, NUM_ARGS)];
1699 named_arg_info<Char> named_args_[max_of<size_t>(1, NUM_NAMED_ARGS)];
1700 compile_parse_context<Char> context_;
1703 parse_func parse_funcs_[max_of<size_t>(1, NUM_ARGS)];
1706 template <
typename... T>
1709 : types_{mapped_type_constant<T, Char>::value...},
1711 context_(fmt, NUM_ARGS, types_),
1712 parse_funcs_{&invoke_parse<T, Char>...} {
1713 int arg_index = 0, named_arg_index = 0;
1715 init_static_named_arg<T>(named_args_, arg_index, named_arg_index));
1716 ignore_unused(arg_index, named_arg_index);
1719 FMT_CONSTEXPR
void on_text(
const Char*,
const Char*) {}
1721 FMT_CONSTEXPR
auto on_arg_id() ->
int {
return context_.next_arg_id(); }
1722 FMT_CONSTEXPR
auto on_arg_id(
int id) ->
int {
1723 context_.check_arg_id(
id);
1727 for (
int i = 0; i < NUM_NAMED_ARGS; ++i) {
1728 if (named_args_[i].name ==
id)
return named_args_[i].id;
1730 if (!DYNAMIC_NAMES) on_error(
"argument not found");
1734 FMT_CONSTEXPR
void on_replacement_field(
int id,
const Char* begin) {
1735 on_format_specs(
id, begin, begin);
1738 FMT_CONSTEXPR
auto on_format_specs(
int id,
const Char* begin,
const Char* end)
1740 context_.advance_to(begin);
1741 if (
id >= 0 &&
id < NUM_ARGS)
return parse_funcs_[id](context_);
1746 for (
int bracket_count = 0;
1747 begin != end && (bracket_count > 0 || *begin !=
'}'); ++begin) {
1750 else if (*begin ==
'}')
1756 FMT_NORETURN FMT_CONSTEXPR
void on_error(
const char* message) {
1757 report_error(message);
1769 using grow_fun = void (*)(
buffer& buf,
size_t capacity);
1774 FMT_MSC_WARNING(suppress : 26495)
1775 FMT_CONSTEXPR
buffer(grow_fun grow,
size_t sz) noexcept
1776 : size_(sz), capacity_(sz), grow_(grow) {}
1778 constexpr
buffer(grow_fun grow, T* p =
nullptr,
size_t sz = 0,
1779 size_t cap = 0) noexcept
1780 : ptr_(p), size_(sz), capacity_(cap), grow_(grow) {}
1782 FMT_CONSTEXPR20 ~
buffer() =
default;
1786 FMT_CONSTEXPR
void set(T* buf_data,
size_t buf_capacity) noexcept {
1788 capacity_ = buf_capacity;
1792 using value_type = T;
1793 using const_reference =
const T&;
1796 void operator=(
const buffer&) =
delete;
1798 auto begin() noexcept -> T* {
return ptr_; }
1799 auto end() noexcept -> T* {
return ptr_ + size_; }
1801 auto begin()
const noexcept ->
const T* {
return ptr_; }
1802 auto end()
const noexcept ->
const T* {
return ptr_ + size_; }
1805 constexpr
auto size() const noexcept ->
size_t {
return size_; }
1808 constexpr
auto capacity() const noexcept ->
size_t {
return capacity_; }
1811 FMT_CONSTEXPR
auto data() noexcept -> T* {
return ptr_; }
1812 FMT_CONSTEXPR
auto data()
const noexcept ->
const T* {
return ptr_; }
1815 FMT_CONSTEXPR
void clear() { size_ = 0; }
1819 FMT_CONSTEXPR
void try_resize(
size_t count) {
1821 size_ = min_of(count, capacity_);
1828 FMT_CONSTEXPR
void try_reserve(
size_t new_capacity) {
1829 if (new_capacity > capacity_) grow_(*
this, new_capacity);
1832 FMT_CONSTEXPR
void push_back(
const T& value) {
1833 try_reserve(size_ + 1);
1834 ptr_[size_++] = value;
1838 template <
typename U>
1841 #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1940 1846 while (begin != end) {
1847 auto count = to_unsigned(end - begin);
1848 try_reserve(size_ + count);
1849 auto free_cap = capacity_ - size_;
1850 if (free_cap < count) count = free_cap;
1852 T* out = ptr_ + size_;
1853 for (
size_t i = 0; i < count; ++i) out[i] = begin[i];
1859 template <
typename Idx> FMT_CONSTEXPR
auto operator[](Idx index) -> T& {
1862 template <
typename Idx>
1863 FMT_CONSTEXPR
auto operator[](Idx index)
const ->
const T& {
1868 struct buffer_traits {
1869 constexpr
explicit buffer_traits(
size_t) {}
1870 constexpr
auto count()
const ->
size_t {
return 0; }
1871 constexpr
auto limit(
size_t size)
const ->
size_t {
return size; }
1874 class fixed_buffer_traits {
1880 constexpr
explicit fixed_buffer_traits(
size_t limit) : limit_(limit) {}
1881 constexpr
auto count()
const ->
size_t {
return count_; }
1882 FMT_CONSTEXPR
auto limit(
size_t size) ->
size_t {
1883 size_t n = limit_ > count_ ? limit_ - count_ : 0;
1885 return min_of(size, n);
1890 template <
typename OutputIt,
typename T,
typename Traits = buffer_traits>
1891 class iterator_buffer :
public Traits,
public buffer<T> {
1894 enum { buffer_size = 256 };
1895 T data_[buffer_size];
1897 static FMT_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
1898 if (buf.
size() == buffer_size) static_cast<iterator_buffer&>(buf).flush();
1902 auto size = this->size();
1904 const T* begin = data_;
1905 const T* end = begin + this->limit(size);
1906 while (begin != end) *out_++ = *begin++;
1910 explicit iterator_buffer(OutputIt out,
size_t n = buffer_size)
1911 : Traits(n),
buffer<T>(grow, data_, 0, buffer_size), out_(out) {}
1912 iterator_buffer(iterator_buffer&& other) noexcept
1916 ~iterator_buffer() {
1918 FMT_TRY { flush(); }
1922 auto out() -> OutputIt {
1926 auto count()
const ->
size_t {
return Traits::count() + this->size(); }
1929 template <
typename T>
1930 class iterator_buffer<T*, T, fixed_buffer_traits> :
public fixed_buffer_traits,
1934 enum { buffer_size = 256 };
1935 T data_[buffer_size];
1937 static FMT_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
1939 static_cast<iterator_buffer&>(buf).flush();
1943 size_t n = this->limit(this->size());
1944 if (this->data() == out_) {
1946 this->
set(data_, buffer_size);
1952 explicit iterator_buffer(T* out,
size_t n = buffer_size)
1953 : fixed_buffer_traits(n),
buffer<T>(grow, out, 0, n), out_(out) {}
1954 iterator_buffer(iterator_buffer&& other) noexcept
1955 : fixed_buffer_traits(other),
1956 buffer<T>(
static_cast<iterator_buffer&&
>(other)),
1958 if (this->data() != out_) {
1959 this->
set(data_, buffer_size);
1963 ~iterator_buffer() { flush(); }
1969 auto count()
const ->
size_t {
1970 return fixed_buffer_traits::count() + this->size();
1974 template <
typename T>
class iterator_buffer<T*, T> :
public buffer<T> {
1976 explicit iterator_buffer(T* out,
size_t = 0)
1979 auto out() -> T* {
return &*this->end(); }
1982 template <
typename Container>
1983 class container_buffer :
public buffer<typename Container::value_type> {
1985 using value_type =
typename Container::value_type;
1988 auto&
self =
static_cast<container_buffer&
>(buf);
1989 self.container.resize(capacity);
1990 self.set(&
self.container[0], capacity);
1994 Container& container;
1996 explicit container_buffer(Container& c)
2001 template <
typename OutputIt>
2002 class iterator_buffer<
2004 enable_if_t<is_back_insert_iterator<OutputIt>::value &&
2005 is_contiguous<typename OutputIt::container_type>::value,
2006 typename OutputIt::container_type::value_type>>
2007 :
public container_buffer<typename OutputIt::container_type> {
2009 using base = container_buffer<typename OutputIt::container_type>;
2012 explicit iterator_buffer(
typename OutputIt::container_type& c) : base(c) {}
2013 explicit iterator_buffer(OutputIt out,
size_t = 0)
2014 : base(get_container(out)) {}
2016 auto out() -> OutputIt {
return OutputIt(this->container); }
2020 template <
typename T =
char>
class counting_buffer :
public buffer<T> {
2022 enum { buffer_size = 256 };
2023 T data_[buffer_size];
2026 static FMT_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
2027 if (buf.
size() != buffer_size)
return;
2028 static_cast<counting_buffer&
>(buf).count_ += buf.
size();
2033 FMT_CONSTEXPR counting_buffer() :
buffer<T>(grow, data_, 0, buffer_size) {}
2035 constexpr
auto count()
const noexcept ->
size_t {
2036 return count_ + this->size();
2040 template <
typename T>
2041 struct is_back_insert_iterator<basic_appender<T>> : std::true_type {};
2043 template <
typename OutputIt,
typename InputIt,
typename =
void>
2044 struct has_back_insert_iterator_container_append : std::false_type {};
2045 template <
typename OutputIt,
typename InputIt>
2046 struct has_back_insert_iterator_container_append<
2048 void_t<decltype(get_container(std::declval<OutputIt>())
2049 .append(std::declval<InputIt>(),
2050 std::declval<InputIt>()))>> : std::true_type {};
2052 template <
typename OutputIt,
typename InputIt,
typename =
void>
2053 struct has_back_insert_iterator_container_insert_at_end : std::false_type {};
2055 template <
typename OutputIt,
typename InputIt>
2056 struct has_back_insert_iterator_container_insert_at_end<
2058 void_t<decltype(get_container(std::declval<OutputIt>())
2059 .insert(get_container(std::declval<OutputIt>()).end(),
2060 std::declval<InputIt>(),
2061 std::declval<InputIt>()))>> : std::true_type {};
2064 template <
typename T,
typename InputIt,
typename OutputIt,
2065 FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value&&
2066 has_back_insert_iterator_container_append<
2067 OutputIt, InputIt>::value)>
2068 FMT_CONSTEXPR20
auto copy(InputIt begin, InputIt end, OutputIt out)
2070 get_container(out).append(begin, end);
2074 template <
typename T,
typename InputIt,
typename OutputIt,
2075 FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value &&
2076 !has_back_insert_iterator_container_append<
2077 OutputIt, InputIt>::value &&
2078 has_back_insert_iterator_container_insert_at_end<
2079 OutputIt, InputIt>::value)>
2080 FMT_CONSTEXPR20
auto copy(InputIt begin, InputIt end, OutputIt out)
2082 auto& c = get_container(out);
2083 c.insert(c.end(), begin, end);
2087 template <
typename T,
typename InputIt,
typename OutputIt,
2088 FMT_ENABLE_IF(!(is_back_insert_iterator<OutputIt>::value &&
2089 (has_back_insert_iterator_container_append<
2090 OutputIt, InputIt>::value ||
2091 has_back_insert_iterator_container_insert_at_end<
2092 OutputIt, InputIt>::value)))>
2093 FMT_CONSTEXPR
auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
2094 while (begin != end) *out++ =
static_cast<T
>(*begin++);
2098 template <
typename T,
typename V,
typename OutputIt>
2100 return copy<T>(s.begin(), s.end(), out);
2103 template <
typename It,
typename Enable = std::true_type>
2104 struct is_buffer_appender : std::false_type {};
2105 template <
typename It>
2106 struct is_buffer_appender<
2108 is_back_insert_iterator<It>::value &&
2109 std::is_base_of<buffer<typename It::container_type::value_type>,
2110 typename It::container_type>::value>>
2111 : std::true_type {};
2114 template <
typename T,
typename OutputIt,
2115 FMT_ENABLE_IF(!is_buffer_appender<OutputIt>::value)>
2116 auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
2117 return iterator_buffer<OutputIt, T>(out);
2119 template <
typename T,
typename OutputIt,
2120 FMT_ENABLE_IF(is_buffer_appender<OutputIt>::value)>
2121 auto get_buffer(OutputIt out) ->
buffer<T>& {
2122 return get_container(out);
2125 template <
typename Buf,
typename OutputIt>
2126 auto get_iterator(Buf& buf, OutputIt) -> decltype(buf.out()) {
2129 template <
typename T,
typename OutputIt>
2130 auto get_iterator(
buffer<T>&, OutputIt out) -> OutputIt {
2135 template <
typename T,
typename Char>
struct type_is_unformattable_for;
2137 template <
typename Char>
struct string_value {
2143 template <
typename Context>
struct custom_value {
2144 using char_type =
typename Context::char_type;
2149 template <
typename Char>
struct named_arg_value {
2150 const named_arg_info<Char>* data;
2154 struct custom_tag {};
2156 #if !FMT_BUILTIN_TYPES 2157 # define FMT_BUILTIN , monostate 2159 # define FMT_BUILTIN 2163 template <
typename Context>
class value {
2165 using char_type =
typename Context::char_type;
2170 unsigned uint_value;
2171 long long long_long_value;
2172 unsigned long long ulong_long_value;
2173 int128_opt int128_value;
2174 uint128_opt uint128_value;
2176 char_type char_value;
2178 double double_value;
2179 long double long_double_value;
2180 const void* pointer;
2181 string_value<char_type> string;
2182 custom_value<Context> custom;
2183 named_arg_value<char_type> named_args;
2186 constexpr FMT_INLINE value() : no_value() {}
2187 constexpr FMT_INLINE value(
signed char x) : int_value(x) {}
2188 constexpr FMT_INLINE value(
unsigned char x FMT_BUILTIN) : uint_value(x) {}
2189 constexpr FMT_INLINE value(
signed short x) : int_value(x) {}
2190 constexpr FMT_INLINE value(
unsigned short x FMT_BUILTIN) : uint_value(x) {}
2191 constexpr FMT_INLINE value(
int x) : int_value(x) {}
2192 constexpr FMT_INLINE value(
unsigned x FMT_BUILTIN) : uint_value(x) {}
2193 FMT_CONSTEXPR FMT_INLINE value(
long x FMT_BUILTIN) : value(long_type(x)) {}
2194 FMT_CONSTEXPR FMT_INLINE value(
unsigned long x FMT_BUILTIN)
2195 : value(ulong_type(x)) {}
2196 constexpr FMT_INLINE value(
long long x FMT_BUILTIN) : long_long_value(x) {}
2197 constexpr FMT_INLINE value(
unsigned long long x FMT_BUILTIN)
2198 : ulong_long_value(x) {}
2199 FMT_INLINE value(int128_opt x FMT_BUILTIN) : int128_value(x) {}
2200 FMT_INLINE value(uint128_opt x FMT_BUILTIN) : uint128_value(x) {}
2201 constexpr FMT_INLINE value(
bool x FMT_BUILTIN) : bool_value(x) {}
2204 constexpr FMT_INLINE value(bitint<N> x FMT_BUILTIN) : long_long_value(x) {
2205 static_assert(N <= 64,
"unsupported _BitInt");
2208 constexpr FMT_INLINE value(ubitint<N> x FMT_BUILTIN) : ulong_long_value(x) {
2209 static_assert(N <= 64,
"unsupported _BitInt");
2212 template <typename T, FMT_ENABLE_IF(is_code_unit<T>::value)>
2213 constexpr FMT_INLINE value(T x FMT_BUILTIN) : char_value(x) {
2215 std::is_same<T, char>::value || std::is_same<T, char_type>::value,
2216 "mixing character types is disallowed");
2219 constexpr FMT_INLINE value(
float x FMT_BUILTIN) : float_value(x) {}
2220 constexpr FMT_INLINE value(
double x FMT_BUILTIN) : double_value(x) {}
2221 FMT_INLINE value(
long double x FMT_BUILTIN) : long_double_value(x) {}
2223 FMT_CONSTEXPR FMT_INLINE value(char_type* x FMT_BUILTIN) {
2225 if (is_constant_evaluated())
string.size = 0;
2227 FMT_CONSTEXPR FMT_INLINE value(
const char_type* x FMT_BUILTIN) {
2229 if (is_constant_evaluated())
string.size = 0;
2231 template <
typename T,
typename C =
char_t<T>,
2232 FMT_ENABLE_IF(!std::is_po
inter<T>::value)>
2233 FMT_CONSTEXPR value(
const T& x FMT_BUILTIN) {
2234 static_assert(std::is_same<C, char_type>::value,
2235 "mixing character types is disallowed");
2236 auto sv = to_string_view(x);
2237 string.data = sv.data();
2238 string.size = sv.size();
2240 FMT_INLINE value(
void* x FMT_BUILTIN) : pointer(x) {}
2241 FMT_INLINE value(
const void* x FMT_BUILTIN) : pointer(x) {}
2242 FMT_INLINE value(
volatile void* x FMT_BUILTIN)
2243 : pointer(const_cast<const void*>(x)) {}
2244 FMT_INLINE value(
const volatile void* x FMT_BUILTIN)
2245 : pointer(const_cast<const void*>(x)) {}
2246 FMT_INLINE value(nullptr_t) : pointer(
nullptr) {}
2248 template <typename T, FMT_ENABLE_IF(std::is_pointer<T>::value ||
2249 std::is_member_pointer<T>::value)>
2254 static_assert(
sizeof(T) == 0,
2255 "formatting of non-void pointers is disallowed");
2258 template <typename T, FMT_ENABLE_IF(use_format_as<T>::value)>
2259 value(
const T& x) : value(format_as(x)) {}
2260 template <typename T, FMT_ENABLE_IF(use_format_as_member<T>::value)>
2261 value(
const T& x) : value(formatter<T>::format_as(x)) {}
2263 template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
2264 value(
const T& named_arg) : value(named_arg.value) {}
2266 template <
typename T,
2267 FMT_ENABLE_IF(use_formatter<T>::value || !FMT_BUILTIN_TYPES)>
2268 FMT_CONSTEXPR20 FMT_INLINE value(T& x) : value(x, custom_tag()) {}
2270 FMT_ALWAYS_INLINE value(
const named_arg_info<char_type>* args,
size_t size)
2271 : named_args{args, size} {}
2274 template <
typename T, FMT_ENABLE_IF(has_formatter<T,
char_type>())>
2275 FMT_CONSTEXPR value(T& x, custom_tag) {
2276 using value_type = remove_const_t<T>;
2278 if (!is_constant_evaluated()) {
2280 const_cast<char*
>(&
reinterpret_cast<const volatile char&
>(x));
2282 custom.value =
nullptr;
2283 #if defined(__cpp_if_constexpr) 2284 if constexpr (std::is_same<decltype(&x), remove_reference_t<T>*>::value)
2285 custom.value =
const_cast<value_type*
>(&x);
2288 custom.format = format_custom<value_type>;
2291 template <
typename T, FMT_ENABLE_IF(!has_formatter<T,
char_type>())>
2292 FMT_CONSTEXPR value(
const T&, custom_tag) {
2295 type_is_unformattable_for<T, char_type> _;
2299 template <
typename T>
2302 auto f = formatter<T, char_type>();
2304 using qualified_type =
2305 conditional_t<has_formatter<const T, char_type>(),
const T, T>;
2308 ctx.advance_to(cf.format(*static_cast<qualified_type*>(arg), ctx));
2312 enum { packed_arg_bits = 4 };
2314 enum { max_packed_args = 62 / packed_arg_bits };
2315 enum :
unsigned long long { is_unpacked_bit = 1ULL << 63 };
2316 enum :
unsigned long long { has_named_args_bit = 1ULL << 62 };
2318 template <
typename It,
typename T,
typename Enable =
void>
2319 struct is_output_iterator : std::false_type {};
2321 template <>
struct is_output_iterator<appender, char> : std::true_type {};
2323 template <
typename It,
typename T>
2324 struct is_output_iterator<
2326 enable_if_t<std::is_assignable<decltype(*std::declval<decay_t<It>&>()++),
2327 T>::value>> : std::true_type {};
2329 template <
typename> constexpr
auto encode_types() ->
unsigned long long {
2333 template <
typename Context,
typename First,
typename... T>
2334 constexpr
auto encode_types() ->
unsigned long long {
2335 return static_cast<unsigned>(stored_type_constant<First, Context>::value) |
2336 (encode_types<Context, T...>() << packed_arg_bits);
2339 template <
typename Context,
typename... T,
size_t NUM_ARGS =
sizeof...(T)>
2340 constexpr
auto make_descriptor() ->
unsigned long long {
2341 return NUM_ARGS <= max_packed_args ? encode_types<Context, T...>()
2342 : is_unpacked_bit | NUM_ARGS;
2345 template <
typename Context,
int NUM_ARGS>
2346 using arg_t = conditional_t<NUM_ARGS <= max_packed_args, value<Context>,
2347 basic_format_arg<Context>>;
2349 template <
typename Context,
int NUM_ARGS,
int NUM_NAMED_ARGS,
2350 unsigned long long DESC>
2351 struct named_arg_store {
2353 arg_t<Context, NUM_ARGS> args[1u + NUM_ARGS];
2354 named_arg_info<typename Context::char_type>
2355 named_args[
static_cast<size_t>(NUM_NAMED_ARGS)];
2357 template <
typename... T>
2358 FMT_CONSTEXPR FMT_ALWAYS_INLINE named_arg_store(T&... values)
2359 : args{{named_args, NUM_NAMED_ARGS}, values...} {
2360 int arg_index = 0, named_arg_index = 0;
2362 init_named_arg(named_args, arg_index, named_arg_index, values));
2365 named_arg_store(named_arg_store&& rhs) {
2366 args[0] = {named_args, NUM_NAMED_ARGS};
2367 for (
size_t i = 1; i <
sizeof(args) /
sizeof(*args); ++i)
2368 args[i] = rhs.args[i];
2369 for (
size_t i = 0; i < NUM_NAMED_ARGS; ++i)
2370 named_args[i] = rhs.named_args[i];
2373 named_arg_store(
const named_arg_store& rhs) =
delete;
2374 auto operator=(
const named_arg_store& rhs) -> named_arg_store& =
delete;
2375 auto operator=(named_arg_store&& rhs) -> named_arg_store& =
delete;
2376 operator const arg_t<Context, NUM_ARGS>*()
const {
return args + 1; }
2382 template <
typename Context,
int NUM_ARGS,
int NUM_NAMED_ARGS,
2383 unsigned long long DESC>
2384 struct format_arg_store {
2387 conditional_t<NUM_NAMED_ARGS == 0,
2388 arg_t<Context, NUM_ARGS>[max_of<size_t>(1, NUM_ARGS)],
2389 named_arg_store<Context, NUM_ARGS, NUM_NAMED_ARGS, DESC>>;
2394 template <
typename T,
typename Char, type TYPE>
struct native_formatter {
2396 dynamic_format_specs<Char> specs_;
2399 using nonlocking = void;
2403 auto end = parse_format_specs(ctx.
begin(), ctx.
end(), specs_, ctx, TYPE);
2404 if (const_check(TYPE == type::char_type)) check_char_specs(specs_);
2408 template <type U = TYPE,
2409 FMT_ENABLE_IF(U == type::string_type || U == type::cstring_type ||
2410 U == type::char_type)>
2411 FMT_CONSTEXPR
void set_debug_format(
bool set =
true) {
2412 specs_.set_type(
set ? presentation_type::debug : presentation_type::none);
2415 FMT_PRAGMA_CLANG(diagnostic ignored
"-Wundefined-inline")
2416 template <
typename FormatContext>
2417 FMT_CONSTEXPR
auto format(
const T& val, FormatContext& ctx)
const 2418 -> decltype(ctx.out());
2421 template <
typename T,
typename Enable =
void>
2423 : bool_constant<mapped_type_constant<T>::value == type::custom_type> {};
2424 template <
typename T>
2425 struct locking<T, void_t<typename formatter<remove_cvref_t<T>>::nonlocking>>
2426 : std::false_type {};
2428 template <
typename T =
int> FMT_CONSTEXPR
inline auto is_locking() ->
bool {
2429 return locking<T>::value;
2431 template <
typename T1,
typename T2,
typename... Tail>
2432 FMT_CONSTEXPR
inline auto is_locking() ->
bool {
2433 return locking<T1>::value || is_locking<T2, Tail...>();
2437 locale_ref loc = {});
2441 #else // format_args is passed by reference since it is defined later. 2448 template <
typename Char>
2452 if (detail::is_constant_evaluated() && use_constexpr_cast) {
2453 auto ctx =
static_cast<detail::compile_parse_context<Char>*
>(
this);
2454 if (arg_id >= ctx->num_args()) report_error(
"argument not found");
2458 template <
typename Char>
2460 using detail::compile_parse_context;
2461 if (detail::is_constant_evaluated() && use_constexpr_cast)
2462 static_cast<compile_parse_context<Char>*
>(
this)->check_dynamic_spec(arg_id);
2469 template <
typename T>
class basic_appender {
2478 FMT_CONSTEXPR20
auto operator=(T c) -> basic_appender& {
2479 container->push_back(c);
2482 FMT_CONSTEXPR20
auto operator*() -> basic_appender& {
return *
this; }
2483 FMT_CONSTEXPR20
auto operator++() -> basic_appender& {
return *
this; }
2484 FMT_CONSTEXPR20
auto operator++(
int) -> basic_appender {
return *
this; }
2489 template <
typename Context>
class basic_format_arg {
2491 detail::value<Context> value_;
2496 using char_type =
typename Context::char_type;
2501 detail::custom_value<Context> custom_;
2504 explicit handle(detail::custom_value<Context> custom) : custom_(custom) {}
2507 custom_.format(custom_.value, parse_ctx, ctx);
2511 constexpr basic_format_arg() : type_(detail::type::none_type) {}
2512 basic_format_arg(
const detail::named_arg_info<char_type>* args,
size_t size)
2513 : value_(args, size) {}
2514 template <
typename T>
2515 basic_format_arg(T&& val)
2516 : value_(val), type_(detail::stored_type_constant<T, Context>::value) {}
2518 constexpr
explicit operator bool()
const noexcept {
2519 return type_ != detail::type::none_type;
2521 auto type()
const -> detail::type {
return type_; }
2528 template <
typename Visitor>
2529 FMT_CONSTEXPR FMT_INLINE
auto visit(Visitor&& vis)
const -> decltype(vis(0)) {
2532 case detail::type::none_type:
break;
2533 case detail::type::int_type:
return vis(value_.int_value);
2534 case detail::type::uint_type:
return vis(value_.uint_value);
2535 case detail::type::long_long_type:
return vis(value_.long_long_value);
2536 case detail::type::ulong_long_type:
return vis(value_.ulong_long_value);
2537 case detail::type::int128_type:
return vis(map(value_.int128_value));
2538 case detail::type::uint128_type:
return vis(map(value_.uint128_value));
2539 case detail::type::bool_type:
return vis(value_.bool_value);
2540 case detail::type::char_type:
return vis(value_.char_value);
2541 case detail::type::float_type:
return vis(value_.float_value);
2542 case detail::type::double_type:
return vis(value_.double_value);
2543 case detail::type::long_double_type:
return vis(value_.long_double_value);
2544 case detail::type::cstring_type:
return vis(value_.string.data);
2545 case detail::type::string_type:
return vis(value_.string.str());
2546 case detail::type::pointer_type:
return vis(value_.pointer);
2547 case detail::type::custom_type:
return vis(handle(value_.custom));
2549 return vis(monostate());
2552 auto format_custom(
const char_type* parse_begin,
2555 if (type_ != detail::type::custom_type)
return false;
2557 value_.custom.format(value_.custom.value, parse_ctx, ctx);
2576 unsigned long long desc_;
2583 const detail::value<Context>* values_;
2584 const basic_format_arg<Context>* args_;
2587 constexpr
auto is_packed()
const ->
bool {
2588 return (desc_ & detail::is_unpacked_bit) == 0;
2590 constexpr
auto has_named_args()
const ->
bool {
2591 return (desc_ & detail::has_named_args_bit) != 0;
2594 FMT_CONSTEXPR
auto type(
int index)
const -> detail::type {
2595 int shift = index * detail::packed_arg_bits;
2596 unsigned mask = (1 << detail::packed_arg_bits) - 1;
2597 return static_cast<detail::type
>((desc_ >> shift) & mask);
2600 template <
int NUM_ARGS,
int NUM_NAMED_ARGS,
unsigned long long DESC>
2602 detail::format_arg_store<Context, NUM_ARGS, NUM_NAMED_ARGS, DESC>;
2605 using format_arg = basic_format_arg<Context>;
2610 template <
int NUM_ARGS,
int NUM_NAMED_ARGS,
unsigned long long DESC,
2611 FMT_ENABLE_IF(NUM_ARGS <= detail::max_packed_args)>
2613 const store<NUM_ARGS, NUM_NAMED_ARGS, DESC>& s)
2614 : desc_(DESC | (NUM_NAMED_ARGS != 0 ? +
detail::has_named_args_bit : 0)),
2617 template <
int NUM_ARGS,
int NUM_NAMED_ARGS,
unsigned long long DESC,
2618 FMT_ENABLE_IF(NUM_ARGS > detail::max_packed_args)>
2619 constexpr basic_format_args(
const store<NUM_ARGS, NUM_NAMED_ARGS, DESC>& s)
2620 : desc_(DESC | (NUM_NAMED_ARGS != 0 ? +detail::has_named_args_bit : 0)),
2625 bool has_named =
false)
2626 : desc_(
detail::is_unpacked_bit |
detail::to_unsigned(count) |
2627 (has_named ? +
detail::has_named_args_bit : 0)),
2631 FMT_CONSTEXPR
auto get(
int id)
const -> format_arg {
2632 auto arg = format_arg();
2634 if (
id < max_size()) arg = args_[id];
2637 if (static_cast<unsigned>(
id) >= detail::max_packed_args)
return arg;
2638 arg.type_ = type(
id);
2639 if (arg.type_ != detail::type::none_type) arg.value_ = values_[id];
2643 template <
typename Char>
2645 int id = get_id(name);
2646 return id >= 0 ?
get(id) : format_arg();
2649 template <
typename Char>
2651 if (!has_named_args())
return -1;
2652 const auto& named_args =
2653 (is_packed() ? values_[-1] : args_[-1].value_).named_args;
2654 for (
size_t i = 0; i < named_args.size; ++i) {
2655 if (named_args.data[i].name == name)
return named_args.data[i].id;
2660 auto max_size()
const ->
int {
2661 unsigned long long max_packed = detail::max_packed_args;
2662 return static_cast<int>(is_packed() ? max_packed
2663 : desc_ & ~
detail::is_unpacked_bit);
2672 FMT_NO_UNIQUE_ADDRESS locale_ref loc_;
2675 using char_type = char;
2676 using iterator = appender;
2677 using format_arg = basic_format_arg<context>;
2678 enum { builtin_types = FMT_BUILTIN_TYPES };
2682 FMT_CONSTEXPR context(iterator out,
format_args args, locale_ref loc = {})
2683 : out_(out), args_(args), loc_(loc) {}
2684 context(context&&) =
default;
2685 context(
const context&) =
delete;
2686 void operator=(
const context&) =
delete;
2688 FMT_CONSTEXPR
auto arg(
int id)
const -> format_arg {
return args_.
get(
id); }
2689 inline auto arg(
string_view name)
const -> format_arg {
2690 return args_.
get(name);
2692 FMT_CONSTEXPR
auto arg_id(
string_view name)
const ->
int {
2693 return args_.get_id(name);
2695 auto args()
const ->
const format_args& {
return args_; }
2698 FMT_CONSTEXPR
auto out()
const -> iterator {
return out_; }
2701 FMT_CONSTEXPR
void advance_to(iterator) {}
2703 FMT_CONSTEXPR
auto locale()
const -> locale_ref {
return loc_; }
2706 template <
typename Char =
char>
struct runtime_format_string {
2718 inline auto runtime(
string_view s) -> runtime_format_string<> {
return {{s}}; }
2724 static constexpr
int num_static_named_args =
2725 detail::count_static_named_args<T...>();
2727 using checker = detail::format_string_checker<
2728 char,
static_cast<int>(
sizeof...(T)), num_static_named_args,
2729 num_static_named_args != detail::count_named_args<T...>()>;
2731 using arg_pack = detail::arg_pack<T...>;
2739 FMT_CONSTEVAL FMT_ALWAYS_INLINE
fstring(
const char (&s)[N]) : str(s, N - 1) {
2741 static_assert(count<(is_view<remove_cvref_t<T>>::value &&
2742 std::is_reference<T>::value)...>() == 0,
2743 "passing views as lvalues is disallowed");
2744 if (FMT_USE_CONSTEVAL) parse_format_string<char>(s, checker(s, arg_pack()));
2745 #ifdef FMT_ENFORCE_COMPILE_STRING 2747 FMT_USE_CONSTEVAL &&
sizeof(s) != 0,
2748 "FMT_ENFORCE_COMPILE_STRING requires format strings to use FMT_STRING");
2751 template <
typename S,
2752 FMT_ENABLE_IF(std::is_convertible<const S&, string_view>::value)>
2753 FMT_CONSTEVAL FMT_ALWAYS_INLINE fstring(
const S& s) : str(s) {
2755 if (FMT_USE_CONSTEVAL)
2756 detail::parse_format_string<char>(sv, checker(sv, arg_pack()));
2757 #ifdef FMT_ENFORCE_COMPILE_STRING 2759 FMT_USE_CONSTEVAL &&
sizeof(s) != 0,
2760 "FMT_ENFORCE_COMPILE_STRING requires format strings to use FMT_STRING");
2763 template <
typename S,
2764 FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
2765 std::is_same<typename S::char_type, char>::value)>
2766 FMT_ALWAYS_INLINE fstring(
const S&) : str(S()) {
2768 FMT_CONSTEXPR
int unused =
2769 (parse_format_string(sv, checker(sv, arg_pack())), 0);
2770 detail::ignore_unused(unused);
2772 fstring(runtime_format_string<> fmt) : str(fmt.str) {}
2775 FMT_ALWAYS_INLINE
operator const string_view&()
const {
return str; }
2779 template <
typename... T>
using format_string =
typename fstring<T...>
::t;
2781 template <
typename T,
typename Char =
char>
2782 using is_formattable = bool_constant<!std::is_same<
2783 detail::mapped_t<conditional_t<std::is_void<T>::value,
int*, T>, Char>,
2785 #ifdef __cpp_concepts 2786 template <
typename T,
typename Char =
char>
2787 concept formattable = is_formattable<remove_reference_t<T>, Char>::value;
2791 template <
typename T,
typename Char>
2792 struct formatter<T, Char,
2793 enable_if_t<detail::type_constant<T, Char>::value !=
2794 detail::type::custom_type>>
2795 : detail::native_formatter<T, Char, detail::type_constant<T, Char>::value> {
2805 template <
typename Context = context,
typename... T,
2806 int NUM_ARGS =
sizeof...(T),
2807 int NUM_NAMED_ARGS = detail::count_named_args<T...>(),
2808 unsigned long long DESC = detail::make_descriptor<Context, T...>()>
2809 constexpr FMT_ALWAYS_INLINE
auto make_format_args(T&... args)
2810 -> detail::format_arg_store<Context, NUM_ARGS, NUM_NAMED_ARGS, DESC> {
2812 FMT_PRAGMA_GCC(diagnostic ignored
"-Wconversion")
2816 template <
typename... T>
2818 detail::format_arg_store<context,
sizeof...(T),
2819 detail::count_named_args<T...>(),
2820 detail::make_descriptor<context, T...>()>;
2830 template <
typename Char,
typename T>
2831 inline auto arg(
const Char* name,
const T& arg) -> detail::named_arg<Char, T> {
2836 template <
typename OutputIt,
2837 FMT_ENABLE_IF(detail::is_output_iterator<remove_cvref_t<OutputIt>,
2840 -> remove_cvref_t<OutputIt> {
2841 auto&& buf = detail::get_buffer<char>(out);
2842 detail::vformat_to(buf, fmt, args, {});
2843 return detail::get_iterator(buf, out);
2856 template <
typename OutputIt,
typename... T,
2857 FMT_ENABLE_IF(detail::is_output_iterator<remove_cvref_t<OutputIt>,
2859 FMT_INLINE
auto format_to(OutputIt&& out, format_string<T...> fmt, T&&... args)
2860 -> remove_cvref_t<OutputIt> {
2861 return vformat_to(out, fmt.str, vargs<T...>{{args...}});
2864 template <
typename OutputIt>
struct format_to_n_result {
2871 template <
typename OutputIt,
typename... T,
2872 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
2874 -> format_to_n_result<OutputIt> {
2875 using traits = detail::fixed_buffer_traits;
2876 auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
2877 detail::vformat_to(buf, fmt, args, {});
2878 return {buf.out(), buf.count()};
2887 template <
typename OutputIt,
typename... T,
2888 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
2889 FMT_INLINE
auto format_to_n(OutputIt out,
size_t n, format_string<T...> fmt,
2890 T&&... args) -> format_to_n_result<OutputIt> {
2891 return vformat_to_n(out, n, fmt.str, vargs<T...>{{args...}});
2894 struct format_to_result {
2900 FMT_CONSTEXPR
operator char*()
const {
2902 if (truncated) report_error(
"output is truncated");
2909 -> format_to_result {
2910 auto result = vformat_to_n(out, N, fmt, args);
2911 return {result.out, result.size > N};
2914 template <
size_t N,
typename... T>
2915 FMT_INLINE
auto format_to(
char (&out)[N], format_string<T...> fmt, T&&... args)
2916 -> format_to_result {
2917 auto result = vformat_to_n(out, N, fmt.str, vargs<T...>{{args...}});
2918 return {result.out, result.size > N};
2922 template <
typename... T>
2923 FMT_NODISCARD FMT_INLINE
auto formatted_size(format_string<T...> fmt,
2924 T&&... args) ->
size_t {
2925 auto buf = detail::counting_buffer<>();
2926 detail::vformat_to(buf, fmt.str, vargs<T...>{{args...}}, {});
2943 template <
typename... T>
2944 FMT_INLINE
void print(format_string<T...> fmt, T&&... args) {
2945 vargs<T...> va = {{args...}};
2946 if (detail::const_check(!detail::use_utf8))
2947 return detail::vprint_mojibake(stdout, fmt.str, va,
false);
2948 return detail::is_locking<T...>() ? vprint_buffered(stdout, fmt.str, va)
2949 : vprint(fmt.str, va);
2960 template <
typename... T>
2961 FMT_INLINE
void print(FILE* f, format_string<T...> fmt, T&&... args) {
2962 vargs<T...> va = {{args...}};
2963 if (detail::const_check(!detail::use_utf8))
2964 return detail::vprint_mojibake(f, fmt.str, va,
false);
2965 return detail::is_locking<T...>() ? vprint_buffered(f, fmt.str, va)
2966 : vprint(f, fmt.str, va);
2971 template <
typename... T>
2972 FMT_INLINE
void println(FILE* f, format_string<T...> fmt, T&&... args) {
2973 vargs<T...> va = {{args...}};
2974 return detail::const_check(detail::use_utf8)
2975 ? vprintln(f, fmt.str, va)
2976 : detail::vprint_mojibake(f, fmt.str, va,
true);
2981 template <
typename... T>
2982 FMT_INLINE
void println(format_string<T...> fmt, T&&... args) {
2983 return fmt::println(stdout, fmt, static_cast<T&&>(args)...);
2986 FMT_PRAGMA_CLANG(diagnostic pop)
2987 FMT_PRAGMA_GCC(pop_options)
2991 #ifdef FMT_HEADER_ONLY 2992 # include "format.h" 2994 #endif // FMT_BASE_H_ FMT_CONSTEXPR void check_arg_id(int id)
Reports an error if using the automatic argument indexing; otherwise switches to the manual indexing...
Definition: base.h:893
A compile-time format string. Use format_string in the public API to prevent type deduction...
Definition: base.h:2722
FMT_CONSTEXPR basic_string_view(const S &s) noexcept
Constructs a string view from a std::basic_string or a std::basic_string_view object.
Definition: base.h:553
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition: base.h:623
FMT_CONSTEXPR auto next_arg_id() -> int
Reports an error if using the manual argument indexing; otherwise returns the next argument index and...
Definition: base.h:881
constexpr auto data() const noexcept -> const Char *
Returns a pointer to the string data.
Definition: base.h:557
FMT_CONSTEXPR void clear()
Clears this buffer.
Definition: base.h:1815
constexpr auto size() const noexcept -> size_t
Returns the string size.
Definition: base.h:560
Converts a string literal into a format string that will be parsed at compile time and converted into...
Definition: args.h:20
An implementation of std::basic_string_view for pre-C++17.
Definition: base.h:515
constexpr auto end() const noexcept -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition: base.h:872
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition: base.h:1805
typename V::value_type char_t
String's character (code unit) type. detail:: is intentional to prevent ADL.
Definition: base.h:973
FMT_CONSTEXPR20 void append(const U *begin, const U *end)
Appends data to the end of the buffer.
Definition: base.h:1845
FMT_ALWAYS_INLINE FMT_CONSTEXPR20 basic_string_view(const Char *s)
Constructs a string view object from a C string.
Definition: base.h:536
constexpr auto capacity() const noexcept -> size_t
Returns the capacity of this buffer.
Definition: base.h:1808
constexpr basic_string_view(const Char *s, size_t count) noexcept
Constructs a string view object from a C string and a size.
Definition: base.h:527
FMT_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition: base.h:1811
constexpr auto begin() const noexcept -> iterator
Returns an iterator to the beginning of the format string range being parsed.
Definition: base.h:869
bool next(BasicCoordinate< num_dimensions, int > &indices, const Array< num_dimensions2, T > &a)
Given an index into an array, increment it to the next one.
Definition: array_index_functions.inl:107
A contiguous memory buffer with an optional growing ability. It is an internal class and shouldn't be...
Definition: base.h:1763
FMT_CONSTEXPR void advance_to(iterator it)
Advances the begin iterator to it.
Definition: base.h:875