17 #include <type_traits> 20 #define FMT_VERSION 80101 22 #if defined(__clang__) && !defined(__ibmxl__) 23 # define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) 25 # define FMT_CLANG_VERSION 0 28 #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && \ 29 !defined(__NVCOMPILER) 30 # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) 32 # define FMT_GCC_VERSION 0 35 #ifndef FMT_GCC_PRAGMA 37 # if FMT_GCC_VERSION >= 504 38 # define FMT_GCC_PRAGMA(arg) _Pragma(arg) 40 # define FMT_GCC_PRAGMA(arg) 45 # define FMT_ICC_VERSION __ICL 46 #elif defined(__INTEL_COMPILER) 47 # define FMT_ICC_VERSION __INTEL_COMPILER 49 # define FMT_ICC_VERSION 0 53 # define FMT_NVCC __NVCC__ 59 # define FMT_MSC_VER _MSC_VER 60 # define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) 62 # define FMT_MSC_VER 0 63 # define FMT_MSC_WARNING(...) 67 # define FMT_HAS_FEATURE(x) __has_feature(x) 69 # define FMT_HAS_FEATURE(x) 0 72 #if defined(__has_include) && \ 73 (!defined(__INTELLISENSE__) || FMT_MSC_VER > 1900) && \ 74 (!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600) 75 # define FMT_HAS_INCLUDE(x) __has_include(x) 77 # define FMT_HAS_INCLUDE(x) 0 80 #ifdef __has_cpp_attribute 81 # define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) 83 # define FMT_HAS_CPP_ATTRIBUTE(x) 0 87 # define FMT_CPLUSPLUS _MSVC_LANG 89 # define FMT_CPLUSPLUS __cplusplus 92 #define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ 93 (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) 95 #define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ 96 (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) 100 #ifndef FMT_USE_CONSTEXPR 101 # define FMT_USE_CONSTEXPR \ 102 (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1912 || \ 103 (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \ 104 !FMT_NVCC && !FMT_ICC_VERSION 106 #if FMT_USE_CONSTEXPR 107 # define FMT_CONSTEXPR constexpr 108 # define FMT_CONSTEXPR_DECL constexpr 110 # define FMT_CONSTEXPR 111 # define FMT_CONSTEXPR_DECL 114 #if ((__cplusplus >= 202002L) && \ 115 (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 9)) || \ 116 (__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002) 117 # define FMT_CONSTEXPR20 constexpr 119 # define FMT_CONSTEXPR20 123 #if defined(__GLIBCXX__) 124 # if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \ 125 _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE. 126 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr 128 #elif defined(_LIBCPP_VERSION) && __cplusplus >= 201703L && \ 129 _LIBCPP_VERSION >= 4000 130 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr 131 #elif FMT_MSC_VER >= 1914 && _MSVC_LANG >= 201703L 132 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr 134 #ifndef FMT_CONSTEXPR_CHAR_TRAITS 135 # define FMT_CONSTEXPR_CHAR_TRAITS 139 #ifndef FMT_EXCEPTIONS 140 # if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ 141 FMT_MSC_VER && !_HAS_EXCEPTIONS 142 # define FMT_EXCEPTIONS 0 144 # define FMT_EXCEPTIONS 1 149 #ifndef FMT_USE_NOEXCEPT 150 # define FMT_USE_NOEXCEPT 0 153 #if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ 154 FMT_GCC_VERSION >= 408 || FMT_MSC_VER >= 1900 155 # define FMT_DETECTED_NOEXCEPT noexcept 156 # define FMT_HAS_CXX11_NOEXCEPT 1 158 # define FMT_DETECTED_NOEXCEPT throw() 159 # define FMT_HAS_CXX11_NOEXCEPT 0 163 # if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT 164 # define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT 166 # define FMT_NOEXCEPT 172 #if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \ 174 # define FMT_NORETURN [[noreturn]] 176 # define FMT_NORETURN 179 #if __cplusplus == 201103L || __cplusplus == 201402L 180 # if defined(__INTEL_COMPILER) || defined(__PGI) 181 # define FMT_FALLTHROUGH 182 # elif defined(__clang__) 183 # define FMT_FALLTHROUGH [[clang::fallthrough]] 184 # elif FMT_GCC_VERSION >= 700 && \ 185 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) 186 # define FMT_FALLTHROUGH [[gnu::fallthrough]] 188 # define FMT_FALLTHROUGH 190 #elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) 191 # define FMT_FALLTHROUGH [[fallthrough]] 193 # define FMT_FALLTHROUGH 196 #ifndef FMT_NODISCARD 197 # if FMT_HAS_CPP17_ATTRIBUTE(nodiscard) 198 # define FMT_NODISCARD [[nodiscard]] 200 # define FMT_NODISCARD 204 #ifndef FMT_USE_FLOAT 205 # define FMT_USE_FLOAT 1 207 #ifndef FMT_USE_DOUBLE 208 # define FMT_USE_DOUBLE 1 210 #ifndef FMT_USE_LONG_DOUBLE 211 # define FMT_USE_LONG_DOUBLE 1 215 # if FMT_GCC_VERSION || FMT_CLANG_VERSION 216 # define FMT_INLINE inline __attribute__((always_inline)) 218 # define FMT_INLINE inline 222 #ifndef FMT_DEPRECATED 223 # if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900 224 # define FMT_DEPRECATED [[deprecated]] 226 # if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) 227 # define FMT_DEPRECATED __attribute__((deprecated)) 229 # define FMT_DEPRECATED __declspec(deprecated) 231 # define FMT_DEPRECATED 236 #ifndef FMT_BEGIN_NAMESPACE 237 # define FMT_BEGIN_NAMESPACE \ 239 inline namespace v8 { 240 # define FMT_END_NAMESPACE \ 245 #ifndef FMT_MODULE_EXPORT 246 # define FMT_MODULE_EXPORT 247 # define FMT_MODULE_EXPORT_BEGIN 248 # define FMT_MODULE_EXPORT_END 249 # define FMT_BEGIN_DETAIL_NAMESPACE namespace detail { 250 # define FMT_END_DETAIL_NAMESPACE } 253 #if !defined(FMT_HEADER_ONLY) && defined(_WIN32) 254 # define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275) 256 # define FMT_API __declspec(dllexport) 257 # elif defined(FMT_SHARED) 258 # define FMT_API __declspec(dllimport) 261 # define FMT_CLASS_API 262 # if defined(FMT_EXPORT) || defined(FMT_SHARED) 263 # if defined(__GNUC__) || defined(__clang__) 264 # define FMT_API __attribute__((visibility("default"))) 273 #if (FMT_HAS_INCLUDE(<string_view>) && \ 274 (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ 275 (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) 276 # include <string_view> 277 # define FMT_USE_STRING_VIEW 278 #elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L 279 # include <experimental/string_view> 280 # define FMT_USE_EXPERIMENTAL_STRING_VIEW 284 # define FMT_UNICODE !FMT_MSC_VER 287 #ifndef FMT_CONSTEVAL 288 # if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \ 289 __cplusplus > 201703L && !defined(__apple_build_version__)) || \ 290 (defined(__cpp_consteval) && \ 291 (!FMT_MSC_VER || _MSC_FULL_VER >= 193030704)) 293 # define FMT_CONSTEVAL consteval 294 # define FMT_HAS_CONSTEVAL 296 # define FMT_CONSTEVAL 300 #ifndef FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 301 # if defined(__cpp_nontype_template_args) && \ 302 ((FMT_GCC_VERSION >= 903 && __cplusplus >= 201709L) || \ 303 __cpp_nontype_template_args >= 201911L) 304 # define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 1 306 # define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0 311 FMT_GCC_PRAGMA(
"GCC push_options")
313 FMT_GCC_PRAGMA(
"GCC optimize(\"Og\")")
317 FMT_MODULE_EXPORT_BEGIN
320 template <
bool B,
typename T =
void>
321 using enable_if_t =
typename std::enable_if<B, T>::type;
322 template <
bool B,
typename T,
typename F>
323 using conditional_t =
typename std::conditional<B, T, F>::type;
324 template <
bool B>
using bool_constant = std::integral_constant<bool, B>;
325 template <
typename T>
326 using remove_reference_t =
typename std::remove_reference<T>::type;
327 template <
typename T>
328 using remove_const_t =
typename std::remove_const<T>::type;
329 template <
typename T>
330 using remove_cvref_t =
typename std::remove_cv<remove_reference_t<T>>::type;
332 template <
typename T>
using type_identity_t =
typename type_identity<T>::type;
342 # define FMT_ENABLE_IF(...) 344 # define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0 347 FMT_BEGIN_DETAIL_NAMESPACE
352 template <
typename... T> FMT_CONSTEXPR
void ignore_unused(
const T&...) {}
354 constexpr FMT_INLINE
auto is_constant_evaluated(
bool default_value =
false)
355 FMT_NOEXCEPT ->
bool {
356 #ifdef __cpp_lib_is_constant_evaluated 357 ignore_unused(default_value);
358 return std::is_constant_evaluated();
360 return default_value;
365 template <
typename T> constexpr FMT_INLINE
auto const_check(T
value) -> T {
369 FMT_NORETURN FMT_API
void assert_fail(
const char* file,
int line,
370 const char* message);
375 # define FMT_ASSERT(condition, message) \ 376 ::fmt::detail::ignore_unused((condition), (message)) 378 # define FMT_ASSERT(condition, message) \ 381 : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message))) 385 #ifdef __cpp_lib_byte 386 using byte = std::byte;
388 enum class byte : unsigned char {};
391 #if defined(FMT_USE_STRING_VIEW) 392 template <
typename Char>
using std_string_view = std::basic_string_view<Char>;
393 #elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) 394 template <
typename Char>
400 #ifdef FMT_USE_INT128 402 #elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \ 403 !(FMT_CLANG_VERSION && FMT_MSC_VER) 404 # define FMT_USE_INT128 1 405 using int128_t = __int128_t;
406 using uint128_t = __uint128_t;
407 template <
typename T>
inline auto convert_for_visit(T value) -> T {
411 # define FMT_USE_INT128 0 414 enum class int128_t {};
415 enum class uint128_t {};
417 template <
typename T>
inline auto convert_for_visit(T) ->
monostate {
423 template <
typename Int>
424 FMT_CONSTEXPR
auto to_unsigned(Int value) ->
425 typename std::make_unsigned<Int>::type {
426 FMT_ASSERT(value >= 0,
"negative value");
427 return static_cast<typename std::make_unsigned<Int>::type
>(value);
430 FMT_MSC_WARNING(suppress : 4566) constexpr
unsigned char micro[] =
"\u00B5";
432 constexpr
auto is_utf8() ->
bool {
435 using uchar =
unsigned char;
436 return FMT_UNICODE || (
sizeof(micro) == 3 && uchar(micro[0]) == 0xC2 &&
437 uchar(micro[1]) == 0xB5);
439 FMT_END_DETAIL_NAMESPACE
454 using value_type = Char;
455 using iterator =
const Char*;
470 FMT_CONSTEXPR_CHAR_TRAITS
474 size_(
detail::const_check(
std::is_same<Char, char>::value &&
475 !
detail::is_constant_evaluated(true))
476 ?
std::strlen(reinterpret_cast<const char*>(s))
477 :
std::char_traits<Char>::length(s)) {}
480 template <
typename Traits,
typename Alloc>
482 const std::basic_string<Char, Traits, Alloc>& s) FMT_NOEXCEPT
486 template <
typename S, FMT_ENABLE_IF(std::is_same<
487 S, detail::std_string_view<Char>>::value)>
492 constexpr
auto data() const FMT_NOEXCEPT -> const Char* {
return data_; }
495 constexpr
auto size() const FMT_NOEXCEPT ->
size_t {
return size_; }
497 constexpr
auto begin()
const FMT_NOEXCEPT -> iterator {
return data_; }
498 constexpr
auto end()
const FMT_NOEXCEPT -> iterator {
return data_ + size_; }
500 constexpr
auto operator[](
size_t pos)
const FMT_NOEXCEPT ->
const Char& {
504 FMT_CONSTEXPR
void remove_prefix(
size_t n) FMT_NOEXCEPT {
511 size_t str_size = size_ < other.size_ ? size_ : other.size_;
512 int result = std::char_traits<Char>::compare(data_, other.data_, str_size);
514 result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
521 return lhs.compare(rhs) == 0;
524 return lhs.compare(rhs) != 0;
527 return lhs.compare(rhs) < 0;
530 return lhs.compare(rhs) <= 0;
533 return lhs.compare(rhs) > 0;
536 return lhs.compare(rhs) >= 0;
543 template <
typename T>
struct is_char : std::false_type {};
544 template <>
struct is_char<char> : std::true_type {};
547 template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
551 template <
typename Char,
typename Traits,
typename Alloc>
552 inline auto to_string_view(
const std::basic_string<Char, Traits, Alloc>& s)
556 template <
typename Char>
561 template <
typename Char,
562 FMT_ENABLE_IF(!std::is_empty<detail::std_string_view<Char>>::value)>
563 inline auto to_string_view(detail::std_string_view<Char> s)
572 template <
typename S>
575 template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
576 constexpr
auto to_string_view(
const S& s)
581 FMT_BEGIN_DETAIL_NAMESPACE
583 void to_string_view(...);
584 using fmt::to_string_view;
589 template <
typename S>
590 struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> {
595 using result = decltype(to_string_view(std::declval<S>()));
596 using type =
typename result::value_type;
601 FMT_INLINE
void check_format_string(
const S&) {
602 #ifdef FMT_ENFORCE_COMPILE_STRING 604 "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " 609 void check_format_string(S);
611 FMT_NORETURN FMT_API
void throw_format_error(
const char* message);
618 FMT_NORETURN FMT_API
void on_error(
const char* message);
620 FMT_END_DETAIL_NAMESPACE
623 template <
typename S>
using char_t =
typename detail::char_t_impl<S>::type;
632 template <
typename Char,
typename ErrorHandler = detail::error_handler>
639 using char_type = Char;
640 using iterator =
typename basic_string_view<Char>::iterator;
645 : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {}
651 constexpr
auto begin() const FMT_NOEXCEPT -> iterator {
652 return format_str_.begin();
658 constexpr
auto end() const FMT_NOEXCEPT -> iterator {
659 return format_str_.end();
664 format_str_.remove_prefix(detail::to_unsigned(it - begin()));
674 if (next_arg_id_ >= 0)
return next_arg_id_++;
675 on_error(
"cannot switch from manual to automatic argument indexing");
684 if (next_arg_id_ > 0)
685 on_error(
"cannot switch from automatic to manual argument indexing");
692 FMT_CONSTEXPR
void on_error(
const char* message) {
693 ErrorHandler::on_error(message);
696 constexpr
auto error_handler()
const -> ErrorHandler {
return *
this; }
706 template <
typename T,
typename Char =
char,
typename Enable =
void>
714 template <
typename T,
typename Context>
715 using has_formatter =
716 std::is_constructible<typename Context::template formatter_type<T>>;
720 template <
typename Char>
725 FMT_BEGIN_DETAIL_NAMESPACE
727 template <
typename Context,
typename T>
728 constexpr
auto has_const_formatter_impl(T*)
729 -> decltype(
typename Context::template formatter_type<T>().format(
730 std::declval<const T&>(), std::declval<Context&>()),
734 template <
typename Context>
735 constexpr
auto has_const_formatter_impl(...) ->
bool {
738 template <
typename T,
typename Context>
739 constexpr
auto has_const_formatter() ->
bool {
740 return has_const_formatter_impl<Context>(
static_cast<T*
>(
nullptr));
744 template <
typename Container>
745 inline auto get_container(std::back_insert_iterator<Container> it)
747 using bi_iterator = std::back_insert_iterator<Container>;
748 struct accessor : bi_iterator {
749 accessor(bi_iterator iter) : bi_iterator(iter) {}
750 using bi_iterator::container;
752 return *accessor(it).container;
755 template <
typename Char,
typename InputIt,
typename OutputIt>
756 FMT_CONSTEXPR
auto copy_str(InputIt begin, InputIt end, OutputIt out)
758 while (begin != end) *out++ =
static_cast<Char
>(*begin++);
762 template <
typename Char,
typename T,
typename U,
765 FMT_CONSTEXPR
auto copy_str(T* begin, T* end, U* out) -> U* {
766 if (is_constant_evaluated())
return copy_str<Char, T*, U*>(begin, end, out);
767 auto size = to_unsigned(end - begin);
768 memcpy(out, begin, size *
sizeof(U));
786 FMT_MSC_WARNING(suppress : 26495)
787 buffer(
size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}
789 FMT_CONSTEXPR20
buffer(T* p =
nullptr,
size_t sz = 0,
790 size_t cap = 0) FMT_NOEXCEPT : ptr_(p),
794 FMT_CONSTEXPR20 ~
buffer() =
default;
798 FMT_CONSTEXPR
void set(T* buf_data,
size_t buf_capacity) FMT_NOEXCEPT {
800 capacity_ = buf_capacity;
804 virtual FMT_CONSTEXPR20
void grow(
size_t capacity) = 0;
807 using value_type = T;
808 using const_reference =
const T&;
811 void operator=(
const buffer&) =
delete;
813 auto begin() FMT_NOEXCEPT -> T* {
return ptr_; }
814 auto end() FMT_NOEXCEPT -> T* {
return ptr_ + size_; }
816 auto begin()
const FMT_NOEXCEPT ->
const T* {
return ptr_; }
817 auto end()
const FMT_NOEXCEPT ->
const T* {
return ptr_ + size_; }
820 constexpr
auto size() const FMT_NOEXCEPT ->
size_t {
return size_; }
823 constexpr
auto capacity() const FMT_NOEXCEPT ->
size_t {
return capacity_; }
826 FMT_CONSTEXPR
auto data() FMT_NOEXCEPT -> T* {
return ptr_; }
829 FMT_CONSTEXPR
auto data() const FMT_NOEXCEPT -> const T* {
return ptr_; }
836 FMT_CONSTEXPR20
void try_resize(
size_t count) {
838 size_ = count <= capacity_ ? count : capacity_;
845 FMT_CONSTEXPR20
void try_reserve(
size_t new_capacity) {
846 if (new_capacity > capacity_) grow(new_capacity);
849 FMT_CONSTEXPR20
void push_back(
const T& value) {
850 try_reserve(size_ + 1);
851 ptr_[size_++] = value;
855 template <
typename U>
void append(
const U* begin,
const U* end);
857 template <
typename I> FMT_CONSTEXPR
auto operator[](I index) -> T& {
860 template <
typename I>
861 FMT_CONSTEXPR
auto operator[](I index)
const ->
const T& {
868 auto count()
const ->
size_t {
return 0; }
869 auto limit(
size_t size) ->
size_t {
return size; }
879 auto count()
const ->
size_t {
return count_; }
880 auto limit(
size_t size) ->
size_t {
881 size_t n = limit_ > count_ ? limit_ - count_ : 0;
883 return size < n ? size : n;
888 template <
typename OutputIt,
typename T,
typename Traits = buffer_traits>
892 enum { buffer_size = 256 };
893 T data_[buffer_size];
896 FMT_CONSTEXPR20
void grow(
size_t)
override {
897 if (this->size() == buffer_size) flush();
901 auto size = this->size();
903 out_ = copy_str<T>(data_, data_ + this->limit(size), out_);
908 : Traits(n),
buffer<T>(data_, 0, buffer_size), out_(out) {}
910 : Traits(other),
buffer<T>(data_, 0, buffer_size), out_(other.out_) {}
913 auto out() -> OutputIt {
917 auto count()
const ->
size_t {
return Traits::count() + this->size(); }
920 template <
typename T>
926 enum { buffer_size = 256 };
927 T data_[buffer_size];
930 FMT_CONSTEXPR20
void grow(
size_t)
override {
935 size_t n = this->limit(this->
size());
936 if (this->
data() == out_) {
938 this->
set(data_, buffer_size);
950 if (this->
data() != out_) {
951 this->
set(data_, buffer_size);
961 auto count()
const ->
size_t {
962 return fixed_buffer_traits::count() + this->
size();
968 FMT_CONSTEXPR20
void grow(
size_t)
override {}
973 auto out() -> T* {
return &*this->end(); }
977 template <
typename Container>
979 enable_if_t<is_contiguous<Container>::value,
980 typename Container::value_type>>
981 final :
public buffer<typename Container::value_type> {
983 Container& container_;
986 FMT_CONSTEXPR20
void grow(
size_t capacity)
override {
987 container_.resize(capacity);
988 this->
set(&container_[0], capacity);
994 explicit iterator_buffer(std::back_insert_iterator<Container> out,
size_t = 0)
996 auto out() -> std::back_insert_iterator<Container> {
997 return std::back_inserter(container_);
1004 enum { buffer_size = 256 };
1005 T data_[buffer_size];
1009 FMT_CONSTEXPR20
void grow(
size_t)
override {
1010 if (this->size() != buffer_size)
return;
1011 count_ += this->size();
1018 auto count() ->
size_t {
return count_ + this->size(); }
1021 template <
typename T>
1022 using buffer_appender = conditional_t<std::is_same<T, char>::value,
appender,
1023 std::back_insert_iterator<buffer<T>>>;
1026 template <
typename T,
typename OutputIt>
1031 template <
typename Buffer>
1032 auto get_iterator(Buffer& buf) -> decltype(buf.out()) {
1035 template <
typename T>
auto get_iterator(
buffer<T>& buf) -> buffer_appender<T> {
1036 return buffer_appender<T>(buf);
1039 template <
typename T,
typename Char =
char,
typename Enable =
void>
1045 template <
typename T,
typename Char>
1046 using has_fallback_formatter =
1047 std::is_constructible<fallback_formatter<T, Char>>;
1054 named_arg(
const Char* n,
const T& v) : name(n), value(v) {}
1062 template <
typename T,
typename Char,
size_t NUM_ARGS,
size_t NUM_NAMED_ARGS>
1066 T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)];
1069 template <
typename... U>
1070 arg_data(
const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {}
1071 arg_data(
const arg_data& other) =
delete;
1072 auto args()
const ->
const T* {
return args_ + 1; }
1076 template <
typename T,
typename Char,
size_t NUM_ARGS>
1079 T args_[NUM_ARGS != 0 ? NUM_ARGS : +1];
1081 template <
typename... U>
1082 FMT_CONSTEXPR FMT_INLINE
arg_data(
const U&... init) : args_{init...} {}
1083 FMT_CONSTEXPR FMT_INLINE
auto args()
const ->
const T* {
return args_; }
1084 FMT_CONSTEXPR FMT_INLINE
auto named_args() -> std::nullptr_t {
1089 template <
typename Char>
1095 template <
typename T,
typename Char>
1098 template <
typename Char,
typename T,
typename... Tail,
1101 int named_arg_count,
const T&,
const Tail&... args) {
1102 init_named_args(named_args, arg_count + 1, named_arg_count, args...);
1105 template <
typename Char,
typename T,
typename... Tail,
1108 int named_arg_count,
const T& arg,
const Tail&... args) {
1109 named_args[named_arg_count++] = {arg.name, arg_count};
1110 init_named_args(named_args, arg_count + 1, named_arg_count, args...);
1113 template <
typename... Args>
1114 FMT_CONSTEXPR FMT_INLINE
void init_named_args(std::nullptr_t,
int,
int,
1117 template <
bool B = false> constexpr
auto count() ->
size_t {
return B ? 1 : 0; }
1118 template <
bool B1,
bool B2,
bool... Tail> constexpr
auto count() ->
size_t {
1119 return (B1 ? 1 : 0) + count<B2, Tail...>();
1122 template <
typename... Args> constexpr
auto count_named_args() ->
size_t {
1123 return count<is_named_arg<Args>::value...>();
1126 template <
typename... Args>
1127 constexpr
auto count_statically_named_args() ->
size_t {
1128 return count<is_statically_named_arg<Args>::value...>();
1142 last_integer_type = char_type,
1147 last_numeric_type = long_double_type,
1155 template <
typename T,
typename Char>
1158 #define FMT_TYPE_CONSTANT(Type, constant) \ 1159 template <typename Char> \ 1160 struct type_constant<Type, Char> \ 1161 : std::integral_constant<type, type::constant> {} 1163 FMT_TYPE_CONSTANT(
int, int_type);
1164 FMT_TYPE_CONSTANT(
unsigned, uint_type);
1165 FMT_TYPE_CONSTANT(
long long, long_long_type);
1166 FMT_TYPE_CONSTANT(
unsigned long long, ulong_long_type);
1167 FMT_TYPE_CONSTANT(int128_t, int128_type);
1168 FMT_TYPE_CONSTANT(uint128_t, uint128_type);
1169 FMT_TYPE_CONSTANT(
bool, bool_type);
1170 FMT_TYPE_CONSTANT(Char, char_type);
1171 FMT_TYPE_CONSTANT(
float, float_type);
1172 FMT_TYPE_CONSTANT(
double, double_type);
1173 FMT_TYPE_CONSTANT(
long double, long_double_type);
1174 FMT_TYPE_CONSTANT(
const Char*, cstring_type);
1176 FMT_TYPE_CONSTANT(
const void*, pointer_type);
1178 constexpr
bool is_integral_type(type t) {
1179 return t > type::none_type && t <= type::last_integer_type;
1182 constexpr
bool is_arithmetic_type(type t) {
1183 return t > type::none_type && t <= type::last_numeric_type;
1202 using parse_context =
typename Context::parse_context_type;
1204 void (*format)(
void* arg, parse_context& parse_ctx, Context& ctx);
1208 template <
typename Context>
class value {
1210 using char_type =
typename Context::char_type;
1215 unsigned uint_value;
1216 long long long_long_value;
1217 unsigned long long ulong_long_value;
1218 int128_t int128_value;
1219 uint128_t uint128_value;
1221 char_type char_value;
1223 double double_value;
1224 long double long_double_value;
1225 const void* pointer;
1231 constexpr FMT_INLINE value() : no_value() {}
1232 constexpr FMT_INLINE value(
int val) : int_value(val) {}
1233 constexpr FMT_INLINE value(
unsigned val) : uint_value(val) {}
1234 constexpr FMT_INLINE value(
long long val) : long_long_value(val) {}
1235 constexpr FMT_INLINE value(
unsigned long long val) : ulong_long_value(val) {}
1236 FMT_INLINE value(int128_t val) : int128_value(val) {}
1237 FMT_INLINE value(uint128_t val) : uint128_value(val) {}
1238 constexpr FMT_INLINE value(
float val) : float_value(val) {}
1239 constexpr FMT_INLINE value(
double val) : double_value(val) {}
1240 FMT_INLINE value(
long double val) : long_double_value(val) {}
1241 constexpr FMT_INLINE value(
bool val) : bool_value(val) {}
1242 constexpr FMT_INLINE value(char_type val) : char_value(val) {}
1243 FMT_CONSTEXPR FMT_INLINE value(
const char_type* val) {
1245 if (is_constant_evaluated())
string.size = {};
1248 string.data = val.
data();
1249 string.size = val.
size();
1251 FMT_INLINE value(
const void* val) : pointer(val) {}
1253 : named_args{args, size} {}
1255 template <
typename T> FMT_CONSTEXPR FMT_INLINE value(T& val) {
1256 using value_type = remove_cvref_t<T>;
1257 custom.value =
const_cast<value_type*
>(&val);
1261 custom.format = format_custom_arg<
1263 conditional_t<has_formatter<value_type, Context>::value,
1264 typename Context::template formatter_type<value_type>,
1274 template <
typename T,
typename Formatter>
1275 static void format_custom_arg(
void* arg,
1276 typename Context::parse_context_type& parse_ctx,
1278 auto f = Formatter();
1279 parse_ctx.advance_to(f.parse(parse_ctx));
1280 using qualified_type =
1281 conditional_t<has_const_formatter<T, Context>(),
const T, T>;
1282 ctx.advance_to(f.format(*static_cast<qualified_type*>(arg), ctx));
1286 template <
typename Context,
typename T>
1291 enum { long_short =
sizeof(long) ==
sizeof(
int) };
1292 using long_type = conditional_t<long_short, int, long long>;
1293 using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
1299 using char_type =
typename Context::char_type;
1301 FMT_CONSTEXPR FMT_INLINE
auto map(
signed char val) ->
int {
return val; }
1302 FMT_CONSTEXPR FMT_INLINE
auto map(
unsigned char val) ->
unsigned {
1305 FMT_CONSTEXPR FMT_INLINE
auto map(
short val) ->
int {
return val; }
1306 FMT_CONSTEXPR FMT_INLINE
auto map(
unsigned short val) ->
unsigned {
1309 FMT_CONSTEXPR FMT_INLINE
auto map(
int val) ->
int {
return val; }
1310 FMT_CONSTEXPR FMT_INLINE
auto map(
unsigned val) ->
unsigned {
return val; }
1311 FMT_CONSTEXPR FMT_INLINE
auto map(
long val) -> long_type {
return val; }
1312 FMT_CONSTEXPR FMT_INLINE
auto map(
unsigned long val) -> ulong_type {
1315 FMT_CONSTEXPR FMT_INLINE
auto map(
long long val) ->
long long {
return val; }
1316 FMT_CONSTEXPR FMT_INLINE
auto map(
unsigned long long val)
1317 ->
unsigned long long {
1320 FMT_CONSTEXPR FMT_INLINE
auto map(int128_t val) -> int128_t {
return val; }
1321 FMT_CONSTEXPR FMT_INLINE
auto map(uint128_t val) -> uint128_t {
return val; }
1322 FMT_CONSTEXPR FMT_INLINE
auto map(
bool val) ->
bool {
return val; }
1324 template <typename T, FMT_ENABLE_IF(std::is_same<T, char>::value ||
1325 std::is_same<T, char_type>::value)>
1326 FMT_CONSTEXPR FMT_INLINE
auto map(T val) -> char_type {
1329 template <typename T, enable_if_t<(std::is_same<T, wchar_t>::value ||
1330 #ifdef __cpp_char8_t 1331 std::is_same<T, char8_t>::value ||
1333 std::is_same<T, char16_t>::value ||
1334 std::is_same<T, char32_t>::value) &&
1335 !std::is_same<T, char_type>::value,
1341 FMT_CONSTEXPR FMT_INLINE
auto map(
float val) ->
float {
return val; }
1342 FMT_CONSTEXPR FMT_INLINE
auto map(
double val) ->
double {
return val; }
1343 FMT_CONSTEXPR FMT_INLINE
auto map(
long double val) ->
long double {
1347 FMT_CONSTEXPR FMT_INLINE
auto map(char_type* val) ->
const char_type* {
1350 FMT_CONSTEXPR FMT_INLINE
auto map(
const char_type* val) ->
const char_type* {
1353 template <
typename T,
1355 std::is_same<char_type, char_t<T>>::value)>
1356 FMT_CONSTEXPR FMT_INLINE
auto map(
const T& val)
1358 return to_string_view(val);
1360 template <
typename T,
1362 !std::is_same<char_type, char_t<T>>::value)>
1366 template <
typename T,
1370 !has_fallback_formatter<T, char_type>::value)>
1371 FMT_CONSTEXPR FMT_INLINE
auto map(
const T& val)
1381 !has_fallback_formatter<T, char_type>::value)>
1382 FMT_CONSTEXPR FMT_INLINE
auto map(
const T& val)
1387 using cstring_result = conditional_t<std::is_same<char_type, char>::value,
1390 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE
auto map(
const signed char* val)
1392 return map(reinterpret_cast<const char*>(val));
1394 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE
auto map(
const unsigned char* val)
1396 return map(reinterpret_cast<const char*>(val));
1398 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE
auto map(
signed char* val)
1400 return map(reinterpret_cast<const char*>(val));
1402 FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE
auto map(
unsigned char* val)
1404 return map(reinterpret_cast<const char*>(val));
1407 FMT_CONSTEXPR FMT_INLINE
auto map(
void* val) ->
const void* {
return val; }
1408 FMT_CONSTEXPR FMT_INLINE
auto map(
const void* val) ->
const void* {
1411 FMT_CONSTEXPR FMT_INLINE
auto map(std::nullptr_t val) ->
const void* {
1420 std::is_member_pointer<T>::value ||
1421 std::is_function<
typename std::remove_pointer<T>::type>::value ||
1422 (std::is_convertible<const T&, const void*>::value &&
1423 !std::is_convertible<const T&, const char_type*>::value))>
1424 FMT_CONSTEXPR
auto map(
const T&) -> unformattable_pointer {
1428 template <
typename T, std::size_t N,
1429 FMT_ENABLE_IF(!std::is_same<T, wchar_t>::value)>
1430 FMT_CONSTEXPR FMT_INLINE
auto map(
const T (&values)[N]) ->
const T (&)[N] {
1434 template <
typename T,
1436 std::is_enum<T>::value&& std::is_convertible<T, int>::value &&
1437 !has_formatter<T, Context>::value &&
1438 !has_fallback_formatter<T, char_type>::value)>
1439 FMT_CONSTEXPR FMT_INLINE
auto map(
const T& val)
1440 -> decltype(std::declval<arg_mapper>().map(
1441 static_cast<typename std::underlying_type<T>::type
>(val))) {
1442 return map(
static_cast<typename std::underlying_type<T>::type
>(val));
1445 FMT_CONSTEXPR FMT_INLINE
auto map(detail::byte val) ->
unsigned {
1446 return map(static_cast<unsigned char>(val));
1449 template <
typename T,
typename U = remove_cvref_t<T>>
1451 : bool_constant<has_const_formatter<U, Context>() ||
1452 !std::is_const<remove_reference_t<T>>::value ||
1453 has_fallback_formatter<U, char_type>::value> {};
1455 #if FMT_MSC_VER != 0 && FMT_MSC_VER < 1910 1457 template <
typename T> FMT_CONSTEXPR FMT_INLINE
auto do_map(T&& val) -> T& {
1461 template <typename T, FMT_ENABLE_IF(formattable<T>::value)>
1462 FMT_CONSTEXPR FMT_INLINE
auto do_map(T&& val) -> T& {
1465 template <typename T, FMT_ENABLE_IF(!formattable<T>::value)>
1471 template <
typename T,
typename U = remove_cvref_t<T>,
1472 FMT_ENABLE_IF(!is_
string<U>::value && !is_
char<U>::value &&
1473 !std::is_array<U>::value &&
1474 (has_formatter<U, Context>::value ||
1475 has_fallback_formatter<U,
char_type>::value))>
1476 FMT_CONSTEXPR FMT_INLINE
auto map(T&& val)
1477 -> decltype(this->do_map(std::forward<T>(val))) {
1478 return do_map(std::forward<T>(val));
1481 template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
1482 FMT_CONSTEXPR FMT_INLINE
auto map(
const T&
named_arg)
1483 -> decltype(std::declval<arg_mapper>().map(named_arg.value)) {
1484 return map(named_arg.value);
1491 template <
typename T,
typename Context>
1494 typename Context::char_type>;
1496 enum { packed_arg_bits = 4 };
1498 enum { max_packed_args = 62 / packed_arg_bits };
1499 enum :
unsigned long long { is_unpacked_bit = 1ULL << 63 };
1500 enum :
unsigned long long { has_named_args_bit = 1ULL << 62 };
1502 FMT_END_DETAIL_NAMESPACE
1506 class appender :
public std::back_insert_iterator<detail::buffer<char>> {
1507 using base = std::back_insert_iterator<detail::buffer<char>>;
1509 template <
typename T>
1510 friend auto get_buffer(appender out) -> detail::buffer<char>& {
1511 return detail::get_container(out);
1515 using std::back_insert_iterator<detail::buffer<char>>::back_insert_iterator;
1516 appender(base it) FMT_NOEXCEPT : base(it) {}
1519 auto operator++() FMT_NOEXCEPT -> appender& {
return *
this; }
1521 auto operator++(
int) FMT_NOEXCEPT -> appender {
return *
this; }
1528 detail::value<Context> value_;
1531 template <
typename ContextType,
typename T>
1532 friend FMT_CONSTEXPR
auto detail::make_arg(
const T& value)
1535 template <
typename Visitor,
typename Ctx>
1536 friend FMT_CONSTEXPR
auto visit_format_arg(Visitor&& vis,
1538 -> decltype(vis(0));
1543 using char_type =
typename Context::char_type;
1545 template <
typename T,
typename Char,
size_t NUM_ARGS,
size_t NUM_NAMED_ARGS>
1546 friend struct detail::arg_data;
1548 basic_format_arg(
const detail::named_arg_info<char_type>* args,
size_t size)
1549 : value_(args, size) {}
1554 explicit handle(detail::custom_value<Context> custom) : custom_(custom) {}
1556 void format(
typename Context::parse_context_type& parse_ctx,
1557 Context& ctx)
const {
1558 custom_.format(custom_.value, parse_ctx, ctx);
1562 detail::custom_value<Context> custom_;
1565 constexpr basic_format_arg() : type_(detail::type::none_type) {}
1567 constexpr
explicit operator bool()
const FMT_NOEXCEPT {
1568 return type_ != detail::type::none_type;
1571 auto type()
const -> detail::type {
return type_; }
1573 auto is_integral()
const ->
bool {
return detail::is_integral_type(type_); }
1574 auto is_arithmetic()
const ->
bool {
1575 return detail::is_arithmetic_type(type_);
1586 template <
typename Visitor,
typename Context>
1587 FMT_CONSTEXPR FMT_INLINE
auto visit_format_arg(
1589 switch (arg.type_) {
1590 case detail::type::none_type:
1592 case detail::type::int_type:
1593 return vis(arg.value_.int_value);
1594 case detail::type::uint_type:
1595 return vis(arg.value_.uint_value);
1596 case detail::type::long_long_type:
1597 return vis(arg.value_.long_long_value);
1598 case detail::type::ulong_long_type:
1599 return vis(arg.value_.ulong_long_value);
1600 case detail::type::int128_type:
1601 return vis(detail::convert_for_visit(arg.value_.int128_value));
1602 case detail::type::uint128_type:
1603 return vis(detail::convert_for_visit(arg.value_.uint128_value));
1604 case detail::type::bool_type:
1605 return vis(arg.value_.bool_value);
1606 case detail::type::char_type:
1607 return vis(arg.value_.char_value);
1608 case detail::type::float_type:
1609 return vis(arg.value_.float_value);
1610 case detail::type::double_type:
1611 return vis(arg.value_.double_value);
1612 case detail::type::long_double_type:
1613 return vis(arg.value_.long_double_value);
1614 case detail::type::cstring_type:
1615 return vis(arg.value_.string.data);
1616 case detail::type::string_type:
1618 return vis(sv(arg.value_.string.data, arg.value_.string.size));
1619 case detail::type::pointer_type:
1620 return vis(arg.value_.pointer);
1621 case detail::type::custom_type:
1627 FMT_BEGIN_DETAIL_NAMESPACE
1629 template <
typename Char,
typename InputIt>
1630 auto copy_str(InputIt begin, InputIt end, appender out) -> appender {
1631 get_container(out).append(begin, end);
1635 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 1637 template <
typename... Ts>
struct void_t_impl {
using type = void; };
1638 template <
typename... Ts>
1639 using void_t =
typename detail::void_t_impl<Ts...>::type;
1641 template <
typename...>
using void_t = void;
1644 template <
typename It,
typename T,
typename Enable =
void>
1647 template <
typename It,
typename T>
1650 void_t<typename std::iterator_traits<It>::iterator_category,
1651 decltype(*std::declval<It>() = std::declval<T>())>>
1652 : std::true_type {};
1654 template <
typename OutputIt>
1656 template <
typename Container>
1658 : std::true_type {};
1660 template <
typename OutputIt>
1662 template <
typename Container>
1671 const void* locale_;
1675 template <
typename Locale>
explicit locale_ref(
const Locale& loc);
1677 explicit operator bool()
const FMT_NOEXCEPT {
return locale_ !=
nullptr; }
1679 template <
typename Locale>
auto get()
const -> Locale;
1682 template <
typename> constexpr
auto encode_types() ->
unsigned long long {
1686 template <
typename Context,
typename Arg,
typename... Args>
1687 constexpr
auto encode_types() ->
unsigned long long {
1689 (encode_types<Context, Args...>() << packed_arg_bits);
1692 template <
typename Context,
typename T>
1703 template <
bool IS_PACKED,
typename Context, type,
typename T,
1704 FMT_ENABLE_IF(IS_PACKED)>
1705 FMT_CONSTEXPR FMT_INLINE
auto make_arg(T&& val) ->
value<Context> {
1708 constexpr
bool formattable_char =
1709 !std::is_same<decltype(arg), const unformattable_char&>::value;
1710 static_assert(formattable_char,
"Mixing character types is disallowed.");
1712 constexpr
bool formattable_const =
1713 !std::is_same<decltype(arg), const unformattable_const&>::value;
1714 static_assert(formattable_const,
"Cannot format a const argument.");
1720 constexpr
bool formattable_pointer =
1721 !std::is_same<decltype(arg), const unformattable_pointer&>::value;
1722 static_assert(formattable_pointer,
1723 "Formatting of non-void pointers is disallowed.");
1725 constexpr
bool formattable =
1726 !std::is_same<decltype(arg), const unformattable&>::value;
1729 "Cannot format an argument. To make type T formattable provide a " 1730 "formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
1734 template <
bool IS_PACKED,
typename Context, type,
typename T,
1735 FMT_ENABLE_IF(!IS_PACKED)>
1737 return make_arg<Context>(value);
1739 FMT_END_DETAIL_NAMESPACE
1750 detail::locale_ref loc_;
1753 using iterator = OutputIt;
1767 detail::locale_ref loc = detail::locale_ref())
1768 : out_(out), args_(ctx_args), loc_(loc) {}
1770 constexpr
auto arg(
int id)
const ->
format_arg {
return args_.
get(
id); }
1772 return args_.
get(name);
1775 return args_.get_id(name);
1781 FMT_CONSTEXPR
auto error_handler() -> detail::error_handler {
return {}; }
1782 void on_error(
const char* message) {
error_handler().on_error(message); }
1785 FMT_CONSTEXPR
auto out() -> iterator {
return out_; }
1788 void advance_to(iterator it) {
1789 if (!detail::is_back_insert_iterator<iterator>()) out_ = it;
1792 FMT_CONSTEXPR
auto locale() -> detail::locale_ref {
return loc_; }
1795 template <
typename Char>
1801 #define FMT_BUFFER_CONTEXT(Char) \ 1802 basic_format_context<detail::buffer_appender<Char>, Char> 1804 template <
typename T,
typename Char =
char>
1805 using is_formattable = bool_constant<
1806 !std::is_base_of<detail::unformattable,
1808 std::declval<T>()))>
::value &&
1809 !detail::has_fallback_formatter<T, Char>::value>;
1818 template <
typename Context,
typename... Args>
1820 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1826 static const size_t num_args =
sizeof...(Args);
1827 static const size_t num_named_args = detail::count_named_args<Args...>();
1828 static const bool is_packed = num_args <= detail::max_packed_args;
1830 using value_type = conditional_t<is_packed, detail::value<Context>,
1833 detail::arg_data<value_type,
typename Context::char_type, num_args,
1839 static constexpr
unsigned long long desc =
1840 (is_packed ? detail::encode_types<Context, Args...>()
1841 : detail::is_unpacked_bit | num_args) |
1842 (num_named_args != 0
1843 ?
static_cast<unsigned long long>(detail::has_named_args_bit)
1847 template <
typename... T>
1850 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 1853 data_{detail::make_arg<
1855 detail::mapped_type_constant<remove_cvref_t<T>, Context>
::value>(
1856 std::forward<T>(args))...} {
1857 detail::init_named_args(data_.named_args(), 0, 0, args...);
1870 constexpr
auto make_format_args(Args&&... args)
1872 return {std::forward<Args>(args)...};
1886 template <
typename Char,
typename T>
1887 inline auto arg(
const Char* name,
const T& arg) -> detail::named_arg<Char, T> {
1888 static_assert(!detail::is_named_arg<T>(),
"nested named arguments");
1904 using size_type = int;
1912 unsigned long long desc_;
1919 const detail::value<Context>* values_;
1920 const format_arg* args_;
1923 constexpr
auto is_packed()
const ->
bool {
1924 return (desc_ & detail::is_unpacked_bit) == 0;
1926 auto has_named_args()
const ->
bool {
1927 return (desc_ & detail::has_named_args_bit) != 0;
1930 FMT_CONSTEXPR
auto type(
int index)
const -> detail::type {
1931 int shift = index * detail::packed_arg_bits;
1932 unsigned int mask = (1 << detail::packed_arg_bits) - 1;
1933 return static_cast<detail::type
>((desc_ >> shift) & mask);
1937 const detail::value<Context>* values)
1938 : desc_(desc), values_(values) {}
1939 constexpr basic_format_args(
unsigned long long desc,
const format_arg* args)
1940 : desc_(desc), args_(args) {}
1943 constexpr basic_format_args() : desc_(0), args_(
nullptr) {}
1950 template <
typename... Args>
1954 store.data_.args()) {}
1964 : basic_format_args(store.get_types(), store.data()) {}
1972 : basic_format_args(
detail::is_unpacked_bit |
detail::to_unsigned(count),
1979 if (
id < max_size()) arg = args_[
id];
1982 if (
id >= detail::max_packed_args)
return arg;
1983 arg.type_ = type(
id);
1984 if (arg.type_ == detail::type::none_type)
return arg;
1985 arg.value_ = values_[id];
1989 template <
typename Char>
1991 int id = get_id(name);
1995 template <
typename Char>
1997 if (!has_named_args())
return -1;
1998 const auto& named_args =
1999 (is_packed() ? values_[-1] : args_[-1].value_).named_args;
2000 for (
size_t i = 0; i < named_args.size; ++i) {
2001 if (named_args.data[i].name == name)
return named_args.data[i].id;
2006 auto max_size()
const ->
int {
2007 unsigned long long max_packed = detail::max_packed_args;
2008 return static_cast<int>(is_packed() ? max_packed
2009 : desc_ & ~
detail::is_unpacked_bit);
2021 enum type { none, left, right, center, numeric };
2023 using align_t = align::type;
2025 enum type { none, minus, plus, space };
2027 using sign_t = sign::type;
2029 FMT_BEGIN_DETAIL_NAMESPACE
2034 enum { max_size = 4 };
2035 Char data_[max_size] = {Char(
' '), Char(0), Char(0), Char(0)};
2036 unsigned char size_ = 1;
2040 auto size = s.
size();
2041 if (size > max_size)
return throw_format_error(
"invalid fill");
2042 for (
size_t i = 0; i < size; ++i) data_[i] = s[i];
2043 size_ =
static_cast<unsigned char>(size);
2046 constexpr
auto size()
const ->
size_t {
return size_; }
2047 constexpr
auto data()
const ->
const Char* {
return data_; }
2049 FMT_CONSTEXPR
auto operator[](
size_t index) -> Char& {
return data_[index]; }
2050 FMT_CONSTEXPR
auto operator[](
size_t index)
const ->
const Char& {
2051 return data_[index];
2054 FMT_END_DETAIL_NAMESPACE
2056 enum class presentation_type : unsigned char {
2082 presentation_type type;
2087 detail::fill_t<Char> fill;
2092 type(presentation_type::none),
2101 FMT_BEGIN_DETAIL_NAMESPACE
2103 enum class arg_id_kind { none, index, name };
2107 FMT_CONSTEXPR
arg_ref() : kind(arg_id_kind::none), val() {}
2109 FMT_CONSTEXPR
explicit arg_ref(
int index)
2110 : kind(arg_id_kind::index), val(index) {}
2112 : kind(arg_id_kind::name), val(name) {}
2114 FMT_CONSTEXPR
auto operator=(
int idx) -> arg_ref& {
2115 kind = arg_id_kind::index;
2122 FMT_CONSTEXPR value(
int id = 0) : index{
id} {}
2133 template <
typename Char>
2150 FMT_CONSTEXPR specs_setter(
const specs_setter& other)
2151 : specs_(other.specs_) {}
2153 FMT_CONSTEXPR
void on_align(align_t
align) { specs_.align = align; }
2157 FMT_CONSTEXPR
void on_sign(sign_t s) { specs_.sign = s; }
2158 FMT_CONSTEXPR
void on_hash() { specs_.alt =
true; }
2159 FMT_CONSTEXPR
void on_localized() { specs_.localized =
true; }
2161 FMT_CONSTEXPR
void on_zero() {
2162 if (specs_.align == align::none) specs_.align = align::numeric;
2163 specs_.fill[0] = Char(
'0');
2166 FMT_CONSTEXPR
void on_width(
int width) { specs_.width = width; }
2167 FMT_CONSTEXPR
void on_precision(
int precision) {
2168 specs_.precision = precision;
2170 FMT_CONSTEXPR
void end_precision() {}
2172 FMT_CONSTEXPR
void on_type(presentation_type type) { specs_.type = type; }
2177 template <
typename ParseContext>
2179 :
public specs_setter<typename ParseContext::char_type> {
2181 using char_type =
typename ParseContext::char_type;
2187 FMT_CONSTEXPR dynamic_specs_handler(
const dynamic_specs_handler& other)
2189 specs_(other.specs_),
2190 context_(other.context_) {}
2192 template <
typename Id> FMT_CONSTEXPR
void on_dynamic_width(Id arg_id) {
2193 specs_.width_ref = make_arg_ref(arg_id);
2196 template <
typename Id> FMT_CONSTEXPR
void on_dynamic_precision(Id arg_id) {
2197 specs_.precision_ref = make_arg_ref(arg_id);
2200 FMT_CONSTEXPR
void on_error(
const char* message) {
2201 context_.on_error(message);
2206 ParseContext& context_;
2210 FMT_CONSTEXPR
auto make_arg_ref(
int arg_id) ->
arg_ref_type {
2211 context_.check_arg_id(arg_id);
2221 context_.check_arg_id(arg_id);
2223 context_.begin(), to_unsigned(context_.end() - context_.begin()));
2228 template <
typename Char> constexpr
bool is_ascii_letter(Char c) {
2229 return (c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z');
2233 template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
2234 constexpr
auto to_ascii(Char value) -> Char {
2237 template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
2238 constexpr
auto to_ascii(Char value) ->
2239 typename std::underlying_type<Char>::type {
2243 template <
typename Char>
2244 FMT_CONSTEXPR
auto code_point_length(
const Char* begin) ->
int {
2245 if (const_check(
sizeof(Char) != 1))
return 1;
2247 "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4";
2248 int len = lengths[
static_cast<unsigned char>(*begin) >> 3];
2257 template <
bool IS_CONSTEXPR,
typename T,
typename Ptr = const T*>
2258 FMT_CONSTEXPR
auto find(Ptr first, Ptr last, T value, Ptr& out) ->
bool {
2259 for (out = first; out != last; ++out) {
2260 if (*out == value)
return true;
2266 inline auto find<false, char>(
const char* first,
const char* last,
char value,
2267 const char*& out) ->
bool {
2268 out =
static_cast<const char*
>(
2269 std::memchr(first, value, to_unsigned(last - first)));
2270 return out !=
nullptr;
2275 template <
typename Char>
2276 FMT_CONSTEXPR
auto parse_nonnegative_int(
const Char*& begin,
const Char* end,
2277 int error_value) noexcept ->
int {
2278 FMT_ASSERT(begin != end &&
'0' <= *begin && *begin <=
'9',
"");
2279 unsigned value = 0, prev = 0;
2283 value = value * 10 + unsigned(*p -
'0');
2285 }
while (p != end &&
'0' <= *p && *p <=
'9');
2286 auto num_digits = p - begin;
2288 if (num_digits <= std::numeric_limits<int>::digits10)
2289 return static_cast<int>(value);
2291 const unsigned max = to_unsigned((std::numeric_limits<int>::max)());
2292 return num_digits == std::numeric_limits<int>::digits10 + 1 &&
2293 prev * 10ull + unsigned(p[-1] -
'0') <= max
2294 ?
static_cast<int>(value)
2299 template <
typename Char,
typename Handler>
2300 FMT_CONSTEXPR
auto parse_align(
const Char* begin,
const Char* end,
2301 Handler&& handler) ->
const Char* {
2302 FMT_ASSERT(begin != end,
"");
2303 auto align = align::none;
2304 auto p = begin + code_point_length(begin);
2305 if (p >= end) p = begin;
2307 switch (to_ascii(*p)) {
2309 align = align::left;
2312 align = align::right;
2315 align = align::center;
2320 if (
align != align::none) {
2324 return handler.on_error(
"invalid fill character '{'"), begin;
2329 handler.on_align(
align);
2331 }
else if (p == begin) {
2339 template <
typename Char> FMT_CONSTEXPR
bool is_name_start(Char c) {
2340 return (
'a' <= c && c <=
'z') || (
'A' <= c && c <=
'Z') ||
'_' == c;
2343 template <
typename Char,
typename IDHandler>
2344 FMT_CONSTEXPR
auto do_parse_arg_id(
const Char* begin,
const Char* end,
2345 IDHandler&& handler) ->
const Char* {
2346 FMT_ASSERT(begin != end,
"");
2348 if (c >=
'0' && c <=
'9') {
2352 parse_nonnegative_int(begin, end, (std::numeric_limits<int>::max)());
2355 if (begin == end || (*begin !=
'}' && *begin !=
':'))
2356 handler.on_error(
"invalid format string");
2361 if (!is_name_start(c)) {
2362 handler.on_error(
"invalid format string");
2368 }
while (it != end && (is_name_start(c = *it) || (
'0' <= c && c <=
'9')));
2373 template <
typename Char,
typename IDHandler>
2374 FMT_CONSTEXPR FMT_INLINE
auto parse_arg_id(
const Char* begin,
const Char* end,
2375 IDHandler&& handler) ->
const Char* {
2377 if (c !=
'}' && c !=
':')
return do_parse_arg_id(begin, end, handler);
2382 template <
typename Char,
typename Handler>
2383 FMT_CONSTEXPR
auto parse_width(
const Char* begin,
const Char* end,
2384 Handler&& handler) ->
const Char* {
2385 using detail::auto_id;
2386 struct width_adapter {
2389 FMT_CONSTEXPR
void operator()() { handler.on_dynamic_width(
auto_id()); }
2390 FMT_CONSTEXPR
void operator()(
int id) { handler.on_dynamic_width(
id); }
2392 handler.on_dynamic_width(
id);
2394 FMT_CONSTEXPR
void on_error(
const char* message) {
2395 if (message) handler.on_error(message);
2399 FMT_ASSERT(begin != end,
"");
2400 if (
'0' <= *begin && *begin <=
'9') {
2401 int width = parse_nonnegative_int(begin, end, -1);
2403 handler.on_width(width);
2405 handler.on_error(
"number is too big");
2406 }
else if (*begin ==
'{') {
2408 if (begin != end) begin = parse_arg_id(begin, end, width_adapter{handler});
2409 if (begin == end || *begin !=
'}')
2410 return handler.on_error(
"invalid format string"), begin;
2416 template <
typename Char,
typename Handler>
2417 FMT_CONSTEXPR
auto parse_precision(
const Char* begin,
const Char* end,
2418 Handler&& handler) ->
const Char* {
2419 using detail::auto_id;
2420 struct precision_adapter {
2423 FMT_CONSTEXPR
void operator()() { handler.on_dynamic_precision(
auto_id()); }
2424 FMT_CONSTEXPR
void operator()(
int id) { handler.on_dynamic_precision(
id); }
2426 handler.on_dynamic_precision(
id);
2428 FMT_CONSTEXPR
void on_error(
const char* message) {
2429 if (message) handler.on_error(message);
2434 auto c = begin != end ? *begin : Char();
2435 if (
'0' <= c && c <=
'9') {
2436 auto precision = parse_nonnegative_int(begin, end, -1);
2437 if (precision != -1)
2438 handler.on_precision(precision);
2440 handler.on_error(
"number is too big");
2441 }
else if (c ==
'{') {
2444 begin = parse_arg_id(begin, end, precision_adapter{handler});
2445 if (begin == end || *begin++ !=
'}')
2446 return handler.on_error(
"invalid format string"), begin;
2448 return handler.on_error(
"missing precision specifier"), begin;
2450 handler.end_precision();
2454 template <
typename Char>
2455 FMT_CONSTEXPR
auto parse_presentation_type(Char type) -> presentation_type {
2456 switch (to_ascii(type)) {
2458 return presentation_type::dec;
2460 return presentation_type::oct;
2462 return presentation_type::hex_lower;
2464 return presentation_type::hex_upper;
2466 return presentation_type::bin_lower;
2468 return presentation_type::bin_upper;
2470 return presentation_type::hexfloat_lower;
2472 return presentation_type::hexfloat_upper;
2474 return presentation_type::exp_lower;
2476 return presentation_type::exp_upper;
2478 return presentation_type::fixed_lower;
2480 return presentation_type::fixed_upper;
2482 return presentation_type::general_lower;
2484 return presentation_type::general_upper;
2486 return presentation_type::chr;
2488 return presentation_type::string;
2490 return presentation_type::pointer;
2492 return presentation_type::none;
2498 template <
typename Char,
typename SpecHandler>
2499 FMT_CONSTEXPR FMT_INLINE
auto parse_format_specs(
const Char* begin,
2501 SpecHandler&& handler)
2503 if (1 < end - begin && begin[1] ==
'}' && is_ascii_letter(*begin) &&
2505 presentation_type type = parse_presentation_type(*begin++);
2506 if (type == presentation_type::none)
2507 handler.on_error(
"invalid type specifier");
2508 handler.on_type(type);
2512 if (begin == end)
return begin;
2514 begin = parse_align(begin, end, handler);
2515 if (begin == end)
return begin;
2518 switch (to_ascii(*begin)) {
2520 handler.on_sign(sign::plus);
2524 handler.on_sign(sign::minus);
2528 handler.on_sign(sign::space);
2534 if (begin == end)
return begin;
2536 if (*begin ==
'#') {
2538 if (++begin == end)
return begin;
2542 if (*begin ==
'0') {
2544 if (++begin == end)
return begin;
2547 begin = parse_width(begin, end, handler);
2548 if (begin == end)
return begin;
2551 if (*begin ==
'.') {
2552 begin = parse_precision(begin, end, handler);
2553 if (begin == end)
return begin;
2556 if (*begin ==
'L') {
2557 handler.on_localized();
2562 if (begin != end && *begin !=
'}') {
2563 presentation_type type = parse_presentation_type(*begin++);
2564 if (type == presentation_type::none)
2565 handler.on_error(
"invalid type specifier");
2566 handler.on_type(type);
2571 template <
typename Char,
typename Handler>
2572 FMT_CONSTEXPR
auto parse_replacement_field(
const Char* begin,
const Char* end,
2573 Handler&& handler) ->
const Char* {
2578 FMT_CONSTEXPR
void operator()() { arg_id = handler.on_arg_id(); }
2579 FMT_CONSTEXPR
void operator()(
int id) { arg_id = handler.on_arg_id(
id); }
2581 arg_id = handler.on_arg_id(
id);
2583 FMT_CONSTEXPR
void on_error(
const char* message) {
2584 if (message) handler.on_error(message);
2589 if (begin == end)
return handler.on_error(
"invalid format string"), end;
2590 if (*begin ==
'}') {
2591 handler.on_replacement_field(handler.on_arg_id(), begin);
2592 }
else if (*begin ==
'{') {
2593 handler.on_text(begin, begin + 1);
2595 auto adapter = id_adapter{handler, 0};
2596 begin = parse_arg_id(begin, end, adapter);
2597 Char c = begin != end ? *begin : Char();
2599 handler.on_replacement_field(adapter.arg_id, begin);
2600 }
else if (c ==
':') {
2601 begin = handler.on_format_specs(adapter.arg_id, begin + 1, end);
2602 if (begin == end || *begin !=
'}')
2603 return handler.on_error(
"unknown format specifier"), end;
2605 return handler.on_error(
"missing '}' in format string"), end;
2611 template <
bool IS_CONSTEXPR,
typename Char,
typename Handler>
2612 FMT_CONSTEXPR FMT_INLINE
void parse_format_string(
2617 auto begin = format_str.
data();
2618 auto end = begin + format_str.
size();
2619 if (end - begin < 32) {
2621 const Char* p = begin;
2625 handler.on_text(begin, p - 1);
2626 begin = p = parse_replacement_field(p - 1, end, handler);
2627 }
else if (c ==
'}') {
2628 if (p == end || *p !=
'}')
2629 return handler.on_error(
"unmatched '}' in format string");
2630 handler.on_text(begin, p);
2634 handler.on_text(begin, end);
2638 FMT_CONSTEXPR
void operator()(
const Char* pbegin,
const Char* pend) {
2639 if (pbegin == pend)
return;
2641 const Char* p =
nullptr;
2642 if (!find<IS_CONSTEXPR>(pbegin, pend, Char(
'}'), p))
2643 return handler_.on_text(pbegin, pend);
2645 if (p == pend || *p !=
'}')
2646 return handler_.on_error(
"unmatched '}' in format string");
2647 handler_.on_text(pbegin, p);
2653 while (begin != end) {
2656 const Char* p = begin;
2657 if (*begin !=
'{' && !find<IS_CONSTEXPR>(begin + 1, end, Char(
'{'), p))
2658 return write(begin, end);
2660 begin = parse_replacement_field(p, end, handler);
2664 template <
typename T,
typename ParseContext>
2665 FMT_CONSTEXPR
auto parse_format_specs(ParseContext& ctx)
2666 -> decltype(ctx.begin()) {
2667 using char_type =
typename ParseContext::char_type;
2669 using mapped_type = conditional_t<
2672 auto f = conditional_t<has_formatter<mapped_type, context>::value,
2675 return f.parse(ctx);
2682 template <
typename Char,
typename ErrorHandler = error_handler>
2692 int num_args = (std::numeric_limits<int>::max)(), ErrorHandler eh = {})
2693 :
base(format_str, eh), num_args_(num_args) {}
2695 FMT_CONSTEXPR
auto next_arg_id() ->
int {
2696 int id = base::next_arg_id();
2697 if (
id >= num_args_) this->on_error(
"argument not found");
2701 FMT_CONSTEXPR
void check_arg_id(
int id) {
2702 base::check_arg_id(
id);
2703 if (
id >= num_args_) this->on_error(
"argument not found");
2705 using base::check_arg_id;
2708 template <
typename ErrorHandler>
2709 FMT_CONSTEXPR
void check_int_type_spec(presentation_type type,
2710 ErrorHandler&& eh) {
2711 if (type > presentation_type::bin_upper && type != presentation_type::chr)
2712 eh.on_error(
"invalid type specifier");
2716 template <
typename Char,
typename ErrorHandler = error_handler>
2718 ErrorHandler&& eh = {}) ->
bool {
2719 if (specs.type != presentation_type::none &&
2720 specs.type != presentation_type::chr) {
2721 check_int_type_spec(specs.type, eh);
2724 if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
2725 eh.on_error(
"invalid format specifier for char");
2730 enum class float_format : unsigned char {
2739 float_format format : 8;
2748 template <
typename ErrorHandler = error_handler,
typename Char>
2750 ErrorHandler&& eh = {})
2753 result.showpoint = specs.alt;
2754 result.locale = specs.localized;
2755 switch (specs.type) {
2756 case presentation_type::none:
2757 result.format = float_format::general;
2759 case presentation_type::general_upper:
2760 result.upper =
true;
2762 case presentation_type::general_lower:
2763 result.format = float_format::general;
2765 case presentation_type::exp_upper:
2766 result.upper =
true;
2768 case presentation_type::exp_lower:
2769 result.format = float_format::exp;
2770 result.showpoint |= specs.precision != 0;
2772 case presentation_type::fixed_upper:
2773 result.upper =
true;
2775 case presentation_type::fixed_lower:
2776 result.format = float_format::fixed;
2777 result.showpoint |= specs.precision != 0;
2779 case presentation_type::hexfloat_upper:
2780 result.upper =
true;
2782 case presentation_type::hexfloat_lower:
2783 result.format = float_format::hex;
2786 eh.on_error(
"invalid type specifier");
2792 template <
typename ErrorHandler = error_handler>
2793 FMT_CONSTEXPR
auto check_cstring_type_spec(presentation_type type,
2794 ErrorHandler&& eh = {}) ->
bool {
2795 if (type == presentation_type::none || type == presentation_type::string)
2797 if (type != presentation_type::pointer) eh.on_error(
"invalid type specifier");
2801 template <
typename ErrorHandler = error_handler>
2802 FMT_CONSTEXPR
void check_string_type_spec(presentation_type type,
2803 ErrorHandler&& eh = {}) {
2804 if (type != presentation_type::none && type != presentation_type::string)
2805 eh.on_error(
"invalid type specifier");
2808 template <
typename ErrorHandler>
2809 FMT_CONSTEXPR
void check_pointer_type_spec(presentation_type type,
2810 ErrorHandler&& eh) {
2811 if (type != presentation_type::none && type != presentation_type::pointer)
2812 eh.on_error(
"invalid type specifier");
2819 detail::type arg_type_;
2821 FMT_CONSTEXPR
void require_numeric_argument() {
2822 if (!is_arithmetic_type(arg_type_))
2823 this->on_error(
"format specifier requires numeric argument");
2827 FMT_CONSTEXPR
specs_checker(
const Handler& handler, detail::type arg_type)
2828 : Handler(handler), arg_type_(arg_type) {}
2830 FMT_CONSTEXPR
void on_align(align_t
align) {
2831 if (align == align::numeric) require_numeric_argument();
2832 Handler::on_align(align);
2835 FMT_CONSTEXPR
void on_sign(sign_t s) {
2836 require_numeric_argument();
2837 if (is_integral_type(arg_type_) && arg_type_ != type::int_type &&
2838 arg_type_ != type::long_long_type && arg_type_ != type::char_type) {
2839 this->on_error(
"format specifier requires signed argument");
2841 Handler::on_sign(s);
2844 FMT_CONSTEXPR
void on_hash() {
2845 require_numeric_argument();
2849 FMT_CONSTEXPR
void on_localized() {
2850 require_numeric_argument();
2851 Handler::on_localized();
2854 FMT_CONSTEXPR
void on_zero() {
2855 require_numeric_argument();
2859 FMT_CONSTEXPR
void end_precision() {
2860 if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type)
2861 this->on_error(
"precision not allowed for this argument type");
2865 constexpr
int invalid_arg_index = -1;
2867 #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 2868 template <
int N,
typename T,
typename... Args,
typename Char>
2870 if constexpr (detail::is_statically_named_arg<T>()) {
2871 if (name == T::name)
return N;
2873 if constexpr (
sizeof...(Args) > 0)
2874 return get_arg_index_by_name<N + 1, Args...>(name);
2876 return invalid_arg_index;
2880 template <
typename... Args,
typename Char>
2882 #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 2883 if constexpr (
sizeof...(Args) > 0)
2884 return get_arg_index_by_name<0, Args...>(name);
2887 return invalid_arg_index;
2890 template <
typename Char,
typename ErrorHandler,
typename... Args>
2894 enum { num_args =
sizeof...(Args) };
2900 parse_func parse_funcs_[num_args > 0 ? num_args : 1];
2905 : context_(format_str, num_args, eh),
2906 parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}
2908 FMT_CONSTEXPR
void on_text(
const Char*,
const Char*) {}
2910 FMT_CONSTEXPR
auto on_arg_id() ->
int {
return context_.next_arg_id(); }
2911 FMT_CONSTEXPR
auto on_arg_id(
int id) ->
int {
2912 return context_.check_arg_id(
id), id;
2915 #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 2916 auto index = get_arg_index_by_name<Args...>(id);
2917 if (index == invalid_arg_index) on_error(
"named argument is not found");
2918 return context_.check_arg_id(index), index;
2921 on_error(
"compile-time checks for named arguments require C++20 support");
2926 FMT_CONSTEXPR
void on_replacement_field(
int,
const Char*) {}
2928 FMT_CONSTEXPR
auto on_format_specs(
int id,
const Char* begin,
const Char*)
2930 context_.advance_to(context_.begin() + (begin - &*context_.begin()));
2932 return id >= 0 &&
id < num_args ? parse_funcs_[id](context_) : begin;
2935 FMT_CONSTEXPR
void on_error(
const char* message) {
2936 context_.on_error(message);
2940 template <
typename... Args,
typename S,
2941 enable_if_t<(is_compile_string<S>::value),
int>>
2942 void check_format_string(S format_str) {
2943 FMT_CONSTEXPR
auto s = to_string_view(format_str);
2945 remove_cvref_t<Args>...>;
2946 FMT_CONSTEXPR
bool invalid_format =
2947 (parse_format_string<true>(s, checker(s, {})),
true);
2948 ignore_unused(invalid_format);
2951 template <
typename Char>
2961 FMT_END_DETAIL_NAMESPACE
2965 template <
typename T,
typename Char>
2967 enable_if_t<detail::type_constant<T, Char>::value !=
2968 detail::type::custom_type>> {
2970 detail::dynamic_format_specs<Char> specs_;
2975 template <
typename ParseContext>
2976 FMT_CONSTEXPR
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
2977 auto begin = ctx.begin(), end = ctx.end();
2978 if (begin == end)
return begin;
2979 using handler_type = detail::dynamic_specs_handler<ParseContext>;
2980 auto type = detail::type_constant<T, Char>::value;
2982 detail::specs_checker<handler_type>(handler_type(specs_, ctx), type);
2983 auto it = detail::parse_format_specs(begin, end, checker);
2984 auto eh = ctx.error_handler();
2986 case detail::type::none_type:
2987 FMT_ASSERT(
false,
"invalid argument type");
2989 case detail::type::bool_type:
2990 if (specs_.type == presentation_type::none ||
2991 specs_.type == presentation_type::string) {
2995 case detail::type::int_type:
2996 case detail::type::uint_type:
2997 case detail::type::long_long_type:
2998 case detail::type::ulong_long_type:
2999 case detail::type::int128_type:
3000 case detail::type::uint128_type:
3001 detail::check_int_type_spec(specs_.type, eh);
3003 case detail::type::char_type:
3004 detail::check_char_specs(specs_, eh);
3006 case detail::type::float_type:
3007 if (detail::const_check(FMT_USE_FLOAT))
3008 detail::parse_float_type_spec(specs_, eh);
3010 FMT_ASSERT(
false,
"float support disabled");
3012 case detail::type::double_type:
3013 if (detail::const_check(FMT_USE_DOUBLE))
3014 detail::parse_float_type_spec(specs_, eh);
3016 FMT_ASSERT(
false,
"double support disabled");
3018 case detail::type::long_double_type:
3019 if (detail::const_check(FMT_USE_LONG_DOUBLE))
3020 detail::parse_float_type_spec(specs_, eh);
3022 FMT_ASSERT(
false,
"long double support disabled");
3024 case detail::type::cstring_type:
3025 detail::check_cstring_type_spec(specs_.type, eh);
3027 case detail::type::string_type:
3028 detail::check_string_type_spec(specs_.type, eh);
3030 case detail::type::pointer_type:
3031 detail::check_pointer_type_spec(specs_.type, eh);
3033 case detail::type::custom_type:
3041 template <
typename FormatContext>
3042 FMT_CONSTEXPR
auto format(
const T& val, FormatContext& ctx)
const 3043 -> decltype(ctx.out());
3054 template <
typename S,
3060 (std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
3061 std::is_reference<Args>::value)...>() == 0,
3062 "passing views as lvalues is disallowed");
3063 #ifdef FMT_HAS_CONSTEVAL 3064 if constexpr (detail::count_named_args<Args...>() ==
3065 detail::count_statically_named_args<Args...>()) {
3066 using checker = detail::format_string_checker<Char, detail::error_handler,
3067 remove_cvref_t<Args>...>;
3068 detail::parse_format_string<true>(str_, checker(s, {}));
3071 detail::check_format_string<Args...>(s);
3079 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 3086 template <
typename... Args>
3116 template <
typename... T>
3119 return vformat(fmt, fmt::make_format_args(args...));
3123 template <
typename OutputIt,
3124 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3126 using detail::get_buffer;
3127 auto&& buf = get_buffer<char>(out);
3128 detail::vformat_to(buf, fmt, args, {});
3129 return detail::get_iterator(buf);
3144 template <
typename OutputIt,
typename... T,
3145 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3148 return vformat_to(out, fmt, fmt::make_format_args(args...));
3158 template <
typename OutputIt,
typename... T,
3159 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3162 using traits = detail::fixed_buffer_traits;
3163 auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
3164 detail::vformat_to(buf, fmt, args, {});
3165 return {buf.out(), buf.count()};
3176 template <
typename OutputIt,
typename... T,
3177 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
3180 return vformat_to_n(out, n, fmt, fmt::make_format_args(args...));
3184 template <
typename... T>
3186 T&&... args) ->
size_t {
3187 auto buf = detail::counting_buffer<>();
3188 detail::vformat_to(buf,
string_view(fmt), fmt::make_format_args(args...), {});
3205 template <
typename... T>
3207 const auto& vargs = fmt::make_format_args(args...);
3208 return detail::is_utf8() ? vprint(fmt, vargs)
3209 : detail::vprint_mojibake(stdout, fmt, vargs);
3222 template <
typename... T>
3224 const auto& vargs = fmt::make_format_args(args...);
3225 return detail::is_utf8() ? vprint(f, fmt, vargs)
3226 : detail::vprint_mojibake(f, fmt, vargs);
3229 FMT_MODULE_EXPORT_END
3230 FMT_GCC_PRAGMA(
"GCC pop_options")
3233 #ifdef FMT_HEADER_ONLY 3234 # include "format.h" 3236 #endif // FMT_CORE_H_
FMT_CONSTEXPR basic_string_view(const std::basic_string< Char, Traits, Alloc > &s) FMT_NOEXCEPT
Constructs a string reference from a std::basic_string object.
Definition: core.h:481
constexpr auto size() const FMT_NOEXCEPT -> size_t
Returns the size of this buffer.
Definition: core.h:820
FMT_CONSTEXPR void advance_to(iterator it)
Advances the begin iterator to it.
Definition: core.h:663
constexpr auto begin() const FMT_NOEXCEPT -> iterator
Returns an iterator to the beginning of the format string range being parsed.
Definition: core.h:651
FMT_CONSTEXPR_CHAR_TRAITS FMT_INLINE basic_string_view(const Char *s)
Constructs a string reference object from a C string computing the size with std::char_traits<Char>::...
Definition: core.h:472
constexpr auto capacity() const FMT_NOEXCEPT -> size_t
Returns the capacity of this buffer.
Definition: core.h:823
constexpr auto end() const FMT_NOEXCEPT -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition: core.h:658
void clear()
Clears this buffer.
Definition: core.h:832
constexpr auto data() const FMT_NOEXCEPT -> const Char *
Returns a pointer to the string data.
Definition: core.h:492
A contiguous memory buffer with an optional growing ability.
Definition: core.h:778
FMT_CONSTEXPR auto data() const FMT_NOEXCEPT -> const T *
Returns a pointer to the buffer data.
Definition: core.h:829
FMT_CONSTEXPR auto next_arg_id() -> int
Reports an error if using the manual argument indexing; otherwise returns the next argument index and...
Definition: core.h:671
constexpr auto size() const FMT_NOEXCEPT -> size_t
Returns the string size.
Definition: core.h:495
Definition: sc_data.cpp:17
An implementation of std::basic_string_view for pre-C++17.
Definition: core.h:448
Char char_type
The character type for the output.
Definition: core.h:1745
FMT_CONSTEXPR auto data() FMT_NOEXCEPT -> T *
Returns a pointer to the buffer data.
Definition: core.h:826
constexpr basic_string_view(const Char *s, size_t count) FMT_NOEXCEPT
Constructs a string reference object from a C string and a size.
Definition: core.h:460
FMT_CONSTEXPR20 void grow(size_t) override
Increases the buffer capacity to hold at least capacity elements.
Definition: core.h:968
FMT_CONSTEXPR20 void grow(size_t) override
Increases the buffer capacity to hold at least capacity elements.
Definition: core.h:1009
FMT_CONSTEXPR20 void grow(size_t) override
Increases the buffer capacity to hold at least capacity elements.
Definition: core.h:930
Definition: color.hpp:198
FMT_CONSTEXPR20 void grow(size_t capacity) override
Increases the buffer capacity to hold at least capacity elements.
Definition: core.h:986
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition: core.h:633
FMT_CONSTEXPR void check_arg_id(int)
Reports an error if using the automatic argument indexing; otherwise switches to the manual indexing...
Definition: core.h:683
Specifies if T is a character type.
Definition: core.h:543
constexpr basic_format_context(OutputIt out, basic_format_args< basic_format_context > ctx_args, detail::locale_ref loc=detail::locale_ref())
Constructs a basic_format_context object.
Definition: core.h:1765
FMT_CONSTEXPR20 void grow(size_t) override
Increases the buffer capacity to hold at least capacity elements.
Definition: core.h:896