8 #ifndef FMTQUILL_BASE_H_ 9 #define FMTQUILL_BASE_H_ 11 #if !defined(FMTQUILL_HEADER_ONLY) 12 #define FMTQUILL_HEADER_ONLY 15 #if defined(FMTQUILL_IMPORT_STD) && !defined(FMTQUILL_MODULE) 16 # define FMTQUILL_MODULE 19 #ifndef FMTQUILL_MODULE 24 # include <type_traits> 28 #define FMTQUILL_VERSION 120100 31 #if defined(__clang__) && !defined(__ibmxl__) 32 # define FMTQUILL_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) 34 # define FMTQUILL_CLANG_VERSION 0 36 #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) 37 # define FMTQUILL_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) 39 # define FMTQUILL_GCC_VERSION 0 42 # define FMTQUILL_ICC_VERSION __ICL 43 #elif defined(__INTEL_COMPILER) 44 # define FMTQUILL_ICC_VERSION __INTEL_COMPILER 46 # define FMTQUILL_ICC_VERSION 0 49 # define FMTQUILL_MSC_VERSION _MSC_VER 51 # define FMTQUILL_MSC_VERSION 0 55 #ifdef _GLIBCXX_RELEASE 56 # define FMTQUILL_GLIBCXX_RELEASE _GLIBCXX_RELEASE 58 # define FMTQUILL_GLIBCXX_RELEASE 0 60 #ifdef _LIBCPP_VERSION 61 # define FMTQUILL_LIBCPP_VERSION _LIBCPP_VERSION 63 # define FMTQUILL_LIBCPP_VERSION 0 67 # define FMTQUILL_CPLUSPLUS _MSVC_LANG 69 # define FMTQUILL_CPLUSPLUS __cplusplus 74 # define FMTQUILL_HAS_FEATURE(x) __has_feature(x) 76 # define FMTQUILL_HAS_FEATURE(x) 0 79 # define FMTQUILL_HAS_INCLUDE(x) __has_include(x) 81 # define FMTQUILL_HAS_INCLUDE(x) 0 84 # define FMTQUILL_HAS_BUILTIN(x) __has_builtin(x) 86 # define FMTQUILL_HAS_BUILTIN(x) 0 88 #ifdef __has_cpp_attribute 89 # define FMTQUILL_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) 91 # define FMTQUILL_HAS_CPP_ATTRIBUTE(x) 0 94 #define FMTQUILL_HAS_CPP14_ATTRIBUTE(attribute) \ 95 (FMTQUILL_CPLUSPLUS >= 201402L && FMTQUILL_HAS_CPP_ATTRIBUTE(attribute)) 97 #define FMTQUILL_HAS_CPP17_ATTRIBUTE(attribute) \ 98 (FMTQUILL_CPLUSPLUS >= 201703L && FMTQUILL_HAS_CPP_ATTRIBUTE(attribute)) 101 #ifdef FMTQUILL_USE_CONSTEXPR 103 #elif FMTQUILL_GCC_VERSION >= 702 && FMTQUILL_CPLUSPLUS >= 201402L 106 # define FMTQUILL_USE_CONSTEXPR 1 107 #elif FMTQUILL_ICC_VERSION 108 # define FMTQUILL_USE_CONSTEXPR 0 // https://github.com/fmtlib/fmt/issues/1628 109 #elif FMTQUILL_HAS_FEATURE(cxx_relaxed_constexpr) || FMTQUILL_MSC_VERSION >= 1912 110 # define FMTQUILL_USE_CONSTEXPR 1 112 # define FMTQUILL_USE_CONSTEXPR 0 114 #if FMTQUILL_USE_CONSTEXPR 115 # define FMTQUILL_CONSTEXPR constexpr 117 # define FMTQUILL_CONSTEXPR 121 #ifdef FMTQUILL_USE_CONSTEVAL 123 #elif !defined(__cpp_lib_is_constant_evaluated) 124 # define FMTQUILL_USE_CONSTEVAL 0 125 #elif FMTQUILL_CPLUSPLUS < 201709L 126 # define FMTQUILL_USE_CONSTEVAL 0 127 #elif FMTQUILL_GLIBCXX_RELEASE && FMTQUILL_GLIBCXX_RELEASE < 10 128 # define FMTQUILL_USE_CONSTEVAL 0 129 #elif FMTQUILL_LIBCPP_VERSION && FMTQUILL_LIBCPP_VERSION < 10000 130 # define FMTQUILL_USE_CONSTEVAL 0 131 #elif defined(__apple_build_version__) && __apple_build_version__ < 14000029L 132 # define FMTQUILL_USE_CONSTEVAL 0 // consteval is broken in Apple clang < 14. 133 #elif FMTQUILL_MSC_VERSION && FMTQUILL_MSC_VERSION < 1929 134 # define FMTQUILL_USE_CONSTEVAL 0 // consteval is broken in MSVC VS2019 < 16.10. 135 #elif defined(__cpp_consteval) 136 # define FMTQUILL_USE_CONSTEVAL 1 137 #elif FMTQUILL_GCC_VERSION >= 1002 || FMTQUILL_CLANG_VERSION >= 1101 138 # define FMTQUILL_USE_CONSTEVAL 1 140 # define FMTQUILL_USE_CONSTEVAL 0 142 #if FMTQUILL_USE_CONSTEVAL 143 # define FMTQUILL_CONSTEVAL consteval 144 # define FMTQUILL_CONSTEXPR20 constexpr 146 # define FMTQUILL_CONSTEVAL 147 # define FMTQUILL_CONSTEXPR20 151 #ifdef FMTQUILL_USE_EXCEPTIONS 153 #elif defined(__GNUC__) && !defined(__EXCEPTIONS) 154 # define FMTQUILL_USE_EXCEPTIONS 0 155 #elif defined(__clang__) && !defined(__cpp_exceptions) 156 # define FMTQUILL_USE_EXCEPTIONS 0 157 #elif FMTQUILL_MSC_VERSION && !_HAS_EXCEPTIONS 158 # define FMTQUILL_USE_EXCEPTIONS 0 160 # define FMTQUILL_USE_EXCEPTIONS 1 162 #if FMTQUILL_USE_EXCEPTIONS 163 # define FMTQUILL_TRY try 164 # define FMTQUILL_CATCH(x) catch (x) 166 # define FMTQUILL_TRY if (true) 167 # define FMTQUILL_CATCH(x) if (false) 170 #ifdef FMTQUILL_NO_UNIQUE_ADDRESS 172 #elif FMTQUILL_CPLUSPLUS < 202002L 174 #elif FMTQUILL_HAS_CPP_ATTRIBUTE(no_unique_address) 175 # define FMTQUILL_NO_UNIQUE_ADDRESS [[no_unique_address]] 177 #elif FMTQUILL_MSC_VERSION >= 1929 && !FMTQUILL_CLANG_VERSION 178 # define FMTQUILL_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] 180 #ifndef FMTQUILL_NO_UNIQUE_ADDRESS 181 # define FMTQUILL_NO_UNIQUE_ADDRESS 184 #if FMTQUILL_HAS_CPP17_ATTRIBUTE(fallthrough) 185 # define FMTQUILL_FALLTHROUGH [[fallthrough]] 186 #elif defined(__clang__) 187 # define FMTQUILL_FALLTHROUGH [[clang::fallthrough]] 188 #elif FMTQUILL_GCC_VERSION >= 700 && \ 189 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) 190 # define FMTQUILL_FALLTHROUGH [[gnu::fallthrough]] 192 # define FMTQUILL_FALLTHROUGH 196 #if FMTQUILL_HAS_CPP_ATTRIBUTE(noreturn) && !FMTQUILL_MSC_VERSION && !defined(__NVCC__) 197 # define FMTQUILL_NORETURN [[noreturn]] 199 # define FMTQUILL_NORETURN 202 #ifdef FMTQUILL_NODISCARD 204 #elif FMTQUILL_HAS_CPP17_ATTRIBUTE(nodiscard) 205 # define FMTQUILL_NODISCARD [[nodiscard]] 207 # define FMTQUILL_NODISCARD 210 #if FMTQUILL_GCC_VERSION || FMTQUILL_CLANG_VERSION 211 # define FMTQUILL_VISIBILITY(value) __attribute__((visibility(value))) 213 # define FMTQUILL_VISIBILITY(value) 217 #define FMTQUILL_PRAGMA_IMPL(x) _Pragma(#x) 218 #if FMTQUILL_GCC_VERSION >= 504 && !defined(__NVCOMPILER) 221 # define FMTQUILL_PRAGMA_GCC(x) FMTQUILL_PRAGMA_IMPL(GCC x) 223 # define FMTQUILL_PRAGMA_GCC(x) 225 #if FMTQUILL_CLANG_VERSION 226 # define FMTQUILL_PRAGMA_CLANG(x) FMTQUILL_PRAGMA_IMPL(clang x) 228 # define FMTQUILL_PRAGMA_CLANG(x) 230 #if FMTQUILL_MSC_VERSION 231 # define FMTQUILL_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) 233 # define FMTQUILL_MSC_WARNING(...) 237 FMTQUILL_PRAGMA_GCC(push_options)
238 #if !defined(__OPTIMIZE__) && !defined(__CUDACC__) && !defined(FMTQUILL_MODULE) 239 FMTQUILL_PRAGMA_GCC(optimize(
"Og"))
240 # define FMTQUILL_GCC_OPTIMIZED 242 FMTQUILL_PRAGMA_CLANG(diagnostic push)
243 FMTQUILL_PRAGMA_GCC(diagnostic push)
245 #ifdef FMTQUILL_ALWAYS_INLINE 247 #elif FMTQUILL_GCC_VERSION || FMTQUILL_CLANG_VERSION 248 # define FMTQUILL_ALWAYS_INLINE inline __attribute__((always_inline)) 250 # define FMTQUILL_ALWAYS_INLINE inline 253 #if defined(NDEBUG) || defined(FMTQUILL_GCC_OPTIMIZED) 254 # define FMTQUILL_INLINE FMTQUILL_ALWAYS_INLINE 256 # define FMTQUILL_INLINE inline 259 #ifndef FMTQUILL_BEGIN_NAMESPACE 260 # define FMTQUILL_BEGIN_NAMESPACE \ 261 namespace fmtquill { \ 262 inline namespace v12 { 263 # define FMTQUILL_END_NAMESPACE \ 268 #ifndef FMTQUILL_EXPORT 269 # define FMTQUILL_EXPORT 270 # define FMTQUILL_BEGIN_EXPORT 271 # define FMTQUILL_END_EXPORT 275 # define FMTQUILL_WIN32 1 277 # define FMTQUILL_WIN32 0 280 #if !defined(FMTQUILL_HEADER_ONLY) && FMTQUILL_WIN32 281 # if defined(FMTQUILL_LIB_EXPORT) 282 # define FMTQUILL_API __declspec(dllexport) 283 # elif defined(FMTQUILL_SHARED) 284 # define FMTQUILL_API __declspec(dllimport) 286 #elif defined(FMTQUILL_LIB_EXPORT) || defined(FMTQUILL_SHARED) 287 # define FMTQUILL_API FMTQUILL_VISIBILITY("default") 290 # define FMTQUILL_API 293 #ifndef FMTQUILL_OPTIMIZE_SIZE 294 # define FMTQUILL_OPTIMIZE_SIZE 0 299 #ifndef FMTQUILL_BUILTIN_TYPES 300 # define FMTQUILL_BUILTIN_TYPES 1 303 #define FMTQUILL_APPLY_VARIADIC(expr) \ 304 using unused = int[]; \ 305 (void)unused { 0, (expr, 0)... } 307 FMTQUILL_BEGIN_NAMESPACE
310 template <
bool B,
typename T =
void>
311 using enable_if_t =
typename std::enable_if<B, T>::type;
312 template <
bool B,
typename T,
typename F>
313 using conditional_t =
typename std::conditional<B, T, F>::type;
314 template <
bool B>
using bool_constant = std::integral_constant<bool, B>;
315 template <
typename T>
316 using remove_reference_t =
typename std::remove_reference<T>::type;
317 template <
typename T>
318 using remove_const_t =
typename std::remove_const<T>::type;
319 template <
typename T>
320 using remove_cvref_t =
typename std::remove_cv<remove_reference_t<T>>::type;
321 template <
typename T>
322 using make_unsigned_t =
typename std::make_unsigned<T>::type;
323 template <
typename T>
324 using underlying_t =
typename std::underlying_type<T>::type;
325 template <
typename T>
using decay_t =
typename std::decay<T>::type;
326 using nullptr_t = decltype(
nullptr);
328 #if (FMTQUILL_GCC_VERSION && FMTQUILL_GCC_VERSION < 500) || FMTQUILL_MSC_VERSION 330 template <
typename...>
struct void_t_impl {
333 template <
typename... T>
using void_t =
typename void_t_impl<T...>::type;
335 template <
typename...>
using void_t = void;
346 # define FMTQUILL_ENABLE_IF(...) 348 # define FMTQUILL_ENABLE_IF(...) fmtquill::enable_if_t<(__VA_ARGS__), int> = 0 351 template <
typename T> constexpr
auto min_of(T a, T b) -> T {
352 return a < b ? a : b;
354 template <
typename T> constexpr
auto max_of(T a, T b) -> T {
355 return a > b ? a : b;
358 FMTQUILL_NORETURN FMTQUILL_API
void assert_fail(
const char* file,
int line,
359 const char* message);
365 template <
typename... T> FMTQUILL_CONSTEXPR
void ignore_unused(
const T&...) {}
367 constexpr
auto is_constant_evaluated(
bool default_value =
false) noexcept
371 #if FMTQUILL_CPLUSPLUS >= 202002L && FMTQUILL_GLIBCXX_RELEASE >= 12 && \ 372 (FMTQUILL_CLANG_VERSION >= 1400 && FMTQUILL_CLANG_VERSION < 1500) 373 ignore_unused(default_value);
374 return __builtin_is_constant_evaluated();
375 #elif defined(__cpp_lib_is_constant_evaluated) 376 ignore_unused(default_value);
377 return std::is_constant_evaluated();
379 return default_value;
384 template <
typename T> FMTQUILL_ALWAYS_INLINE constexpr
auto const_check(T val) -> T {
388 FMTQUILL_NORETURN FMTQUILL_API
void assert_fail(
const char* file,
int line,
389 const char* message);
391 #if defined(FMTQUILL_ASSERT) 393 #elif defined(NDEBUG) 395 # define FMTQUILL_ASSERT(condition, message) \ 396 fmtquill::detail::ignore_unused((condition), (message)) 398 # define FMTQUILL_ASSERT(condition, message) \ 401 : ::fmtquill::assert_fail(__FILE__, __LINE__, (message))) 404 #ifdef FMTQUILL_USE_INT128 406 #elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \ 407 !(FMTQUILL_CLANG_VERSION && FMTQUILL_MSC_VERSION) 408 # define FMTQUILL_USE_INT128 1 409 using int128_opt = __int128_t;
410 using uint128_opt = __uint128_t;
411 inline auto map(int128_opt x) -> int128_opt {
return x; }
412 inline auto map(uint128_opt x) -> uint128_opt {
return x; }
414 # define FMTQUILL_USE_INT128 0 416 #if !FMTQUILL_USE_INT128 417 enum class int128_opt {};
418 enum class uint128_opt {};
420 inline auto map(int128_opt) ->
monostate {
return {}; }
421 inline auto map(uint128_opt) ->
monostate {
return {}; }
424 #ifdef FMTQUILL_USE_BITINT 426 #elif FMTQUILL_CLANG_VERSION >= 1500 && !defined(__CUDACC__) 427 # define FMTQUILL_USE_BITINT 1 429 # define FMTQUILL_USE_BITINT 0 432 #if FMTQUILL_USE_BITINT 433 FMTQUILL_PRAGMA_CLANG(diagnostic ignored
"-Wbit-int-extension")
434 template <
int N>
using bitint = _BitInt(N);
435 template <
int N>
using ubitint =
unsigned _BitInt(N);
437 template <
int N>
struct bitint {};
438 template <
int N>
struct ubitint {};
439 #endif // FMTQUILL_USE_BITINT 442 template <
typename Int>
443 FMTQUILL_CONSTEXPR
auto to_unsigned(Int
value) -> make_unsigned_t<Int> {
444 FMTQUILL_ASSERT(std::is_unsigned<Int>::value || value >= 0,
"negative value");
445 return static_cast<make_unsigned_t<Int>
>(value);
448 template <
typename Char>
449 using unsigned_char = conditional_t<sizeof(Char) == 1, unsigned char, unsigned>;
453 template <
typename T,
typename Enable =
void>
455 template <
typename T>
457 typename T::value_type(), 0))>>
458 : std::is_convertible<decltype(std::declval<T>().data()),
459 const typename T::value_type*> {};
462 enum { is_utf8_enabled =
"\u00A7"[1] ==
'\xA7' };
463 enum { use_utf8 = !FMTQUILL_WIN32 || is_utf8_enabled };
465 #ifndef FMTQUILL_UNICODE 466 # define FMTQUILL_UNICODE 0 469 static_assert(!FMTQUILL_UNICODE || use_utf8,
470 "Unicode support requires compiling with /utf-8");
472 template <
typename T> constexpr
auto narrow(T*) ->
char* {
return nullptr; }
473 constexpr FMTQUILL_ALWAYS_INLINE
auto narrow(
const char* s) ->
const char* {
477 template <
typename Char>
478 FMTQUILL_CONSTEXPR
auto compare(
const Char* s1,
const Char* s2,
size_t n) ->
int {
479 if (!is_constant_evaluated() &&
sizeof(Char) == 1)
return memcmp(s1, s2, n);
480 for (; n != 0; ++s1, ++s2, --n) {
481 if (*s1 < *s2)
return -1;
482 if (*s1 > *s2)
return 1;
490 template <
typename Container>
491 auto invoke_back_inserter()
492 -> decltype(back_inserter(std::declval<Container&>()));
495 template <
typename It,
typename Enable = std::true_type>
498 template <
typename It>
500 It, bool_constant<
std::is_same<
501 decltype(adl::invoke_back_inserter<typename It::container_type>()),
502 It>
::value>> : std::true_type {};
505 template <
typename OutputIt>
506 inline FMTQUILL_CONSTEXPR20
auto get_container(OutputIt it) ->
507 typename OutputIt::container_type& {
508 struct accessor : OutputIt {
509 FMTQUILL_CONSTEXPR20 accessor(OutputIt base) : OutputIt(base) {}
510 using OutputIt::container;
512 return *accessor(it).container;
517 FMTQUILL_BEGIN_EXPORT
532 using value_type = Char;
533 using iterator =
const Char*;
539 : data_(s), size_(count) {}
544 #if FMTQUILL_GCC_VERSION 545 FMTQUILL_ALWAYS_INLINE
548 #if FMTQUILL_HAS_BUILTIN(__builtin_strlen) || FMTQUILL_GCC_VERSION || FMTQUILL_CLANG_VERSION 549 if (std::is_same<Char, char>::value && !detail::is_constant_evaluated()) {
550 size_ = __builtin_strlen(detail::narrow(s));
561 template <
typename S,
563 typename S::value_type, Char>::value)>
565 : data_(s.data()), size_(s.size()) {}
568 constexpr
auto data() const noexcept -> const Char* {
return data_; }
571 constexpr
auto size() const noexcept ->
size_t {
return size_; }
573 constexpr
auto begin()
const noexcept -> iterator {
return data_; }
574 constexpr
auto end()
const noexcept -> iterator {
return data_ + size_; }
576 constexpr
auto operator[](
size_t pos)
const noexcept ->
const Char& {
580 FMTQUILL_CONSTEXPR
void remove_prefix(
size_t n) noexcept {
587 return size_ >= sv.size_ && detail::compare(data_, sv.data_, sv.size_) == 0;
589 FMTQUILL_CONSTEXPR
auto starts_with(Char c)
const noexcept ->
bool {
590 return size_ >= 1 && *data_ == c;
592 FMTQUILL_CONSTEXPR
auto starts_with(
const Char* s)
const ->
bool {
598 detail::compare(data_, other.data_, min_of(size_, other.size_));
599 if (result != 0)
return result;
600 return size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
605 return lhs.compare(rhs) == 0;
608 return lhs.compare(rhs) != 0;
611 return lhs.compare(rhs) < 0;
614 return lhs.compare(rhs) <= 0;
617 return lhs.compare(rhs) > 0;
620 return lhs.compare(rhs) >= 0;
639 template <
typename OutputIt,
typename Char>
640 using basic_format_context =
641 conditional_t<std::is_same<OutputIt, appender>::value,
context,
645 template <
typename Char>
646 using buffered_context =
647 conditional_t<std::is_same<Char, char>::value, context,
658 template <
typename T,
typename Char =
char,
typename Enable =
void>
661 formatter() =
delete;
667 FMTQUILL_NORETURN FMTQUILL_API
void report_error(
const char* message);
669 enum class presentation_type : unsigned char {
692 enum class align { none, left, right, center, numeric };
693 enum class sign { none, minus, plus, space };
694 enum class arg_id_kind { none, index, name };
718 align_mask = 0x00038,
719 width_mask = 0x000C0,
720 precision_mask = 0x00300,
722 uppercase_mask = 0x01000,
723 alternate_mask = 0x02000,
724 localized_mask = 0x04000,
725 fill_size_mask = 0x38000,
731 fill_size_shift = 15,
736 unsigned data_ = 1 << fill_size_shift;
737 static_assert(
sizeof(basic_specs::data_) * CHAR_BIT >= 18,
"");
740 char fill_data_[max_fill_size] = {
' '};
742 FMTQUILL_CONSTEXPR
void set_fill_size(
size_t size) {
743 data_ = (data_ & ~fill_size_mask) |
744 (static_cast<unsigned>(size) << fill_size_shift);
748 constexpr
auto type()
const -> presentation_type {
749 return static_cast<presentation_type
>(data_ & type_mask);
751 FMTQUILL_CONSTEXPR
void set_type(presentation_type t) {
752 data_ = (data_ & ~type_mask) | static_cast<unsigned>(t);
755 constexpr
auto align()
const -> align {
756 return static_cast<fmtquill::align
>((data_ & align_mask) >> align_shift);
758 FMTQUILL_CONSTEXPR
void set_align(fmtquill::align a) {
759 data_ = (data_ & ~align_mask) | (static_cast<unsigned>(a) << align_shift);
762 constexpr
auto dynamic_width()
const -> arg_id_kind {
763 return static_cast<arg_id_kind
>((data_ & width_mask) >> width_shift);
765 FMTQUILL_CONSTEXPR
void set_dynamic_width(arg_id_kind w) {
766 data_ = (data_ & ~width_mask) | (static_cast<unsigned>(w) << width_shift);
769 FMTQUILL_CONSTEXPR
auto dynamic_precision()
const -> arg_id_kind {
770 return static_cast<arg_id_kind
>((data_ & precision_mask) >>
773 FMTQUILL_CONSTEXPR
void set_dynamic_precision(arg_id_kind p) {
774 data_ = (data_ & ~precision_mask) |
775 (static_cast<unsigned>(p) << precision_shift);
778 constexpr
auto dynamic()
const ->
bool {
779 return (data_ & (width_mask | precision_mask)) != 0;
782 constexpr
auto sign()
const -> sign {
783 return static_cast<fmtquill::sign
>((data_ & sign_mask) >> sign_shift);
785 FMTQUILL_CONSTEXPR
void set_sign(fmtquill::sign s) {
786 data_ = (data_ & ~sign_mask) | (static_cast<unsigned>(s) << sign_shift);
789 constexpr
auto upper()
const ->
bool {
return (data_ & uppercase_mask) != 0; }
790 FMTQUILL_CONSTEXPR
void set_upper() { data_ |= uppercase_mask; }
792 constexpr
auto alt()
const ->
bool {
return (data_ & alternate_mask) != 0; }
793 FMTQUILL_CONSTEXPR
void set_alt() { data_ |= alternate_mask; }
794 FMTQUILL_CONSTEXPR
void clear_alt() { data_ &= ~alternate_mask; }
796 constexpr
auto localized()
const ->
bool {
797 return (data_ & localized_mask) != 0;
799 FMTQUILL_CONSTEXPR
void set_localized() { data_ |= localized_mask; }
801 constexpr
auto fill_size()
const ->
size_t {
802 return (data_ & fill_size_mask) >> fill_size_shift;
805 template <typename Char, FMTQUILL_ENABLE_IF(std::is_same<Char, char>::value)>
806 constexpr
auto fill()
const ->
const Char* {
809 template <typename Char, FMTQUILL_ENABLE_IF(!std::is_same<Char, char>::value)>
810 constexpr
auto fill()
const ->
const Char* {
814 template <
typename Char> constexpr
auto fill_unit()
const -> Char {
815 using uchar =
unsigned char;
816 return static_cast<Char
>(
static_cast<uchar
>(fill_data_[0]) |
817 (static_cast<uchar>(fill_data_[1]) << 8) |
818 (static_cast<uchar>(fill_data_[2]) << 16));
821 FMTQUILL_CONSTEXPR
void set_fill(
char c) {
826 template <
typename Char>
828 auto size = s.
size();
831 unsigned uchar =
static_cast<detail::unsigned_char<Char>
>(s[0]);
832 fill_data_[0] =
static_cast<char>(uchar);
833 fill_data_[1] =
static_cast<char>(uchar >> 8);
834 fill_data_[2] =
static_cast<char>(uchar >> 16);
837 FMTQUILL_ASSERT(size <= max_fill_size,
"invalid fill");
838 for (
size_t i = 0; i < size; ++i)
839 fill_data_[i & 3] = static_cast<char>(s[i]);
842 FMTQUILL_CONSTEXPR
void copy_fill_from(
const basic_specs& specs) {
843 set_fill_size(specs.fill_size());
844 for (
size_t i = 0; i < max_fill_size; ++i)
845 fill_data_[i] = specs.fill_data_[i];
866 enum { use_constexpr_cast = !FMTQUILL_GCC_VERSION || FMTQUILL_GCC_VERSION >= 1200 };
868 FMTQUILL_CONSTEXPR
void do_check_arg_id(
int arg_id);
871 using char_type = Char;
872 using iterator =
const Char*;
876 : fmt_(fmt), next_arg_id_(next_arg_id) {}
880 constexpr
auto begin() const noexcept -> iterator {
return fmt_.begin(); }
883 constexpr
auto end() const noexcept -> iterator {
return fmt_.end(); }
887 fmt_.remove_prefix(detail::to_unsigned(it - begin()));
893 if (next_arg_id_ < 0) {
894 report_error(
"cannot switch from manual to automatic argument indexing");
897 int id = next_arg_id_++;
905 if (next_arg_id_ > 0) {
906 report_error(
"cannot switch from automatic to manual argument indexing");
915 FMTQUILL_CONSTEXPR
void check_dynamic_spec(
int arg_id);
918 #ifndef FMTQUILL_USE_LOCALE 919 # define FMTQUILL_USE_LOCALE (FMTQUILL_OPTIMIZE_SIZE <= 1) 924 #if FMTQUILL_USE_LOCALE 931 template <
typename Locale, FMTQUILL_ENABLE_IF(sizeof(Locale::collate) != 0)>
932 locale_ref(
const Locale& loc) : locale_(&loc) {
937 inline explicit operator bool()
const noexcept {
return locale_ !=
nullptr; }
938 #endif // FMTQUILL_USE_LOCALE 941 template <
typename Locale>
auto get()
const -> Locale;
955 template <>
struct is_code_unit<char8_t> : bool_constant<is_utf8_enabled> {};
961 template <typename Char, FMTQUILL_ENABLE_IF(is_code_unit<Char>::value)>
965 template <typename T, FMTQUILL_ENABLE_IF(is_std_string_like<T>::value)>
966 constexpr
auto to_string_view(
const T& s)
970 template <
typename Char>
976 template <
typename T,
typename Enable =
void>
979 template <
typename T>
981 T, void_t<decltype(
detail::to_string_view(std::declval<T>()))>>
985 template <
typename S,
986 typename V = decltype(detail::to_string_view(std::declval<S>()))>
1000 last_integer_type = char_type,
1005 last_numeric_type = long_double_type,
1013 template <
typename T,
typename Char>
1016 #define FMTQUILL_TYPE_CONSTANT(Type, constant) \ 1017 template <typename Char> \ 1018 struct type_constant<Type, Char> \ 1019 : std::integral_constant<type, type::constant> {} 1021 FMTQUILL_TYPE_CONSTANT(
int, int_type);
1022 FMTQUILL_TYPE_CONSTANT(
unsigned, uint_type);
1023 FMTQUILL_TYPE_CONSTANT(
long long, long_long_type);
1024 FMTQUILL_TYPE_CONSTANT(
unsigned long long, ulong_long_type);
1025 FMTQUILL_TYPE_CONSTANT(int128_opt, int128_type);
1026 FMTQUILL_TYPE_CONSTANT(uint128_opt, uint128_type);
1027 FMTQUILL_TYPE_CONSTANT(
bool, bool_type);
1028 FMTQUILL_TYPE_CONSTANT(Char, char_type);
1029 FMTQUILL_TYPE_CONSTANT(
float, float_type);
1030 FMTQUILL_TYPE_CONSTANT(
double, double_type);
1031 FMTQUILL_TYPE_CONSTANT(
long double, long_double_type);
1032 FMTQUILL_TYPE_CONSTANT(
const Char*, cstring_type);
1034 FMTQUILL_TYPE_CONSTANT(
const void*, pointer_type);
1036 constexpr
auto is_integral_type(type t) ->
bool {
1037 return t > type::none_type && t <= type::last_integer_type;
1039 constexpr
auto is_arithmetic_type(type t) ->
bool {
1040 return t > type::none_type && t <= type::last_numeric_type;
1043 constexpr
auto set(type rhs) ->
int {
return 1 <<
static_cast<int>(rhs); }
1044 constexpr
auto in(type t,
int set) ->
bool {
1045 return ((
set >> static_cast<int>(t)) & 1) != 0;
1051 set(type::int_type) |
set(type::long_long_type) |
set(type::int128_type),
1052 uint_set =
set(type::uint_type) |
set(type::ulong_long_type) |
1053 set(type::uint128_type),
1054 bool_set =
set(type::bool_type),
1055 char_set =
set(type::char_type),
1056 float_set =
set(type::float_type) |
set(type::double_type) |
1057 set(type::long_double_type),
1058 string_set =
set(type::string_type),
1059 cstring_set =
set(type::cstring_type),
1060 pointer_set =
set(type::pointer_type)
1065 template <
typename T,
typename Enable = std::true_type>
1067 template <
typename T>
1068 struct is_view<T, bool_constant<sizeof(T) != 0>> : std::is_base_of<view, T> {};
1074 template <
typename Char,
typename T>
1077 template <
typename Char,
typename T>
struct named_arg :
view {
1081 named_arg(
const Char* n,
const T& v) : name(n), value(v) {}
1085 template <
bool B = false> constexpr
auto count() ->
int {
return B ? 1 : 0; }
1086 template <
bool B1,
bool B2,
bool... Tail> constexpr
auto count() ->
int {
1087 return (B1 ? 1 : 0) + count<B2, Tail...>();
1090 template <
typename... T> constexpr
auto count_named_args() ->
int {
1091 return count<is_named_arg<T>::value...>();
1093 template <
typename... T> constexpr
auto count_static_named_args() ->
int {
1094 return count<is_static_named_arg<T>::value...>();
1103 template <
typename Char>
1105 int named_arg_index,
1107 for (
int i = 0; i < named_arg_index; ++i) {
1108 if (named_args[i].name == arg_name) report_error(
"duplicate named arg");
1112 template <typename Char, typename T, FMTQUILL_ENABLE_IF(!is_named_arg<T>::value)>
1116 template <typename Char, typename T, FMTQUILL_ENABLE_IF(is_named_arg<T>::value)>
1118 int& named_arg_index,
const T& arg) {
1119 check_for_duplicate<Char>(named_args, named_arg_index, arg.name);
1120 named_args[named_arg_index++] = {arg.name, arg_index++};
1123 template <
typename T,
typename Char,
1129 template <
typename T,
typename Char,
1132 int& arg_index,
int& named_arg_index) {
1133 check_for_duplicate<Char>(named_args, named_arg_index, T::name);
1134 named_args[named_arg_index++] = {T::name, arg_index++};
1139 enum { long_short =
sizeof(long) ==
sizeof(
int) && FMTQUILL_BUILTIN_TYPES };
1140 using long_type = conditional_t<long_short, int, long long>;
1141 using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
1143 template <
typename T>
1144 using format_as_result =
1145 remove_cvref_t<decltype(format_as(std::declval<const T&>()))>;
1146 template <
typename T>
1147 using format_as_member_result =
1148 remove_cvref_t<decltype(formatter<T>::format_as(std::declval<const T&>()))>;
1150 template <
typename T,
typename Enable = std::true_type>
1153 template <
typename T,
typename Enable = std::true_type>
1157 template <
typename T>
1159 T, bool_constant<
std::is_arithmetic<format_as_result<T>>
::value>>
1160 : std::true_type {};
1161 template <
typename T>
1163 T, bool_constant<std::is_arithmetic<format_as_member_result<T>>
::value>>
1164 : std::true_type {};
1166 template <
typename T,
typename U = remove_const_t<T>>
1167 using use_formatter =
1168 bool_constant<(std::is_class<T>::value || std::is_enum<T>::value ||
1169 std::is_union<T>::value || std::is_array<T>::value) &&
1173 template <
typename Char,
typename T,
typename U = remove_const_t<T>>
1174 auto has_formatter_impl(T* p, buffered_context<Char>* ctx =
nullptr)
1175 -> decltype(formatter<U, Char>().format(*p, *ctx), std::true_type());
1176 template <
typename Char>
auto has_formatter_impl(...) -> std::false_type;
1179 template <
typename T,
typename Char> constexpr
auto has_formatter() ->
bool {
1180 return decltype(has_formatter_impl<Char>(static_cast<T*>(
nullptr)))::
value;
1186 static auto map(
signed char) -> int;
1187 static auto map(
unsigned char) -> unsigned;
1188 static auto map(
short) -> int;
1189 static auto map(
unsigned short) -> unsigned;
1190 static auto map(
int) -> int;
1191 static auto map(
unsigned) -> unsigned;
1192 static auto map(
long) -> long_type;
1193 static auto map(
unsigned long) -> ulong_type;
1194 static auto map(
long long) ->
long long;
1195 static auto map(
unsigned long long) ->
unsigned long long;
1196 static auto map(int128_opt) -> int128_opt;
1197 static auto map(uint128_opt) -> uint128_opt;
1198 static auto map(
bool) -> bool;
1201 static auto map(
bitint<N>) -> conditional_t<N <= 64, long long, void>;
1204 -> conditional_t<N <= 64, unsigned long long, void>;
1206 template <typename T, FMTQUILL_ENABLE_IF(is_code_unit<T>::value)>
1207 static auto map(T) -> conditional_t<
1208 std::is_same<T, char>::value || std::is_same<T, Char>::value, Char,
void>;
1210 static auto map(
float) -> float;
1211 static auto map(
double) -> double;
1212 static auto map(
long double) ->
long double;
1214 static auto map(Char*) ->
const Char*;
1215 static auto map(
const Char*) ->
const Char*;
1216 template <
typename T,
typename C =
char_t<T>,
1217 FMTQUILL_ENABLE_IF(!std::is_po
inter<T>::value)>
1218 static auto map(
const T&) -> conditional_t<std::is_same<C, Char>::value,
1221 static auto map(
void*) ->
const void*;
1222 static auto map(
const void*) ->
const void*;
1223 static auto map(
volatile void*) ->
const void*;
1224 static auto map(
const volatile void*) ->
const void*;
1225 static auto map(nullptr_t) ->
const void*;
1226 template <typename T, FMTQUILL_ENABLE_IF(std::is_pointer<T>::value ||
1227 std::is_member_pointer<T>::value)>
1228 static auto map(
const T&) -> void;
1230 template <typename T, FMTQUILL_ENABLE_IF(use_format_as<T>::value)>
1231 static auto map(
const T& x) -> decltype(map(format_as(x)));
1232 template <typename T, FMTQUILL_ENABLE_IF(use_format_as_member<T>::value)>
1233 static auto map(
const T& x) -> decltype(map(formatter<T>::format_as(x)));
1235 template <typename T, FMTQUILL_ENABLE_IF(use_formatter<T>::value)>
1236 static auto map(T&) -> conditional_t<has_formatter<T, Char>(), T&,
void>;
1238 template <typename T, FMTQUILL_ENABLE_IF(is_named_arg<T>::value)>
1239 static auto map(
const T&
named_arg) -> decltype(map(named_arg.value));
1243 template <
typename T,
typename Char>
1247 template <
typename T,
typename Char =
char>
1250 template <
typename T,
typename Context,
1253 using stored_type_constant = std::integral_constant<
1254 type, Context::builtin_types || TYPE == type::int_type ? TYPE
1255 : type::custom_type>;
1257 template <
typename Char>
1266 int num_args,
const type* types,
1267 int next_arg_id = 0)
1268 :
base(fmt, next_arg_id), num_args_(num_args), types_(types) {}
1270 constexpr
auto num_args()
const ->
int {
return num_args_; }
1271 constexpr
auto arg_type(
int id)
const -> type {
return types_[id]; }
1273 FMTQUILL_CONSTEXPR
auto next_arg_id() ->
int {
1274 int id = base::next_arg_id();
1275 if (
id >= num_args_) report_error(
"argument not found");
1279 FMTQUILL_CONSTEXPR
void check_arg_id(
int id) {
1280 base::check_arg_id(
id);
1281 if (
id >= num_args_) report_error(
"argument not found");
1283 using base::check_arg_id;
1285 FMTQUILL_CONSTEXPR
void check_dynamic_spec(
int arg_id) {
1286 ignore_unused(arg_id);
1287 if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
1288 report_error(
"width/precision is not integer");
1294 FMTQUILL_CONSTEXPR
arg_ref(
int idx = 0) : index(idx) {}
1310 template <typename Char, FMTQUILL_ENABLE_IF(std::is_integral<Char>::value)>
1311 constexpr
auto to_ascii(Char c) ->
char {
1312 return c <= 0xff ? static_cast<char>(c) :
'\0';
1316 template <
typename Char>
1317 FMTQUILL_CONSTEXPR
auto code_point_length(
const Char* begin) ->
int {
1318 if (const_check(
sizeof(Char) != 1))
return 1;
1319 auto c =
static_cast<unsigned char>(*begin);
1320 return static_cast<int>((0x3a55000000000000ull >> (2 * (c >> 3))) & 3) + 1;
1325 template <
typename Char>
1326 FMTQUILL_CONSTEXPR
auto parse_nonnegative_int(
const Char*& begin,
const Char* end,
1327 int error_value) noexcept ->
int {
1328 FMTQUILL_ASSERT(begin != end &&
'0' <= *begin && *begin <=
'9',
"");
1329 unsigned value = 0, prev = 0;
1333 value = value * 10 + unsigned(*p -
'0');
1335 }
while (p != end &&
'0' <= *p && *p <=
'9');
1336 auto num_digits = p - begin;
1338 int digits10 =
static_cast<int>(
sizeof(int) * CHAR_BIT * 3 / 10);
1339 if (num_digits <= digits10)
return static_cast<int>(value);
1341 unsigned max = INT_MAX;
1342 return num_digits == digits10 + 1 &&
1343 prev * 10ull + unsigned(p[-1] -
'0') <= max
1344 ?
static_cast<int>(value)
1348 FMTQUILL_CONSTEXPR
inline auto parse_align(
char c) -> align {
1350 case '<':
return align::left;
1351 case '>':
return align::right;
1352 case '^':
return align::center;
1357 template <
typename Char> constexpr
auto is_name_start(Char c) ->
bool {
1358 return (
'a' <= c && c <=
'z') || (
'A' <= c && c <=
'Z') || c ==
'_';
1361 template <
typename Char,
typename Handler>
1362 FMTQUILL_CONSTEXPR
auto parse_arg_id(
const Char* begin,
const Char* end,
1363 Handler&& handler) ->
const Char* {
1365 if (c >=
'0' && c <=
'9') {
1368 index = parse_nonnegative_int(begin, end, INT_MAX);
1371 if (begin == end || (*begin !=
'}' && *begin !=
':'))
1372 report_error(
"invalid format string");
1374 handler.on_index(index);
1377 if (FMTQUILL_OPTIMIZE_SIZE > 1 || !is_name_start(c)) {
1378 report_error(
"invalid format string");
1384 }
while (it != end && (is_name_start(*it) || (
'0' <= *it && *it <=
'9')));
1385 handler.on_name({begin, to_unsigned(it - begin)});
1394 FMTQUILL_CONSTEXPR
void on_index(
int id) {
1396 kind = arg_id_kind::index;
1398 ctx.check_dynamic_spec(
id);
1402 kind = arg_id_kind::name;
1413 template <
typename Char>
1414 FMTQUILL_CONSTEXPR
auto parse_dynamic_spec(
const Char* begin,
const Char* end,
1418 FMTQUILL_ASSERT(begin != end,
"");
1419 auto kind = arg_id_kind::none;
1420 if (
'0' <= *begin && *begin <=
'9') {
1421 int val = parse_nonnegative_int(begin, end, -1);
1422 if (val == -1) report_error(
"number is too big");
1425 if (*begin ==
'{') {
1429 if (c ==
'}' || c ==
':') {
1432 kind = arg_id_kind::index;
1433 ctx.check_dynamic_spec(
id);
1435 begin = parse_arg_id(begin, end,
1439 if (begin != end && *begin ==
'}')
return {++begin, kind};
1441 report_error(
"invalid format string");
1443 return {begin, kind};
1446 template <
typename Char>
1447 FMTQUILL_CONSTEXPR
auto parse_width(
const Char* begin,
const Char* end,
1450 auto result = parse_dynamic_spec(begin, end, specs.width, width_ref, ctx);
1451 specs.set_dynamic_width(result.kind);
1455 template <
typename Char>
1456 FMTQUILL_CONSTEXPR
auto parse_precision(
const Char* begin,
const Char* end,
1462 report_error(
"invalid precision");
1466 parse_dynamic_spec(begin, end, specs.precision, precision_ref, ctx);
1467 specs.set_dynamic_precision(result.kind);
1471 enum class state { start, align, sign, hash, zero, width, precision, locale };
1474 template <
typename Char>
1475 FMTQUILL_CONSTEXPR
auto parse_format_specs(
const Char* begin,
const Char* end,
1480 if (end - begin > 1) {
1481 auto next = to_ascii(begin[1]);
1482 c = parse_align(next) == align::none ? to_ascii(*begin) :
'\0';
1484 if (begin == end)
return begin;
1485 c = to_ascii(*begin);
1489 state current_state = state::start;
1490 FMTQUILL_CONSTEXPR
void operator()(state s,
bool valid =
true) {
1491 if (current_state >= s || !valid)
1492 report_error(
"invalid format specifier");
1497 using pres = presentation_type;
1498 constexpr
auto integral_set = sint_set | uint_set | bool_set | char_set;
1504 FMTQUILL_CONSTEXPR
auto operator()(pres pres_type,
int set) ->
const Char* {
1505 if (!in(arg_type,
set)) report_error(
"invalid format specifier");
1506 specs.set_type(pres_type);
1509 } parse_presentation_type{begin, specs, arg_type};
1516 enter_state(state::align);
1517 specs.set_align(parse_align(c));
1522 specs.set_sign(c ==
' ' ? sign::space : sign::plus);
1523 FMTQUILL_FALLTHROUGH;
1525 enter_state(state::sign, in(arg_type, sint_set | float_set));
1529 enter_state(state::hash, is_arithmetic_type(arg_type));
1534 enter_state(state::zero);
1535 if (!is_arithmetic_type(arg_type))
1536 report_error(
"format specifier requires numeric argument");
1537 if (specs.align() == align::none) {
1539 specs.set_align(align::numeric);
1540 specs.set_fill(
'0');
1545 case '1':
case '2':
case '3':
case '4':
case '5':
1546 case '6':
case '7':
case '8':
case '9':
case '{':
1548 enter_state(state::width);
1549 begin = parse_width(begin, end, specs, specs.width_ref, ctx);
1552 enter_state(state::precision,
1553 in(arg_type, float_set | string_set | cstring_set));
1554 begin = parse_precision(begin, end, specs, specs.precision_ref, ctx);
1557 enter_state(state::locale, is_arithmetic_type(arg_type));
1558 specs.set_localized();
1561 case 'd':
return parse_presentation_type(pres::dec, integral_set);
1562 case 'X': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1563 case 'x':
return parse_presentation_type(pres::hex, integral_set);
1564 case 'o':
return parse_presentation_type(pres::oct, integral_set);
1565 case 'B': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1566 case 'b':
return parse_presentation_type(pres::bin, integral_set);
1567 case 'E': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1568 case 'e':
return parse_presentation_type(pres::exp, float_set);
1569 case 'F': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1570 case 'f':
return parse_presentation_type(pres::fixed, float_set);
1571 case 'G': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1572 case 'g':
return parse_presentation_type(pres::general, float_set);
1573 case 'A': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1574 case 'a':
return parse_presentation_type(pres::hexfloat, float_set);
1576 if (arg_type == type::bool_type) report_error(
"invalid format specifier");
1577 return parse_presentation_type(pres::chr, integral_set);
1579 return parse_presentation_type(pres::string,
1580 bool_set | string_set | cstring_set);
1582 return parse_presentation_type(pres::pointer, pointer_set | cstring_set);
1584 return parse_presentation_type(pres::debug,
1585 char_set | string_set | cstring_set);
1586 case '}':
return begin;
1588 if (*begin ==
'}')
return begin;
1590 auto fill_end = begin + code_point_length(begin);
1591 if (end - fill_end <= 0) {
1592 report_error(
"invalid format specifier");
1595 if (*begin ==
'{') {
1596 report_error(
"invalid fill character '{'");
1599 auto alignment = parse_align(to_ascii(*fill_end));
1600 enter_state(state::align, alignment != align::none);
1603 specs.set_align(alignment);
1604 begin = fill_end + 1;
1607 if (begin == end)
return begin;
1608 c = to_ascii(*begin);
1612 template <
typename Char,
typename Handler>
1613 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
auto parse_replacement_field(
const Char* begin,
1619 handler.on_error(
"invalid format string");
1625 handler.on_replacement_field(handler.on_arg_id(), begin);
1627 case '{': handler.on_text(begin, begin + 1);
return begin + 1;
1628 case ':': arg_id = handler.on_arg_id();
break;
1634 FMTQUILL_CONSTEXPR
void on_index(
int id) { arg_id = handler.on_arg_id(
id); }
1636 arg_id = handler.on_arg_id(
id);
1638 } adapter = {handler, 0};
1639 begin = parse_arg_id(begin, end, adapter);
1640 arg_id = adapter.arg_id;
1641 Char c = begin != end ? *begin : Char();
1643 handler.on_replacement_field(arg_id, begin);
1647 handler.on_error(
"missing '}' in format string");
1653 begin = handler.on_format_specs(arg_id, begin + 1, end);
1654 if (begin == end || *begin !=
'}')
1655 return handler.on_error(
"unknown format specifier"), end;
1659 template <
typename Char,
typename Handler>
1661 Handler&& handler) {
1662 auto begin = fmt.
data(), end = begin + fmt.
size();
1667 handler.on_text(begin, p - 1);
1668 begin = p = parse_replacement_field(p - 1, end, handler);
1669 }
else if (c ==
'}') {
1670 if (p == end || *p !=
'}')
1671 return handler.on_error(
"unmatched '}' in format string");
1672 handler.on_text(begin, p);
1676 handler.on_text(begin, end);
1680 FMTQUILL_CONSTEXPR
inline auto check_char_specs(
const format_specs& specs) ->
bool {
1681 auto type = specs.type();
1682 if (type != presentation_type::none && type != presentation_type::chr &&
1683 type != presentation_type::debug) {
1686 if (specs.align() == align::numeric || specs.sign() != sign::none ||
1688 report_error(
"invalid format specifier for char");
1696 template <
typename T,
typename Char>
1697 FMTQUILL_VISIBILITY(
"hidden")
1699 using mapped_type = remove_cvref_t<mapped_t<T, Char>>;
1700 constexpr
bool formattable =
1701 std::is_constructible<formatter<mapped_type, Char>>
::value;
1702 if (!formattable)
return ctx.
begin();
1703 using formatted_type = conditional_t<formattable, mapped_type, int>;
1704 return formatter<formatted_type, Char>().parse(ctx);
1709 template <
typename Char,
int NUM_ARGS,
int NUM_NAMED_ARGS,
bool DYNAMIC_NAMES>
1712 type types_[max_of<size_t>(1, NUM_ARGS)];
1717 parse_func parse_funcs_[max_of<size_t>(1, NUM_ARGS)];
1720 template <
typename... T>
1725 context_(fmt, NUM_ARGS, types_),
1726 parse_funcs_{&invoke_parse<T, Char>...} {
1727 int arg_index = 0, named_arg_index = 0;
1728 FMTQUILL_APPLY_VARIADIC(
1729 init_static_named_arg<T>(named_args_, arg_index, named_arg_index));
1730 ignore_unused(arg_index, named_arg_index);
1733 FMTQUILL_CONSTEXPR
void on_text(
const Char*,
const Char*) {}
1735 FMTQUILL_CONSTEXPR
auto on_arg_id() ->
int {
return context_.next_arg_id(); }
1736 FMTQUILL_CONSTEXPR
auto on_arg_id(
int id) ->
int {
1737 context_.check_arg_id(
id);
1741 for (
int i = 0; i < NUM_NAMED_ARGS; ++i) {
1742 if (named_args_[i].name ==
id)
return named_args_[i].id;
1744 if (!DYNAMIC_NAMES) on_error(
"argument not found");
1748 FMTQUILL_CONSTEXPR
void on_replacement_field(
int id,
const Char* begin) {
1749 on_format_specs(
id, begin, begin);
1752 FMTQUILL_CONSTEXPR
auto on_format_specs(
int id,
const Char* begin,
const Char* end)
1754 context_.advance_to(begin);
1755 if (
id >= 0 &&
id < NUM_ARGS)
return parse_funcs_[id](context_);
1760 for (
int bracket_count = 0;
1761 begin != end && (bracket_count > 0 || *begin !=
'}'); ++begin) {
1764 else if (*begin ==
'}')
1770 FMTQUILL_NORETURN FMTQUILL_CONSTEXPR
void on_error(
const char* message) {
1771 report_error(message);
1783 using grow_fun = void (*)(
buffer& buf,
size_t capacity);
1788 FMTQUILL_MSC_WARNING(suppress : 26495)
1789 FMTQUILL_CONSTEXPR
buffer(grow_fun grow,
size_t sz) noexcept
1790 : size_(sz), capacity_(sz), grow_(grow) {}
1792 constexpr
buffer(grow_fun grow, T* p =
nullptr,
size_t sz = 0,
1793 size_t cap = 0) noexcept
1794 : ptr_(p), size_(sz), capacity_(cap), grow_(grow) {}
1796 FMTQUILL_CONSTEXPR20 ~
buffer() =
default;
1800 FMTQUILL_CONSTEXPR
void set(T* buf_data,
size_t buf_capacity) noexcept {
1802 capacity_ = buf_capacity;
1806 using value_type = T;
1807 using const_reference =
const T&;
1810 void operator=(
const buffer&) =
delete;
1812 auto begin() noexcept -> T* {
return ptr_; }
1813 auto end() noexcept -> T* {
return ptr_ + size_; }
1815 auto begin()
const noexcept ->
const T* {
return ptr_; }
1816 auto end()
const noexcept ->
const T* {
return ptr_ + size_; }
1819 constexpr
auto size() const noexcept ->
size_t {
return size_; }
1822 constexpr
auto capacity() const noexcept ->
size_t {
return capacity_; }
1825 FMTQUILL_CONSTEXPR
auto data() noexcept -> T* {
return ptr_; }
1826 FMTQUILL_CONSTEXPR
auto data()
const noexcept ->
const T* {
return ptr_; }
1829 FMTQUILL_CONSTEXPR
void clear() { size_ = 0; }
1833 FMTQUILL_CONSTEXPR
void try_resize(
size_t count) {
1835 size_ = min_of(count, capacity_);
1842 FMTQUILL_CONSTEXPR
void try_reserve(
size_t new_capacity) {
1843 if (new_capacity > capacity_) grow_(*
this, new_capacity);
1846 FMTQUILL_CONSTEXPR
void push_back(
const T& value) {
1847 try_reserve(size_ + 1);
1848 ptr_[size_++] = value;
1852 template <
typename U>
1855 #if !FMTQUILL_MSC_VERSION || FMTQUILL_MSC_VERSION >= 1940 1856 FMTQUILL_CONSTEXPR20
1860 while (begin != end) {
1862 auto free_cap = capacity_ - size;
1863 auto count = to_unsigned(end - begin);
1865 if (free_cap < count) {
1866 grow_(*
this, size + count);
1868 free_cap = capacity_ - size;
1869 count = count < free_cap ? count : free_cap;
1872 if constexpr (std::is_same<T, U>::value) {
1873 memcpy(ptr_ + size_, begin, count *
sizeof(T));
1875 T* out = ptr_ + size_;
1876 for (
size_t i = 0; i < count; ++i) out[i] = begin[i];
1884 template <
typename Idx> FMTQUILL_CONSTEXPR
auto operator[](Idx index) -> T& {
1887 template <
typename Idx>
1888 FMTQUILL_CONSTEXPR
auto operator[](Idx index)
const ->
const T& {
1895 constexpr
auto count()
const ->
size_t {
return 0; }
1896 constexpr
auto limit(
size_t size)
const ->
size_t {
return size; }
1906 constexpr
auto count()
const ->
size_t {
return count_; }
1907 FMTQUILL_CONSTEXPR
auto limit(
size_t size) ->
size_t {
1908 size_t n = limit_ > count_ ? limit_ - count_ : 0;
1910 return min_of(size, n);
1915 template <
typename OutputIt,
typename T,
typename Traits = buffer_traits>
1919 enum { buffer_size = 256 };
1920 T data_[buffer_size];
1922 static FMTQUILL_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
1923 if (buf.
size() == buffer_size) static_cast<iterator_buffer&>(buf).flush();
1927 auto size = this->size();
1929 const T* begin = data_;
1930 const T* end = begin + this->limit(size);
1931 while (begin != end) *out_++ = *begin++;
1936 : Traits(n),
buffer<T>(grow, data_, 0, buffer_size), out_(out) {}
1943 FMTQUILL_TRY { flush(); }
1944 FMTQUILL_CATCH(...) {}
1947 auto out() -> OutputIt {
1951 auto count()
const ->
size_t {
return Traits::count() + this->size(); }
1954 template <
typename T>
1959 enum { buffer_size = 256 };
1960 T data_[buffer_size];
1962 static FMTQUILL_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
1964 static_cast<iterator_buffer&>(buf).flush();
1968 size_t n = this->limit(this->size());
1969 if (this->data() == out_) {
1971 this->
set(data_, buffer_size);
1983 if (this->data() != out_) {
1984 this->
set(data_, buffer_size);
1994 auto count()
const ->
size_t {
1995 return fixed_buffer_traits::count() + this->size();
2004 auto out() -> T* {
return &*this->end(); }
2007 template <
typename Container>
2010 using value_type =
typename Container::value_type;
2014 self.container.resize(capacity);
2015 self.set(&
self.container[0], capacity);
2019 Container& container;
2026 template <
typename OutputIt>
2031 typename OutputIt::container_type::value_type>>
2039 :
base(get_container(out)) {}
2041 auto out() -> OutputIt {
return OutputIt(this->container); }
2047 enum { buffer_size = 256 };
2048 T data_[buffer_size];
2051 static FMTQUILL_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
2052 if (buf.
size() != buffer_size)
return;
2060 constexpr
auto count()
const noexcept ->
size_t {
2061 return count_ + this->size();
2065 template <
typename T>
2068 template <
typename OutputIt,
typename InputIt,
typename =
void>
2070 template <
typename OutputIt,
typename InputIt>
2073 void_t<decltype(get_container(std::declval<OutputIt>())
2074 .append(std::declval<InputIt>(),
2075 std::declval<InputIt>()))>> : std::true_type {};
2077 template <
typename OutputIt,
typename InputIt,
typename =
void>
2080 template <
typename OutputIt,
typename InputIt>
2083 void_t<decltype(get_container(std::declval<OutputIt>())
2084 .insert(get_container(std::declval<OutputIt>()).end(),
2085 std::declval<InputIt>(),
2086 std::declval<InputIt>()))>> : std::true_type {};
2089 template <
typename T,
typename InputIt,
typename OutputIt,
2092 OutputIt, InputIt>::value)>
2093 FMTQUILL_CONSTEXPR20
auto copy(InputIt begin, InputIt end, OutputIt out)
2095 get_container(out).append(begin, end);
2099 template <
typename T,
typename InputIt,
typename OutputIt,
2102 OutputIt, InputIt>::value &&
2104 OutputIt, InputIt>::value)>
2105 FMTQUILL_CONSTEXPR20
auto copy(InputIt begin, InputIt end, OutputIt out)
2107 auto& c = get_container(out);
2108 c.insert(c.end(), begin, end);
2112 template <
typename T,
typename InputIt,
typename OutputIt,
2115 OutputIt, InputIt>::value ||
2117 OutputIt, InputIt>::value)))>
2118 FMTQUILL_CONSTEXPR
auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
2119 #if defined(__GNUC__) && !defined(__clang__) 2120 #pragma GCC diagnostic push 2121 #pragma GCC diagnostic ignored "-Wstringop-overflow" 2124 while (begin != end) *out++ =
static_cast<T
>(*begin++);
2126 #if defined(__GNUC__) && !defined(__clang__) 2127 #pragma GCC diagnostic pop 2133 template <
typename T,
typename V,
typename OutputIt>
2135 return copy<T>(s.begin(), s.end(), out);
2138 template <
typename It,
typename Enable = std::true_type>
2140 template <
typename It>
2144 std::is_base_of<buffer<typename It::container_type::value_type>,
2145 typename It::container_type>
::value>>
2146 : std::true_type {};
2149 template <
typename T,
typename OutputIt,
2154 template <
typename T,
typename OutputIt,
2156 auto get_buffer(OutputIt out) ->
buffer<T>& {
2157 return get_container(out);
2160 template <
typename Buf,
typename OutputIt>
2161 auto get_iterator(Buf& buf, OutputIt) -> decltype(buf.out()) {
2164 template <
typename T,
typename OutputIt>
2165 auto get_iterator(
buffer<T>&, OutputIt out) -> OutputIt {
2179 using char_type =
typename Context::char_type;
2191 #if !FMTQUILL_BUILTIN_TYPES 2192 # define FMTQUILL_BUILTIN , monostate 2194 # define FMTQUILL_BUILTIN 2198 template <
typename Context>
class value {
2200 using char_type =
typename Context::char_type;
2205 unsigned uint_value;
2206 long long long_long_value;
2207 unsigned long long ulong_long_value;
2208 int128_opt int128_value;
2209 uint128_opt uint128_value;
2211 char_type char_value;
2213 double double_value;
2214 long double long_double_value;
2215 const void* pointer;
2221 constexpr FMTQUILL_INLINE value() : no_value() {}
2222 constexpr FMTQUILL_INLINE value(
signed char x) : int_value(x) {}
2223 constexpr FMTQUILL_INLINE value(
unsigned char x FMTQUILL_BUILTIN) : uint_value(x) {}
2224 constexpr FMTQUILL_INLINE value(
signed short x) : int_value(x) {}
2225 constexpr FMTQUILL_INLINE value(
unsigned short x FMTQUILL_BUILTIN) : uint_value(x) {}
2226 constexpr FMTQUILL_INLINE value(
int x) : int_value(x) {}
2227 constexpr FMTQUILL_INLINE value(
unsigned x FMTQUILL_BUILTIN) : uint_value(x) {}
2228 FMTQUILL_CONSTEXPR FMTQUILL_INLINE value(
long x FMTQUILL_BUILTIN) : value(long_type(x)) {}
2229 FMTQUILL_CONSTEXPR FMTQUILL_INLINE value(
unsigned long x FMTQUILL_BUILTIN)
2230 : value(ulong_type(x)) {}
2231 constexpr FMTQUILL_INLINE value(
long long x FMTQUILL_BUILTIN) : long_long_value(x) {}
2232 constexpr FMTQUILL_INLINE value(
unsigned long long x FMTQUILL_BUILTIN)
2233 : ulong_long_value(x) {}
2234 FMTQUILL_INLINE value(int128_opt x FMTQUILL_BUILTIN) : int128_value(x) {}
2235 FMTQUILL_INLINE value(uint128_opt x FMTQUILL_BUILTIN) : uint128_value(x) {}
2236 constexpr FMTQUILL_INLINE value(
bool x FMTQUILL_BUILTIN) : bool_value(x) {}
2239 constexpr FMTQUILL_INLINE value(
bitint<N> x FMTQUILL_BUILTIN) : long_long_value(x) {
2240 static_assert(N <= 64,
"unsupported _BitInt");
2243 constexpr FMTQUILL_INLINE value(
ubitint<N> x FMTQUILL_BUILTIN) : ulong_long_value(x) {
2244 static_assert(N <= 64,
"unsupported _BitInt");
2247 template <typename T, FMTQUILL_ENABLE_IF(is_code_unit<T>::value)>
2248 constexpr FMTQUILL_INLINE value(T x FMTQUILL_BUILTIN) : char_value(x) {
2250 std::is_same<T, char>::value || std::is_same<T, char_type>::value,
2251 "mixing character types is disallowed");
2254 constexpr FMTQUILL_INLINE value(
float x FMTQUILL_BUILTIN) : float_value(x) {}
2255 constexpr FMTQUILL_INLINE value(
double x FMTQUILL_BUILTIN) : double_value(x) {}
2256 FMTQUILL_INLINE value(
long double x FMTQUILL_BUILTIN) : long_double_value(x) {}
2258 FMTQUILL_CONSTEXPR FMTQUILL_INLINE value(char_type* x FMTQUILL_BUILTIN) {
2260 if (is_constant_evaluated())
string.size = 0;
2262 FMTQUILL_CONSTEXPR FMTQUILL_INLINE value(
const char_type* x FMTQUILL_BUILTIN) {
2264 if (is_constant_evaluated())
string.size = 0;
2266 template <
typename T,
typename C =
char_t<T>,
2267 FMTQUILL_ENABLE_IF(!std::is_po
inter<T>::value)>
2268 FMTQUILL_CONSTEXPR value(
const T& x FMTQUILL_BUILTIN) {
2269 static_assert(std::is_same<C, char_type>::value,
2270 "mixing character types is disallowed");
2271 auto sv = to_string_view(x);
2272 string.data = sv.data();
2273 string.size = sv.size();
2275 FMTQUILL_INLINE value(
void* x FMTQUILL_BUILTIN) : pointer(x) {}
2276 FMTQUILL_INLINE value(
const void* x FMTQUILL_BUILTIN) : pointer(x) {}
2277 FMTQUILL_INLINE value(
volatile void* x FMTQUILL_BUILTIN)
2278 : pointer(const_cast<const void*>(x)) {}
2279 FMTQUILL_INLINE value(
const volatile void* x FMTQUILL_BUILTIN)
2280 : pointer(const_cast<const void*>(x)) {}
2281 FMTQUILL_INLINE value(nullptr_t) : pointer(
nullptr) {}
2283 template <typename T, FMTQUILL_ENABLE_IF(std::is_pointer<T>::value ||
2284 std::is_member_pointer<T>::value)>
2289 static_assert(
sizeof(T) == 0,
2290 "formatting of non-void pointers is disallowed");
2293 template <typename T, FMTQUILL_ENABLE_IF(use_format_as<T>::value)>
2294 value(
const T& x) : value(format_as(x)) {}
2295 template <typename T, FMTQUILL_ENABLE_IF(use_format_as_member<T>::value)>
2296 value(
const T& x) : value(formatter<T>::format_as(x)) {}
2298 template <typename T, FMTQUILL_ENABLE_IF(is_named_arg<T>::value)>
2299 value(
const T&
named_arg) : value(named_arg.value) {}
2301 template <
typename T,
2302 FMTQUILL_ENABLE_IF(use_formatter<T>::value || !FMTQUILL_BUILTIN_TYPES)>
2303 FMTQUILL_CONSTEXPR20 FMTQUILL_INLINE value(T& x) : value(x,
custom_tag()) {}
2306 : named_args{args, size} {}
2309 template <
typename T, FMTQUILL_ENABLE_IF(has_formatter<T,
char_type>())>
2311 using value_type = remove_const_t<T>;
2313 if (!is_constant_evaluated()) {
2315 const_cast<char*
>(&
reinterpret_cast<const volatile char&
>(x));
2317 custom.value =
nullptr;
2318 #if defined(__cpp_if_constexpr) 2319 if constexpr (std::is_same<decltype(&x), remove_reference_t<T>*>::value)
2320 custom.value =
const_cast<value_type*
>(&x);
2323 custom.format = format_custom<value_type>;
2326 template <
typename T, FMTQUILL_ENABLE_IF(!has_formatter<T,
char_type>())>
2327 FMTQUILL_CONSTEXPR value(
const T&,
custom_tag) {
2334 template <
typename T>
2337 auto f = formatter<T, char_type>();
2339 using qualified_type =
2340 conditional_t<has_formatter<const T, char_type>(),
const T, T>;
2343 ctx.advance_to(cf.format(*static_cast<qualified_type*>(arg), ctx));
2347 enum { packed_arg_bits = 4 };
2349 enum { max_packed_args = 62 / packed_arg_bits };
2350 enum :
unsigned long long { is_unpacked_bit = 1ULL << 63 };
2351 enum :
unsigned long long { has_named_args_bit = 1ULL << 62 };
2353 template <
typename It,
typename T,
typename Enable =
void>
2358 template <
typename It,
typename T>
2361 enable_if_t<std::is_assignable<decltype(*std::declval<decay_t<It>&>()++),
2362 T>
::value>> : std::true_type {};
2364 template <
typename> constexpr
auto encode_types() ->
unsigned long long {
2368 template <
typename Context,
typename First,
typename... T>
2369 constexpr
auto encode_types() ->
unsigned long long {
2370 return static_cast<unsigned>(stored_type_constant<First, Context>::value) |
2371 (encode_types<Context, T...>() << packed_arg_bits);
2374 template <
typename Context,
typename... T,
size_t NUM_ARGS =
sizeof...(T)>
2375 constexpr
auto make_descriptor() ->
unsigned long long {
2376 return NUM_ARGS <= max_packed_args ? encode_types<Context, T...>()
2377 : is_unpacked_bit | NUM_ARGS;
2380 template <
typename Context,
int NUM_ARGS>
2381 using arg_t = conditional_t<NUM_ARGS <= max_packed_args, value<Context>,
2384 template <
typename Context,
int NUM_ARGS,
int NUM_NAMED_ARGS,
2385 unsigned long long DESC>
2388 arg_t<Context, NUM_ARGS> args[1u + NUM_ARGS];
2390 named_args[
static_cast<size_t>(NUM_NAMED_ARGS)];
2392 template <
typename... T>
2393 FMTQUILL_CONSTEXPR FMTQUILL_ALWAYS_INLINE
named_arg_store(T&... values)
2394 : args{{named_args, NUM_NAMED_ARGS}, values...} {
2395 int arg_index = 0, named_arg_index = 0;
2396 FMTQUILL_APPLY_VARIADIC(
2397 init_named_arg(named_args, arg_index, named_arg_index, values));
2400 named_arg_store(named_arg_store&& rhs) {
2401 args[0] = {named_args, NUM_NAMED_ARGS};
2402 for (
size_t i = 1; i <
sizeof(args) /
sizeof(*args); ++i)
2403 args[i] = rhs.args[i];
2404 for (
size_t i = 0; i < NUM_NAMED_ARGS; ++i)
2405 named_args[i] = rhs.named_args[i];
2408 named_arg_store(
const named_arg_store& rhs) =
delete;
2409 auto operator=(
const named_arg_store& rhs) -> named_arg_store& =
delete;
2410 auto operator=(named_arg_store&& rhs) -> named_arg_store& =
delete;
2411 operator const arg_t<Context, NUM_ARGS>*()
const {
return args + 1; }
2417 template <
typename Context,
int NUM_ARGS,
int NUM_NAMED_ARGS,
2418 unsigned long long DESC>
2422 conditional_t<NUM_NAMED_ARGS == 0,
2423 arg_t<Context, NUM_ARGS>[max_of<size_t>(1, NUM_ARGS)],
2434 using nonlocking = void;
2438 auto end = parse_format_specs(ctx.
begin(), ctx.
end(), specs_, ctx, TYPE);
2439 if (const_check(TYPE == type::char_type)) check_char_specs(specs_);
2443 template <type U = TYPE,
2444 FMTQUILL_ENABLE_IF(U == type::string_type || U == type::cstring_type ||
2445 U == type::char_type)>
2446 FMTQUILL_CONSTEXPR
void set_debug_format(
bool set =
true) {
2447 specs_.set_type(
set ? presentation_type::debug : presentation_type::none);
2450 FMTQUILL_PRAGMA_CLANG(diagnostic ignored
"-Wundefined-inline")
2451 template <
typename FormatContext>
2452 FMTQUILL_CONSTEXPR
auto format(
const T& val, FormatContext& ctx)
const 2453 -> decltype(ctx.out());
2456 template <
typename T,
typename Enable =
void>
2458 : bool_constant<mapped_type_constant<T>::value == type::custom_type> {};
2459 template <
typename T>
2460 struct locking<T, void_t<typename formatter<remove_cvref_t<T>>::nonlocking>>
2461 : std::false_type {};
2463 template <
typename T =
int> FMTQUILL_CONSTEXPR
inline auto is_locking() ->
bool {
2466 template <
typename T1,
typename T2,
typename... Tail>
2467 FMTQUILL_CONSTEXPR
inline auto is_locking() ->
bool {
2476 #else // format_args is passed by reference since it is defined later. 2483 template <
typename Char>
2487 if (detail::is_constant_evaluated() && use_constexpr_cast) {
2489 if (arg_id >= ctx->num_args()) report_error(
"argument not found");
2493 template <
typename Char>
2496 if (detail::is_constant_evaluated() && use_constexpr_cast)
2500 FMTQUILL_BEGIN_EXPORT
2513 FMTQUILL_CONSTEXPR20
auto operator=(T c) -> basic_appender& {
2514 container->push_back(c);
2517 FMTQUILL_CONSTEXPR20
auto operator*() -> basic_appender& {
return *
this; }
2518 FMTQUILL_CONSTEXPR20
auto operator++() -> basic_appender& {
return *
this; }
2519 FMTQUILL_CONSTEXPR20
auto operator++(
int) -> basic_appender {
return *
this; }
2531 using char_type =
typename Context::char_type;
2542 custom_.format(custom_.value, parse_ctx, ctx);
2548 : value_(args, size) {}
2549 template <
typename T>
2550 basic_format_arg(T&& val)
2551 : value_(val), type_(detail::stored_type_constant<T, Context>::value) {}
2553 constexpr
explicit operator bool()
const noexcept {
2554 return type_ != detail::type::none_type;
2556 auto type()
const -> detail::type {
return type_; }
2563 template <
typename Visitor>
2564 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
auto visit(Visitor&& vis)
const -> decltype(vis(0)) {
2567 case detail::type::none_type:
break;
2568 case detail::type::int_type:
return vis(value_.int_value);
2569 case detail::type::uint_type:
return vis(value_.uint_value);
2570 case detail::type::long_long_type:
return vis(value_.long_long_value);
2571 case detail::type::ulong_long_type:
return vis(value_.ulong_long_value);
2572 case detail::type::int128_type:
return vis(map(value_.int128_value));
2573 case detail::type::uint128_type:
return vis(map(value_.uint128_value));
2574 case detail::type::bool_type:
return vis(value_.bool_value);
2575 case detail::type::char_type:
return vis(value_.char_value);
2576 case detail::type::float_type:
return vis(value_.float_value);
2577 case detail::type::double_type:
return vis(value_.double_value);
2578 case detail::type::long_double_type:
return vis(value_.long_double_value);
2579 case detail::type::cstring_type:
return vis(value_.string.data);
2580 case detail::type::string_type:
return vis(value_.string.str());
2581 case detail::type::pointer_type:
return vis(value_.pointer);
2582 case detail::type::custom_type:
return vis(handle(value_.custom));
2587 auto format_custom(
const char_type* parse_begin,
2590 if (type_ != detail::type::custom_type)
return false;
2592 value_.custom.format(value_.custom.value, parse_ctx, ctx);
2611 unsigned long long desc_;
2622 constexpr
auto is_packed()
const ->
bool {
2623 return (desc_ & detail::is_unpacked_bit) == 0;
2625 constexpr
auto has_named_args()
const ->
bool {
2626 return (desc_ & detail::has_named_args_bit) != 0;
2629 FMTQUILL_CONSTEXPR
auto type(
int index)
const -> detail::type {
2630 int shift = index * detail::packed_arg_bits;
2631 unsigned mask = (1 << detail::packed_arg_bits) - 1;
2632 return static_cast<detail::type
>((desc_ >> shift) & mask);
2635 template <
int NUM_ARGS,
int NUM_NAMED_ARGS,
unsigned long long DESC>
2645 template <
int NUM_ARGS,
int NUM_NAMED_ARGS,
unsigned long long DESC,
2646 FMTQUILL_ENABLE_IF(NUM_ARGS <= detail::max_packed_args)>
2649 : desc_(DESC | (NUM_NAMED_ARGS != 0 ? +
detail::has_named_args_bit : 0)),
2652 template <
int NUM_ARGS,
int NUM_NAMED_ARGS,
unsigned long long DESC,
2653 FMTQUILL_ENABLE_IF(NUM_ARGS > detail::max_packed_args)>
2655 : desc_(DESC | (NUM_NAMED_ARGS != 0 ? +detail::has_named_args_bit : 0)),
2660 bool has_named =
false)
2661 : desc_(
detail::is_unpacked_bit |
detail::to_unsigned(count) |
2662 (has_named ? +
detail::has_named_args_bit : 0)),
2669 if (
id < max_size()) arg = args_[id];
2672 if (static_cast<unsigned>(
id) >= detail::max_packed_args)
return arg;
2673 arg.type_ = type(
id);
2674 if (arg.type_ != detail::type::none_type) arg.value_ = values_[id];
2678 template <
typename Char>
2680 int id = get_id(name);
2684 template <
typename Char>
2686 if (!has_named_args())
return -1;
2687 const auto& named_args =
2688 (is_packed() ? values_[-1] : args_[-1].value_).named_args;
2689 for (
size_t i = 0; i < named_args.size; ++i) {
2690 if (named_args.data[i].name == name)
return named_args.data[i].id;
2695 auto max_size()
const ->
int {
2696 unsigned long long max_packed = detail::max_packed_args;
2697 return static_cast<int>(is_packed() ? max_packed
2698 : desc_ & ~
detail::is_unpacked_bit);
2710 using char_type = char;
2713 enum { builtin_types = FMTQUILL_BUILTIN_TYPES };
2718 : out_(out), args_(args), loc_(loc) {}
2719 context(context&&) =
default;
2720 context(
const context&) =
delete;
2721 void operator=(
const context&) =
delete;
2723 FMTQUILL_CONSTEXPR
auto arg(
int id)
const ->
format_arg {
return args_.
get(
id); }
2725 return args_.
get(name);
2727 FMTQUILL_CONSTEXPR
auto arg_id(
string_view name)
const ->
int {
2728 return args_.get_id(name);
2730 auto args()
const ->
const format_args& {
return args_; }
2733 FMTQUILL_CONSTEXPR
auto out()
const ->
iterator {
return out_; }
2736 FMTQUILL_CONSTEXPR
void advance_to(
iterator) {}
2738 FMTQUILL_CONSTEXPR
auto locale()
const ->
locale_ref {
return loc_; }
2759 static constexpr
int num_static_named_args =
2760 detail::count_static_named_args<T...>();
2763 char,
static_cast<int>(
sizeof...(T)), num_static_named_args,
2764 num_static_named_args != detail::count_named_args<T...>()>;
2774 FMTQUILL_CONSTEVAL FMTQUILL_ALWAYS_INLINE
fstring(
const char (&s)[N]) : str(s, N - 1) {
2776 static_assert(count<(
is_view<remove_cvref_t<T>>::
value &&
2777 std::is_reference<T>::value)...>() == 0,
2778 "passing views as lvalues is disallowed");
2779 if (FMTQUILL_USE_CONSTEVAL) parse_format_string<char>(s,
checker(s,
arg_pack()));
2780 #ifdef FMTQUILL_ENFORCE_COMPILE_STRING 2782 FMTQUILL_USE_CONSTEVAL &&
sizeof(s) != 0,
2783 "FMTQUILL_ENFORCE_COMPILE_STRING requires format strings to use FMTQUILL_STRING");
2786 template <
typename S,
2787 FMTQUILL_ENABLE_IF(std::is_convertible<const S&, string_view>::value)>
2788 FMTQUILL_CONSTEVAL FMTQUILL_ALWAYS_INLINE fstring(
const S& s) : str(s) {
2790 if (FMTQUILL_USE_CONSTEVAL)
2792 #ifdef FMTQUILL_ENFORCE_COMPILE_STRING 2794 FMTQUILL_USE_CONSTEVAL &&
sizeof(s) != 0,
2795 "FMTQUILL_ENFORCE_COMPILE_STRING requires format strings to use FMTQUILL_STRING");
2798 template <
typename S,
2799 FMTQUILL_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
2800 std::is_same<typename S::char_type, char>::value)>
2801 FMTQUILL_ALWAYS_INLINE fstring(
const S&) : str(S()) {
2803 FMTQUILL_CONSTEXPR
int unused =
2805 detail::ignore_unused(unused);
2810 FMTQUILL_ALWAYS_INLINE
operator const string_view&()
const {
return str; }
2814 template <
typename... T>
using format_string =
typename fstring<T...>
::t;
2816 template <
typename T,
typename Char =
char>
2817 using is_formattable = bool_constant<!std::is_same<
2818 detail::mapped_t<conditional_t<std::is_void<T>::value,
int*, T>, Char>,
2820 #ifdef __cpp_concepts 2821 template <
typename T,
typename Char =
char>
2822 concept formattable = is_formattable<remove_reference_t<T>, Char>::value;
2826 template <
typename T,
typename Char>
2827 struct formatter<T, Char,
2829 detail::type::custom_type>>
2840 template <
typename Context = context,
typename... T,
2841 int NUM_ARGS =
sizeof...(T),
2842 int NUM_NAMED_ARGS = detail::count_named_args<T...>(),
2843 unsigned long long DESC = detail::make_descriptor<Context, T...>()>
2844 constexpr FMTQUILL_ALWAYS_INLINE
auto make_format_args(T&... args)
2847 FMTQUILL_PRAGMA_GCC(diagnostic ignored
"-Wconversion")
2851 template <
typename... T>
2854 detail::count_named_args<T...>(),
2855 detail::make_descriptor<context, T...>()>;
2865 template <
typename Char,
typename T>
2871 template <
typename OutputIt,
2875 -> remove_cvref_t<OutputIt> {
2876 auto&& buf = detail::get_buffer<char>(out);
2877 detail::vformat_to(buf, fmt, args, {});
2878 return detail::get_iterator(buf, out);
2891 template <
typename OutputIt,
typename... T,
2894 FMTQUILL_INLINE
auto format_to(OutputIt&& out, format_string<T...> fmt, T&&... args)
2895 -> remove_cvref_t<OutputIt> {
2896 return vformat_to(out, fmt.str,
vargs<T...>{{args...}});
2906 template <
typename OutputIt,
typename... T,
2912 detail::vformat_to(buf, fmt, args, {});
2913 return {buf.out(), buf.count()};
2922 template <
typename OutputIt,
typename... T,
2924 FMTQUILL_INLINE
auto format_to_n(OutputIt out,
size_t n, format_string<T...> fmt,
2926 return vformat_to_n(out, n, fmt.str,
vargs<T...>{{args...}});
2935 FMTQUILL_CONSTEXPR
operator char*()
const {
2937 if (truncated) report_error(
"output is truncated");
2945 auto result = vformat_to_n(out, N, fmt, args);
2946 return {result.out, result.size > N};
2949 template <
size_t N,
typename... T>
2950 FMTQUILL_INLINE
auto format_to(
char (&out)[N], format_string<T...> fmt, T&&... args)
2952 auto result = vformat_to_n(out, N, fmt.str,
vargs<T...>{{args...}});
2953 return {result.out, result.size > N};
2957 template <
typename... T>
2958 FMTQUILL_NODISCARD FMTQUILL_INLINE
auto formatted_size(format_string<T...> fmt,
2959 T&&... args) ->
size_t {
2961 detail::vformat_to(buf, fmt.str,
vargs<T...>{{args...}}, {});
2978 template <
typename... T>
2979 FMTQUILL_INLINE
void print(format_string<T...> fmt, T&&... args) {
2980 vargs<T...> va = {{args...}};
2981 if (detail::const_check(!detail::use_utf8))
2982 return detail::vprint_mojibake(stdout, fmt.str, va,
false);
2983 return detail::is_locking<T...>() ? vprint_buffered(stdout, fmt.str, va)
2984 : vprint(fmt.str, va);
2995 template <
typename... T>
2996 FMTQUILL_INLINE
void print(FILE* f, format_string<T...> fmt, T&&... args) {
2997 vargs<T...> va = {{args...}};
2998 if (detail::const_check(!detail::use_utf8))
2999 return detail::vprint_mojibake(f, fmt.str, va,
false);
3000 return detail::is_locking<T...>() ? vprint_buffered(f, fmt.str, va)
3001 : vprint(f, fmt.str, va);
3006 template <
typename... T>
3007 FMTQUILL_INLINE
void println(FILE* f, format_string<T...> fmt, T&&... args) {
3008 vargs<T...> va = {{args...}};
3009 return detail::const_check(detail::use_utf8)
3010 ? vprintln(f, fmt.str, va)
3011 : detail::vprint_mojibake(f, fmt.str, va,
true);
3016 template <
typename... T>
3017 FMTQUILL_INLINE
void println(format_string<T...> fmt, T&&... args) {
3018 return fmtquill::println(stdout, fmt, static_cast<T&&>(args)...);
3021 FMTQUILL_PRAGMA_GCC(diagnostic pop)
3022 FMTQUILL_PRAGMA_CLANG(diagnostic pop)
3023 FMTQUILL_PRAGMA_GCC(pop_options)
3025 FMTQUILL_END_NAMESPACE
3028 #endif // FMTQUILL_BASE_H_
FMTQUILL_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition: base.h:1825
A compile-time format string.
Definition: base.h:2757
FMTQUILL_CONSTEXPR context(iterator out, format_args args, locale_ref loc={})
Constructs a context object.
Definition: base.h:2717
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition: base.h:634
Definition: UserDefinedDirectFormatFuzzer.cpp:81
FMTQUILL_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:904
FMTQUILL_CONSTEXPR20 basic_string_view(const Char *s)
Constructs a string view object from a C string.
Definition: base.h:547
FMTQUILL_CONSTEXPR20 void append(const U *begin, const U *end)
Appends data to the end of the buffer.
Definition: base.h:1859
Definition: LogFunctions.h:177
constexpr auto data() const noexcept -> const Char *
Returns a pointer to the string data.
Definition: base.h:568
FMTQUILL_CONSTEXPR void advance_to(iterator it)
Advances the begin iterator to it.
Definition: base.h:886
constexpr auto size() const noexcept -> size_t
Returns the string size.
Definition: base.h:571
FMTQUILL_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:892
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:24
An implementation of std::basic_string_view for pre-C++17.
Definition: base.h:526
FMTQUILL_CONSTEXPR void clear()
Clears this buffer.
Definition: base.h:1829
constexpr auto end() const noexcept -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition: base.h:883
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition: base.h:1819
typename V::value_type char_t
String's character (code unit) type. detail:: is intentional to prevent ADL.
Definition: base.h:987
constexpr auto capacity() const noexcept -> size_t
Returns the capacity of this buffer.
Definition: base.h:1822
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:538
constexpr auto begin() const noexcept -> iterator
Returns an iterator to the beginning of the format string range being parsed.
Definition: base.h:880
FMTQUILL_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:564
A contiguous memory buffer with an optional growing ability.
Definition: base.h:1777