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 110200 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 #if !defined(__cpp_lib_is_constant_evaluated) 122 # define FMTQUILL_USE_CONSTEVAL 0 123 #elif FMTQUILL_CPLUSPLUS < 201709L 124 # define FMTQUILL_USE_CONSTEVAL 0 125 #elif FMTQUILL_GLIBCXX_RELEASE && FMTQUILL_GLIBCXX_RELEASE < 10 126 # define FMTQUILL_USE_CONSTEVAL 0 127 #elif FMTQUILL_LIBCPP_VERSION && FMTQUILL_LIBCPP_VERSION < 10000 128 # define FMTQUILL_USE_CONSTEVAL 0 129 #elif defined(__apple_build_version__) && __apple_build_version__ < 14000029L 130 # define FMTQUILL_USE_CONSTEVAL 0 // consteval is broken in Apple clang < 14. 131 #elif FMTQUILL_MSC_VERSION && FMTQUILL_MSC_VERSION < 1929 132 # define FMTQUILL_USE_CONSTEVAL 0 // consteval is broken in MSVC VS2019 < 16.10. 133 #elif defined(__cpp_consteval) 134 # define FMTQUILL_USE_CONSTEVAL 1 135 #elif FMTQUILL_GCC_VERSION >= 1002 || FMTQUILL_CLANG_VERSION >= 1101 136 # define FMTQUILL_USE_CONSTEVAL 1 138 # define FMTQUILL_USE_CONSTEVAL 0 140 #if FMTQUILL_USE_CONSTEVAL 141 # define FMTQUILL_CONSTEVAL consteval 142 # define FMTQUILL_CONSTEXPR20 constexpr 144 # define FMTQUILL_CONSTEVAL 145 # define FMTQUILL_CONSTEXPR20 149 #ifdef FMTQUILL_USE_EXCEPTIONS 151 #elif defined(__GNUC__) && !defined(__EXCEPTIONS) 152 # define FMTQUILL_USE_EXCEPTIONS 0 153 #elif defined(__clang__) && !defined(__cpp_exceptions) 154 # define FMTQUILL_USE_EXCEPTIONS 0 155 #elif FMTQUILL_MSC_VERSION && !_HAS_EXCEPTIONS 156 # define FMTQUILL_USE_EXCEPTIONS 0 158 # define FMTQUILL_USE_EXCEPTIONS 1 160 #if FMTQUILL_USE_EXCEPTIONS 161 # define FMTQUILL_TRY try 162 # define FMTQUILL_CATCH(x) catch (x) 164 # define FMTQUILL_TRY if (true) 165 # define FMTQUILL_CATCH(x) if (false) 168 #ifdef FMTQUILL_NO_UNIQUE_ADDRESS 170 #elif FMTQUILL_CPLUSPLUS < 202002L 172 #elif FMTQUILL_HAS_CPP_ATTRIBUTE(no_unique_address) 173 # define FMTQUILL_NO_UNIQUE_ADDRESS [[no_unique_address]] 175 #elif FMTQUILL_MSC_VERSION >= 1929 && !FMTQUILL_CLANG_VERSION 176 # define FMTQUILL_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] 178 #ifndef FMTQUILL_NO_UNIQUE_ADDRESS 179 # define FMTQUILL_NO_UNIQUE_ADDRESS 182 #if FMTQUILL_HAS_CPP17_ATTRIBUTE(fallthrough) 183 # define FMTQUILL_FALLTHROUGH [[fallthrough]] 184 #elif defined(__clang__) 185 # define FMTQUILL_FALLTHROUGH [[clang::fallthrough]] 186 #elif FMTQUILL_GCC_VERSION >= 700 && \ 187 (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) 188 # define FMTQUILL_FALLTHROUGH [[gnu::fallthrough]] 190 # define FMTQUILL_FALLTHROUGH 194 #if FMTQUILL_HAS_CPP_ATTRIBUTE(noreturn) && !FMTQUILL_MSC_VERSION && !defined(__NVCC__) 195 # define FMTQUILL_NORETURN [[noreturn]] 197 # define FMTQUILL_NORETURN 200 #ifdef FMTQUILL_NODISCARD 202 #elif FMTQUILL_HAS_CPP17_ATTRIBUTE(nodiscard) 203 # define FMTQUILL_NODISCARD [[nodiscard]] 205 # define FMTQUILL_NODISCARD 208 #ifdef FMTQUILL_DEPRECATED 210 #elif FMTQUILL_HAS_CPP14_ATTRIBUTE(deprecated) 211 # define FMTQUILL_DEPRECATED [[deprecated]] 213 # define FMTQUILL_DEPRECATED 216 #if FMTQUILL_GCC_VERSION || FMTQUILL_CLANG_VERSION 217 # define FMTQUILL_VISIBILITY(value) __attribute__((visibility(value))) 219 # define FMTQUILL_VISIBILITY(value) 223 #define FMTQUILL_PRAGMA_IMPL(x) _Pragma(#x) 224 #if FMTQUILL_GCC_VERSION >= 504 && !defined(__NVCOMPILER) 227 # define FMTQUILL_PRAGMA_GCC(x) FMTQUILL_PRAGMA_IMPL(GCC x) 229 # define FMTQUILL_PRAGMA_GCC(x) 231 #if FMTQUILL_CLANG_VERSION 232 # define FMTQUILL_PRAGMA_CLANG(x) FMTQUILL_PRAGMA_IMPL(clang x) 234 # define FMTQUILL_PRAGMA_CLANG(x) 236 #if FMTQUILL_MSC_VERSION 237 # define FMTQUILL_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) 239 # define FMTQUILL_MSC_WARNING(...) 243 FMTQUILL_PRAGMA_GCC(push_options)
244 #if !defined(__OPTIMIZE__) && !defined(__CUDACC__) && !defined(FMTQUILL_MODULE) 245 FMTQUILL_PRAGMA_GCC(optimize(
"Og"))
246 # define FMTQUILL_GCC_OPTIMIZED 248 FMTQUILL_PRAGMA_CLANG(diagnostic push)
250 #ifdef FMTQUILL_ALWAYS_INLINE 252 #elif FMTQUILL_GCC_VERSION || FMTQUILL_CLANG_VERSION 253 # define FMTQUILL_ALWAYS_INLINE inline __attribute__((always_inline)) 255 # define FMTQUILL_ALWAYS_INLINE inline 258 #if defined(NDEBUG) || defined(FMTQUILL_GCC_OPTIMIZED) 259 # define FMTQUILL_INLINE FMTQUILL_ALWAYS_INLINE 261 # define FMTQUILL_INLINE inline 264 #ifndef FMTQUILL_BEGIN_NAMESPACE 265 # define FMTQUILL_BEGIN_NAMESPACE \ 266 namespace fmtquill { \ 267 inline namespace v11 { 268 # define FMTQUILL_END_NAMESPACE \ 273 #ifndef FMTQUILL_EXPORT 274 # define FMTQUILL_EXPORT 275 # define FMTQUILL_BEGIN_EXPORT 276 # define FMTQUILL_END_EXPORT 280 # define FMTQUILL_WIN32 1 282 # define FMTQUILL_WIN32 0 285 #if !defined(FMTQUILL_HEADER_ONLY) && FMTQUILL_WIN32 286 # if defined(FMTQUILL_LIB_EXPORT) 287 # define FMTQUILL_API __declspec(dllexport) 288 # elif defined(FMTQUILL_SHARED) 289 # define FMTQUILL_API __declspec(dllimport) 291 #elif defined(FMTQUILL_LIB_EXPORT) || defined(FMTQUILL_SHARED) 292 # define FMTQUILL_API FMTQUILL_VISIBILITY("default") 295 # define FMTQUILL_API 298 #ifndef FMTQUILL_OPTIMIZE_SIZE 299 # define FMTQUILL_OPTIMIZE_SIZE 0 304 #ifndef FMTQUILL_BUILTIN_TYPES 305 # define FMTQUILL_BUILTIN_TYPES 1 308 #define FMTQUILL_APPLY_VARIADIC(expr) \ 309 using unused = int[]; \ 310 (void)unused { 0, (expr, 0)... } 312 FMTQUILL_BEGIN_NAMESPACE
315 template <
bool B,
typename T =
void>
316 using enable_if_t =
typename std::enable_if<B, T>::type;
317 template <
bool B,
typename T,
typename F>
318 using conditional_t =
typename std::conditional<B, T, F>::type;
319 template <
bool B>
using bool_constant = std::integral_constant<bool, B>;
320 template <
typename T>
321 using remove_reference_t =
typename std::remove_reference<T>::type;
322 template <
typename T>
323 using remove_const_t =
typename std::remove_const<T>::type;
324 template <
typename T>
325 using remove_cvref_t =
typename std::remove_cv<remove_reference_t<T>>::type;
326 template <
typename T>
327 using make_unsigned_t =
typename std::make_unsigned<T>::type;
328 template <
typename T>
329 using underlying_t =
typename std::underlying_type<T>::type;
330 template <
typename T>
using decay_t =
typename std::decay<T>::type;
331 using nullptr_t = decltype(
nullptr);
333 #if (FMTQUILL_GCC_VERSION && FMTQUILL_GCC_VERSION < 500) || FMTQUILL_MSC_VERSION 335 template <
typename...>
struct void_t_impl {
338 template <
typename... T>
using void_t =
typename void_t_impl<T...>::type;
340 template <
typename...>
using void_t = void;
351 # define FMTQUILL_ENABLE_IF(...) 353 # define FMTQUILL_ENABLE_IF(...) fmtquill::enable_if_t<(__VA_ARGS__), int> = 0 356 template <
typename T> constexpr
auto min_of(T a, T b) -> T {
357 return a < b ? a : b;
359 template <
typename T> constexpr
auto max_of(T a, T b) -> T {
360 return a > b ? a : b;
367 template <
typename... T> FMTQUILL_CONSTEXPR
void ignore_unused(
const T&...) {}
369 constexpr
auto is_constant_evaluated(
bool default_value =
false) noexcept
373 #if FMTQUILL_CPLUSPLUS >= 202002L && FMTQUILL_GLIBCXX_RELEASE >= 12 && \ 374 (FMTQUILL_CLANG_VERSION >= 1400 && FMTQUILL_CLANG_VERSION < 1500) 375 ignore_unused(default_value);
376 return __builtin_is_constant_evaluated();
377 #elif defined(__cpp_lib_is_constant_evaluated) 378 ignore_unused(default_value);
379 return std::is_constant_evaluated();
381 return default_value;
386 template <
typename T> FMTQUILL_ALWAYS_INLINE constexpr
auto const_check(T val) -> T {
390 FMTQUILL_NORETURN FMTQUILL_API
void assert_fail(
const char* file,
int line,
391 const char* message);
393 #if defined(FMTQUILL_ASSERT) 395 #elif defined(NDEBUG) 397 # define FMTQUILL_ASSERT(condition, message) \ 398 fmtquill::detail::ignore_unused((condition), (message)) 400 # define FMTQUILL_ASSERT(condition, message) \ 403 : fmtquill::detail::assert_fail(__FILE__, __LINE__, (message))) 406 #ifdef FMTQUILL_USE_INT128 408 #elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \ 409 !(FMTQUILL_CLANG_VERSION && FMTQUILL_MSC_VERSION) 410 # define FMTQUILL_USE_INT128 1 411 using int128_opt = __int128_t;
412 using uint128_opt = __uint128_t;
413 inline auto map(int128_opt x) -> int128_opt {
return x; }
414 inline auto map(uint128_opt x) -> uint128_opt {
return x; }
416 # define FMTQUILL_USE_INT128 0 418 #if !FMTQUILL_USE_INT128 419 enum class int128_opt {};
420 enum class uint128_opt {};
422 inline auto map(int128_opt) ->
monostate {
return {}; }
423 inline auto map(uint128_opt) ->
monostate {
return {}; }
426 #ifndef FMTQUILL_USE_BITINT 427 # define FMTQUILL_USE_BITINT (FMTQUILL_CLANG_VERSION >= 1500) 430 #if FMTQUILL_USE_BITINT 431 FMTQUILL_PRAGMA_CLANG(diagnostic ignored
"-Wbit-int-extension")
432 template <
int N>
using bitint = _BitInt(N);
433 template <
int N>
using ubitint =
unsigned _BitInt(N);
435 template <
int N>
struct bitint {};
436 template <
int N>
struct ubitint {};
437 #endif // FMTQUILL_USE_BITINT 440 template <
typename Int>
441 FMTQUILL_CONSTEXPR
auto to_unsigned(Int
value) -> make_unsigned_t<Int> {
442 FMTQUILL_ASSERT(std::is_unsigned<Int>::value || value >= 0,
"negative value");
443 return static_cast<make_unsigned_t<Int>
>(value);
446 template <
typename Char>
447 using unsigned_char = conditional_t<sizeof(Char) == 1, unsigned char, unsigned>;
451 template <
typename T,
typename Enable =
void>
453 template <
typename T>
455 typename T::value_type(), 0))>>
456 : std::is_convertible<decltype(std::declval<T>().data()),
457 const typename T::value_type*> {};
460 enum { is_utf8_enabled =
"\u00A7"[1] ==
'\xA7' };
461 enum { use_utf8 = !FMTQUILL_WIN32 || is_utf8_enabled };
463 #ifndef FMTQUILL_UNICODE 464 # define FMTQUILL_UNICODE 0 467 static_assert(!FMTQUILL_UNICODE || use_utf8,
468 "Unicode support requires compiling with /utf-8");
470 template <
typename T> constexpr
const char* narrow(
const T*) {
return nullptr; }
471 constexpr FMTQUILL_ALWAYS_INLINE
const char* narrow(
const char* s) {
return s; }
473 template <
typename Char>
474 FMTQUILL_CONSTEXPR
auto compare(
const Char* s1,
const Char* s2, std::size_t n)
476 if (!is_constant_evaluated() &&
sizeof(Char) == 1)
return memcmp(s1, s2, n);
477 for (; n != 0; ++s1, ++s2, --n) {
478 if (*s1 < *s2)
return -1;
479 if (*s1 > *s2)
return 1;
487 template <
typename Container>
488 auto invoke_back_inserter()
489 -> decltype(back_inserter(std::declval<Container&>()));
492 template <
typename It,
typename Enable = std::true_type>
495 template <
typename It>
497 It, bool_constant<
std::is_same<
498 decltype(adl::invoke_back_inserter<typename It::container_type>()),
499 It>
::value>> : std::true_type {};
502 template <
typename OutputIt>
503 inline FMTQUILL_CONSTEXPR20
auto get_container(OutputIt it) ->
504 typename OutputIt::container_type& {
505 struct accessor : OutputIt {
506 FMTQUILL_CONSTEXPR20 accessor(OutputIt base) : OutputIt(base) {}
507 using OutputIt::container;
509 return *accessor(it).container;
514 FMTQUILL_BEGIN_EXPORT
529 using value_type = Char;
530 using iterator =
const Char*;
536 : data_(s), size_(count) {}
541 #if FMTQUILL_GCC_VERSION 542 FMTQUILL_ALWAYS_INLINE
545 #if FMTQUILL_HAS_BUILTIN(__builtin_strlen) || FMTQUILL_GCC_VERSION || FMTQUILL_CLANG_VERSION 546 if (std::is_same<Char, char>::value && !detail::is_constant_evaluated()) {
547 size_ = __builtin_strlen(detail::narrow(s));
558 template <
typename S,
560 typename S::value_type, Char>::value)>
562 : data_(s.data()), size_(s.size()) {}
565 constexpr
auto data() const noexcept -> const Char* {
return data_; }
568 constexpr
auto size() const noexcept ->
size_t {
return size_; }
570 constexpr
auto begin()
const noexcept -> iterator {
return data_; }
571 constexpr
auto end()
const noexcept -> iterator {
return data_ + size_; }
573 constexpr
auto operator[](
size_t pos)
const noexcept ->
const Char& {
577 FMTQUILL_CONSTEXPR
void remove_prefix(
size_t n) noexcept {
584 return size_ >= sv.size_ && detail::compare(data_, sv.data_, sv.size_) == 0;
586 FMTQUILL_CONSTEXPR
auto starts_with(Char c)
const noexcept ->
bool {
587 return size_ >= 1 && *data_ == c;
589 FMTQUILL_CONSTEXPR
auto starts_with(
const Char* s)
const ->
bool {
595 detail::compare(data_, other.data_, min_of(size_, other.size_));
596 if (result != 0)
return result;
597 return size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
602 return lhs.compare(rhs) == 0;
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;
624 template <
typename T>
struct is_xchar : std::false_type {};
625 template <>
struct is_xchar<wchar_t> : std::true_type {};
626 template <>
struct is_xchar<char16_t> : std::true_type {};
627 template <>
struct is_xchar<char32_t> : std::true_type {};
629 template <>
struct is_xchar<char8_t> : std::true_type {};
634 template <>
struct is_char<char> : std::true_type {};
649 template <
typename OutputIt,
typename Char>
650 using basic_format_context =
651 conditional_t<std::is_same<OutputIt, appender>::value,
context,
655 template <
typename Char>
656 using buffered_context =
657 conditional_t<std::is_same<Char, char>::value, context,
668 template <
typename T,
typename Char =
char,
typename Enable =
void>
671 formatter() =
delete;
677 FMTQUILL_NORETURN FMTQUILL_API
void report_error(
const char* message);
679 enum class presentation_type : unsigned char {
702 enum class align { none, left, right, center, numeric };
703 enum class sign { none, minus, plus, space };
704 enum class arg_id_kind { none, index, name };
728 align_mask = 0x00038,
729 width_mask = 0x000C0,
730 precision_mask = 0x00300,
732 uppercase_mask = 0x01000,
733 alternate_mask = 0x02000,
734 localized_mask = 0x04000,
735 fill_size_mask = 0x38000,
741 fill_size_shift = 15,
746 unsigned data_ = 1 << fill_size_shift;
747 static_assert(
sizeof(basic_specs::data_) * CHAR_BIT >= 18,
"");
750 char fill_data_[max_fill_size] = {
' '};
752 FMTQUILL_CONSTEXPR
void set_fill_size(
size_t size) {
753 data_ = (data_ & ~fill_size_mask) |
754 (static_cast<unsigned>(size) << fill_size_shift);
758 constexpr
auto type()
const -> presentation_type {
759 return static_cast<presentation_type
>(data_ & type_mask);
761 FMTQUILL_CONSTEXPR
void set_type(presentation_type t) {
762 data_ = (data_ & ~type_mask) | static_cast<unsigned>(t);
765 constexpr
auto align()
const -> align {
766 return static_cast<fmtquill::align
>((data_ & align_mask) >> align_shift);
768 FMTQUILL_CONSTEXPR
void set_align(fmtquill::align a) {
769 data_ = (data_ & ~align_mask) | (static_cast<unsigned>(a) << align_shift);
772 constexpr
auto dynamic_width()
const -> arg_id_kind {
773 return static_cast<arg_id_kind
>((data_ & width_mask) >> width_shift);
775 FMTQUILL_CONSTEXPR
void set_dynamic_width(arg_id_kind w) {
776 data_ = (data_ & ~width_mask) | (static_cast<unsigned>(w) << width_shift);
779 FMTQUILL_CONSTEXPR
auto dynamic_precision()
const -> arg_id_kind {
780 return static_cast<arg_id_kind
>((data_ & precision_mask) >>
783 FMTQUILL_CONSTEXPR
void set_dynamic_precision(arg_id_kind p) {
784 data_ = (data_ & ~precision_mask) |
785 (static_cast<unsigned>(p) << precision_shift);
788 constexpr
bool dynamic()
const {
789 return (data_ & (width_mask | precision_mask)) != 0;
792 constexpr
auto sign()
const -> sign {
793 return static_cast<fmtquill::sign
>((data_ & sign_mask) >> sign_shift);
795 FMTQUILL_CONSTEXPR
void set_sign(fmtquill::sign s) {
796 data_ = (data_ & ~sign_mask) | (static_cast<unsigned>(s) << sign_shift);
799 constexpr
auto upper()
const ->
bool {
return (data_ & uppercase_mask) != 0; }
800 FMTQUILL_CONSTEXPR
void set_upper() { data_ |= uppercase_mask; }
802 constexpr
auto alt()
const ->
bool {
return (data_ & alternate_mask) != 0; }
803 FMTQUILL_CONSTEXPR
void set_alt() { data_ |= alternate_mask; }
804 FMTQUILL_CONSTEXPR
void clear_alt() { data_ &= ~alternate_mask; }
806 constexpr
auto localized()
const ->
bool {
807 return (data_ & localized_mask) != 0;
809 FMTQUILL_CONSTEXPR
void set_localized() { data_ |= localized_mask; }
811 constexpr
auto fill_size()
const ->
size_t {
812 return (data_ & fill_size_mask) >> fill_size_shift;
815 template <typename Char, FMTQUILL_ENABLE_IF(std::is_same<Char, char>::value)>
816 constexpr
auto fill()
const ->
const Char* {
819 template <typename Char, FMTQUILL_ENABLE_IF(!std::is_same<Char, char>::value)>
820 constexpr
auto fill()
const ->
const Char* {
824 template <
typename Char> constexpr
auto fill_unit()
const -> Char {
825 using uchar =
unsigned char;
826 return static_cast<Char
>(
static_cast<uchar
>(fill_data_[0]) |
827 (static_cast<uchar>(fill_data_[1]) << 8) |
828 (static_cast<uchar>(fill_data_[2]) << 16));
831 FMTQUILL_CONSTEXPR
void set_fill(
char c) {
836 template <
typename Char>
838 auto size = s.
size();
841 unsigned uchar =
static_cast<detail::unsigned_char<Char>
>(s[0]);
842 fill_data_[0] =
static_cast<char>(uchar);
843 fill_data_[1] =
static_cast<char>(uchar >> 8);
844 fill_data_[2] =
static_cast<char>(uchar >> 16);
847 FMTQUILL_ASSERT(size <= max_fill_size,
"invalid fill");
848 for (
size_t i = 0; i < size; ++i)
849 fill_data_[i & 3] = static_cast<char>(s[i]);
852 FMTQUILL_CONSTEXPR
void copy_fill_from(
const basic_specs& specs) {
853 set_fill_size(specs.fill_size());
854 for (
size_t i = 0; i < max_fill_size; ++i)
855 fill_data_[i] = specs.fill_data_[i];
876 enum { use_constexpr_cast = !FMTQUILL_GCC_VERSION || FMTQUILL_GCC_VERSION >= 1200 };
878 FMTQUILL_CONSTEXPR
void do_check_arg_id(
int arg_id);
881 using char_type = Char;
882 using iterator =
const Char*;
886 : fmt_(fmt), next_arg_id_(next_arg_id) {}
890 constexpr
auto begin() const noexcept -> iterator {
return fmt_.begin(); }
893 constexpr
auto end() const noexcept -> iterator {
return fmt_.end(); }
897 fmt_.remove_prefix(detail::to_unsigned(it - begin()));
903 if (next_arg_id_ < 0) {
904 report_error(
"cannot switch from manual to automatic argument indexing");
907 int id = next_arg_id_++;
915 if (next_arg_id_ > 0) {
916 report_error(
"cannot switch from automatic to manual argument indexing");
925 FMTQUILL_CONSTEXPR
void check_dynamic_spec(
int arg_id);
935 template <typename Char, FMTQUILL_ENABLE_IF(is_char<Char>::value)>
939 template <typename T, FMTQUILL_ENABLE_IF(is_std_string_like<T>::value)>
940 constexpr
auto to_string_view(
const T& s)
944 template <
typename Char>
950 template <
typename T,
typename Enable =
void>
953 template <
typename T>
955 T, void_t<decltype(
detail::to_string_view(std::declval<T>()))>>
959 template <
typename S,
960 typename V = decltype(detail::to_string_view(std::declval<S>()))>
974 last_integer_type = char_type,
979 last_numeric_type = long_double_type,
987 template <
typename T,
typename Char>
990 #define FMTQUILL_TYPE_CONSTANT(Type, constant) \ 991 template <typename Char> \ 992 struct type_constant<Type, Char> \ 993 : std::integral_constant<type, type::constant> {} 995 FMTQUILL_TYPE_CONSTANT(
int, int_type);
996 FMTQUILL_TYPE_CONSTANT(
unsigned, uint_type);
997 FMTQUILL_TYPE_CONSTANT(
long long, long_long_type);
998 FMTQUILL_TYPE_CONSTANT(
unsigned long long, ulong_long_type);
999 FMTQUILL_TYPE_CONSTANT(int128_opt, int128_type);
1000 FMTQUILL_TYPE_CONSTANT(uint128_opt, uint128_type);
1001 FMTQUILL_TYPE_CONSTANT(
bool, bool_type);
1002 FMTQUILL_TYPE_CONSTANT(Char, char_type);
1003 FMTQUILL_TYPE_CONSTANT(
float, float_type);
1004 FMTQUILL_TYPE_CONSTANT(
double, double_type);
1005 FMTQUILL_TYPE_CONSTANT(
long double, long_double_type);
1006 FMTQUILL_TYPE_CONSTANT(
const Char*, cstring_type);
1008 FMTQUILL_TYPE_CONSTANT(
const void*, pointer_type);
1010 constexpr
auto is_integral_type(type t) ->
bool {
1011 return t > type::none_type && t <= type::last_integer_type;
1013 constexpr
auto is_arithmetic_type(type t) ->
bool {
1014 return t > type::none_type && t <= type::last_numeric_type;
1017 constexpr
auto set(type rhs) ->
int {
return 1 <<
static_cast<int>(rhs); }
1018 constexpr
auto in(type t,
int set) ->
bool {
1019 return ((
set >> static_cast<int>(t)) & 1) != 0;
1025 set(type::int_type) |
set(type::long_long_type) |
set(type::int128_type),
1026 uint_set =
set(type::uint_type) |
set(type::ulong_long_type) |
1027 set(type::uint128_type),
1028 bool_set =
set(type::bool_type),
1029 char_set =
set(type::char_type),
1030 float_set =
set(type::float_type) |
set(type::double_type) |
1031 set(type::long_double_type),
1032 string_set =
set(type::string_type),
1033 cstring_set =
set(type::cstring_type),
1034 pointer_set =
set(type::pointer_type)
1039 template <
typename T,
typename Enable = std::true_type>
1041 template <
typename T>
1042 struct is_view<T, bool_constant<sizeof(T) != 0>> : std::is_base_of<view, T> {};
1048 template <
typename Char,
typename T>
1051 template <
typename Char,
typename T>
struct named_arg :
view {
1055 named_arg(
const Char* n,
const T& v) : name(n), value(v) {}
1059 template <
bool B = false> constexpr
auto count() ->
int {
return B ? 1 : 0; }
1060 template <
bool B1,
bool B2,
bool... Tail> constexpr
auto count() ->
int {
1061 return (B1 ? 1 : 0) + count<B2, Tail...>();
1064 template <
typename... Args> constexpr
auto count_named_args() ->
int {
1065 return count<is_named_arg<Args>::value...>();
1067 template <
typename... Args> constexpr
auto count_static_named_args() ->
int {
1068 return count<is_static_named_arg<Args>::value...>();
1077 template <
typename Char>
1079 int named_arg_index,
1081 for (
int i = 0; i < named_arg_index; ++i) {
1082 if (named_args[i].name == arg_name) report_error(
"duplicate named arg");
1086 template <typename Char, typename T, FMTQUILL_ENABLE_IF(!is_named_arg<T>::value)>
1090 template <typename Char, typename T, FMTQUILL_ENABLE_IF(is_named_arg<T>::value)>
1092 int& named_arg_index,
const T& arg) {
1093 check_for_duplicate<Char>(named_args, named_arg_index, arg.name);
1094 named_args[named_arg_index++] = {arg.name, arg_index++};
1097 template <
typename T,
typename Char,
1103 template <
typename T,
typename Char,
1106 int& arg_index,
int& named_arg_index) {
1107 check_for_duplicate<Char>(named_args, named_arg_index, T::name);
1108 named_args[named_arg_index++] = {T::name, arg_index++};
1113 enum { long_short =
sizeof(long) ==
sizeof(
int) && FMTQUILL_BUILTIN_TYPES };
1114 using long_type = conditional_t<long_short, int, long long>;
1115 using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
1117 template <
typename T>
1118 using format_as_result =
1119 remove_cvref_t<decltype(format_as(std::declval<const T&>()))>;
1120 template <
typename T>
1121 using format_as_member_result =
1122 remove_cvref_t<decltype(formatter<T>::format_as(std::declval<const T&>()))>;
1124 template <
typename T,
typename Enable = std::true_type>
1127 template <
typename T,
typename Enable = std::true_type>
1131 template <
typename T>
1133 T, bool_constant<
std::is_arithmetic<format_as_result<T>>
::value>>
1134 : std::true_type {};
1135 template <
typename T>
1137 T, bool_constant<std::is_arithmetic<format_as_member_result<T>>
::value>>
1138 : std::true_type {};
1140 template <
typename T,
typename U = remove_const_t<T>>
1141 using use_formatter =
1142 bool_constant<(std::is_class<T>::value || std::is_enum<T>::value ||
1143 std::is_union<T>::value || std::is_array<T>::value) &&
1147 template <
typename Char,
typename T,
typename U = remove_const_t<T>>
1148 auto has_formatter_impl(T* p, buffered_context<Char>* ctx =
nullptr)
1149 -> decltype(formatter<U, Char>().format(*p, *ctx), std::true_type());
1150 template <
typename Char>
auto has_formatter_impl(...) -> std::false_type;
1153 template <
typename T,
typename Char> constexpr
auto has_formatter() ->
bool {
1154 return decltype(has_formatter_impl<Char>(static_cast<T*>(
nullptr)))::
value;
1160 static auto map(
signed char) -> int;
1161 static auto map(
unsigned char) -> unsigned;
1162 static auto map(
short) -> int;
1163 static auto map(
unsigned short) -> unsigned;
1164 static auto map(
int) -> int;
1165 static auto map(
unsigned) -> unsigned;
1166 static auto map(
long) -> long_type;
1167 static auto map(
unsigned long) -> ulong_type;
1168 static auto map(
long long) ->
long long;
1169 static auto map(
unsigned long long) ->
unsigned long long;
1170 static auto map(int128_opt) -> int128_opt;
1171 static auto map(uint128_opt) -> uint128_opt;
1172 static auto map(
bool) -> bool;
1175 static auto map(
bitint<N>) -> conditional_t<N <= 64, long long, void>;
1178 -> conditional_t<N <= 64, unsigned long long, void>;
1180 template <typename T, FMTQUILL_ENABLE_IF(is_char<T>::value)>
1181 static auto map(T) -> conditional_t<
1182 std::is_same<T, char>::value || std::is_same<T, Char>::value, Char,
void>;
1184 static auto map(
float) -> float;
1185 static auto map(
double) -> double;
1186 static auto map(
long double) ->
long double;
1188 static auto map(Char*) ->
const Char*;
1189 static auto map(
const Char*) ->
const Char*;
1190 template <
typename T,
typename C =
char_t<T>,
1191 FMTQUILL_ENABLE_IF(!std::is_po
inter<T>::value)>
1192 static auto map(
const T&) -> conditional_t<std::is_same<C, Char>::value,
1195 static auto map(
void*) ->
const void*;
1196 static auto map(
const void*) ->
const void*;
1197 static auto map(
volatile void*) ->
const void*;
1198 static auto map(
const volatile void*) ->
const void*;
1199 static auto map(nullptr_t) ->
const void*;
1200 template <typename T, FMTQUILL_ENABLE_IF(std::is_pointer<T>::value ||
1201 std::is_member_pointer<T>::value)>
1202 static auto map(
const T&) -> void;
1204 template <typename T, FMTQUILL_ENABLE_IF(use_format_as<T>::value)>
1205 static auto map(
const T& x) -> decltype(map(format_as(x)));
1206 template <typename T, FMTQUILL_ENABLE_IF(use_format_as_member<T>::value)>
1207 static auto map(
const T& x) -> decltype(map(formatter<T>::format_as(x)));
1209 template <typename T, FMTQUILL_ENABLE_IF(use_formatter<T>::value)>
1210 static auto map(T&) -> conditional_t<has_formatter<T, Char>(), T&,
void>;
1212 template <typename T, FMTQUILL_ENABLE_IF(is_named_arg<T>::value)>
1213 static auto map(
const T&
named_arg) -> decltype(map(named_arg.value));
1217 template <
typename T,
typename Char>
1221 template <
typename T,
typename Char =
char>
1224 template <
typename T,
typename Context,
1227 using stored_type_constant = std::integral_constant<
1228 type, Context::builtin_types || TYPE == type::int_type ? TYPE
1229 : type::custom_type>;
1231 template <
typename Char>
1240 int num_args,
const type* types,
1241 int next_arg_id = 0)
1242 :
base(fmt, next_arg_id), num_args_(num_args), types_(types) {}
1244 constexpr
auto num_args()
const ->
int {
return num_args_; }
1245 constexpr
auto arg_type(
int id)
const -> type {
return types_[id]; }
1247 FMTQUILL_CONSTEXPR
auto next_arg_id() ->
int {
1248 int id = base::next_arg_id();
1249 if (
id >= num_args_) report_error(
"argument not found");
1253 FMTQUILL_CONSTEXPR
void check_arg_id(
int id) {
1254 base::check_arg_id(
id);
1255 if (
id >= num_args_) report_error(
"argument not found");
1257 using base::check_arg_id;
1259 FMTQUILL_CONSTEXPR
void check_dynamic_spec(
int arg_id) {
1260 ignore_unused(arg_id);
1261 if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
1262 report_error(
"width/precision is not integer");
1268 FMTQUILL_CONSTEXPR
arg_ref(
int idx = 0) : index(idx) {}
1284 template <typename Char, FMTQUILL_ENABLE_IF(std::is_integral<Char>::value)>
1285 constexpr
auto to_ascii(Char c) ->
char {
1286 return c <= 0xff ? static_cast<char>(c) :
'\0';
1290 template <
typename Char>
1291 FMTQUILL_CONSTEXPR
auto code_point_length(
const Char* begin) ->
int {
1292 if (const_check(
sizeof(Char) != 1))
return 1;
1293 auto c =
static_cast<unsigned char>(*begin);
1294 return static_cast<int>((0x3a55000000000000ull >> (2 * (c >> 3))) & 3) + 1;
1299 template <
typename Char>
1300 FMTQUILL_CONSTEXPR
auto parse_nonnegative_int(
const Char*& begin,
const Char* end,
1301 int error_value) noexcept ->
int {
1302 FMTQUILL_ASSERT(begin != end &&
'0' <= *begin && *begin <=
'9',
"");
1303 unsigned value = 0, prev = 0;
1307 value = value * 10 + unsigned(*p -
'0');
1309 }
while (p != end &&
'0' <= *p && *p <=
'9');
1310 auto num_digits = p - begin;
1312 int digits10 =
static_cast<int>(
sizeof(int) * CHAR_BIT * 3 / 10);
1313 if (num_digits <= digits10)
return static_cast<int>(value);
1315 unsigned max = INT_MAX;
1316 return num_digits == digits10 + 1 &&
1317 prev * 10ull + unsigned(p[-1] -
'0') <= max
1318 ?
static_cast<int>(value)
1322 FMTQUILL_CONSTEXPR
inline auto parse_align(
char c) -> align {
1324 case '<':
return align::left;
1325 case '>':
return align::right;
1326 case '^':
return align::center;
1331 template <
typename Char> constexpr
auto is_name_start(Char c) ->
bool {
1332 return (
'a' <= c && c <=
'z') || (
'A' <= c && c <=
'Z') || c ==
'_';
1335 template <
typename Char,
typename Handler>
1336 FMTQUILL_CONSTEXPR
auto parse_arg_id(
const Char* begin,
const Char* end,
1337 Handler&& handler) ->
const Char* {
1339 if (c >=
'0' && c <=
'9') {
1342 index = parse_nonnegative_int(begin, end, INT_MAX);
1345 if (begin == end || (*begin !=
'}' && *begin !=
':'))
1346 report_error(
"invalid format string");
1348 handler.on_index(index);
1351 if (FMTQUILL_OPTIMIZE_SIZE > 1 || !is_name_start(c)) {
1352 report_error(
"invalid format string");
1358 }
while (it != end && (is_name_start(*it) || (
'0' <= *it && *it <=
'9')));
1359 handler.on_name({begin, to_unsigned(it - begin)});
1368 FMTQUILL_CONSTEXPR
void on_index(
int id) {
1370 kind = arg_id_kind::index;
1372 ctx.check_dynamic_spec(
id);
1376 kind = arg_id_kind::name;
1387 template <
typename Char>
1388 FMTQUILL_CONSTEXPR
auto parse_dynamic_spec(
const Char* begin,
const Char* end,
1392 FMTQUILL_ASSERT(begin != end,
"");
1393 auto kind = arg_id_kind::none;
1394 if (
'0' <= *begin && *begin <=
'9') {
1395 int val = parse_nonnegative_int(begin, end, -1);
1396 if (val == -1) report_error(
"number is too big");
1399 if (*begin ==
'{') {
1403 if (c ==
'}' || c ==
':') {
1406 kind = arg_id_kind::index;
1407 ctx.check_dynamic_spec(
id);
1409 begin = parse_arg_id(begin, end,
1413 if (begin != end && *begin ==
'}')
return {++begin, kind};
1415 report_error(
"invalid format string");
1417 return {begin, kind};
1420 template <
typename Char>
1421 FMTQUILL_CONSTEXPR
auto parse_width(
const Char* begin,
const Char* end,
1424 auto result = parse_dynamic_spec(begin, end, specs.width, width_ref, ctx);
1425 specs.set_dynamic_width(result.kind);
1429 template <
typename Char>
1430 FMTQUILL_CONSTEXPR
auto parse_precision(
const Char* begin,
const Char* end,
1436 report_error(
"invalid precision");
1440 parse_dynamic_spec(begin, end, specs.precision, precision_ref, ctx);
1441 specs.set_dynamic_precision(result.kind);
1445 enum class state { start, align, sign, hash, zero, width, precision, locale };
1448 template <
typename Char>
1449 FMTQUILL_CONSTEXPR
auto parse_format_specs(
const Char* begin,
const Char* end,
1454 if (end - begin > 1) {
1455 auto next = to_ascii(begin[1]);
1456 c = parse_align(next) == align::none ? to_ascii(*begin) :
'\0';
1458 if (begin == end)
return begin;
1459 c = to_ascii(*begin);
1463 state current_state = state::start;
1464 FMTQUILL_CONSTEXPR
void operator()(state s,
bool valid =
true) {
1465 if (current_state >= s || !valid)
1466 report_error(
"invalid format specifier");
1471 using pres = presentation_type;
1472 constexpr
auto integral_set = sint_set | uint_set | bool_set | char_set;
1478 FMTQUILL_CONSTEXPR
auto operator()(pres pres_type,
int set) ->
const Char* {
1479 if (!in(arg_type,
set)) report_error(
"invalid format specifier");
1480 specs.set_type(pres_type);
1483 } parse_presentation_type{begin, specs, arg_type};
1490 enter_state(state::align);
1491 specs.set_align(parse_align(c));
1496 specs.set_sign(c ==
' ' ? sign::space : sign::plus);
1497 FMTQUILL_FALLTHROUGH;
1499 enter_state(state::sign, in(arg_type, sint_set | float_set));
1503 enter_state(state::hash, is_arithmetic_type(arg_type));
1508 enter_state(state::zero);
1509 if (!is_arithmetic_type(arg_type))
1510 report_error(
"format specifier requires numeric argument");
1511 if (specs.align() == align::none) {
1513 specs.set_align(align::numeric);
1514 specs.set_fill(
'0');
1519 case '1':
case '2':
case '3':
case '4':
case '5':
1520 case '6':
case '7':
case '8':
case '9':
case '{':
1522 enter_state(state::width);
1523 begin = parse_width(begin, end, specs, specs.width_ref, ctx);
1526 enter_state(state::precision,
1527 in(arg_type, float_set | string_set | cstring_set));
1528 begin = parse_precision(begin, end, specs, specs.precision_ref, ctx);
1531 enter_state(state::locale, is_arithmetic_type(arg_type));
1532 specs.set_localized();
1535 case 'd':
return parse_presentation_type(pres::dec, integral_set);
1536 case 'X': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1537 case 'x':
return parse_presentation_type(pres::hex, integral_set);
1538 case 'o':
return parse_presentation_type(pres::oct, integral_set);
1539 case 'B': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1540 case 'b':
return parse_presentation_type(pres::bin, integral_set);
1541 case 'E': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1542 case 'e':
return parse_presentation_type(pres::exp, float_set);
1543 case 'F': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1544 case 'f':
return parse_presentation_type(pres::fixed, float_set);
1545 case 'G': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1546 case 'g':
return parse_presentation_type(pres::general, float_set);
1547 case 'A': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1548 case 'a':
return parse_presentation_type(pres::hexfloat, float_set);
1550 if (arg_type == type::bool_type) report_error(
"invalid format specifier");
1551 return parse_presentation_type(pres::chr, integral_set);
1553 return parse_presentation_type(pres::string,
1554 bool_set | string_set | cstring_set);
1556 return parse_presentation_type(pres::pointer, pointer_set | cstring_set);
1558 return parse_presentation_type(pres::debug,
1559 char_set | string_set | cstring_set);
1560 case '}':
return begin;
1562 if (*begin ==
'}')
return begin;
1564 auto fill_end = begin + code_point_length(begin);
1565 if (end - fill_end <= 0) {
1566 report_error(
"invalid format specifier");
1569 if (*begin ==
'{') {
1570 report_error(
"invalid fill character '{'");
1573 auto alignment = parse_align(to_ascii(*fill_end));
1574 enter_state(state::align, alignment != align::none);
1577 specs.set_align(alignment);
1578 begin = fill_end + 1;
1581 if (begin == end)
return begin;
1582 c = to_ascii(*begin);
1586 template <
typename Char,
typename Handler>
1587 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
auto parse_replacement_field(
const Char* begin,
1593 handler.on_error(
"invalid format string");
1599 handler.on_replacement_field(handler.on_arg_id(), begin);
1601 case '{': handler.on_text(begin, begin + 1);
return begin + 1;
1602 case ':': arg_id = handler.on_arg_id();
break;
1608 FMTQUILL_CONSTEXPR
void on_index(
int id) { arg_id = handler.on_arg_id(
id); }
1610 arg_id = handler.on_arg_id(
id);
1612 } adapter = {handler, 0};
1613 begin = parse_arg_id(begin, end, adapter);
1614 arg_id = adapter.arg_id;
1615 Char c = begin != end ? *begin : Char();
1617 handler.on_replacement_field(arg_id, begin);
1621 handler.on_error(
"missing '}' in format string");
1627 begin = handler.on_format_specs(arg_id, begin + 1, end);
1628 if (begin == end || *begin !=
'}')
1629 return handler.on_error(
"unknown format specifier"), end;
1633 template <
typename Char,
typename Handler>
1635 Handler&& handler) {
1636 auto begin = fmt.
data(), end = begin + fmt.
size();
1641 handler.on_text(begin, p - 1);
1642 begin = p = parse_replacement_field(p - 1, end, handler);
1643 }
else if (c ==
'}') {
1644 if (p == end || *p !=
'}')
1645 return handler.on_error(
"unmatched '}' in format string");
1646 handler.on_text(begin, p);
1650 handler.on_text(begin, end);
1654 FMTQUILL_CONSTEXPR
inline auto check_char_specs(
const format_specs& specs) ->
bool {
1655 auto type = specs.type();
1656 if (type != presentation_type::none && type != presentation_type::chr &&
1657 type != presentation_type::debug) {
1660 if (specs.align() == align::numeric || specs.sign() != sign::none ||
1662 report_error(
"invalid format specifier for char");
1670 template <
typename T,
typename Char>
1671 FMTQUILL_VISIBILITY(
"hidden")
1673 using mapped_type = remove_cvref_t<mapped_t<T, Char>>;
1674 constexpr
bool formattable =
1675 std::is_constructible<formatter<mapped_type, Char>>
::value;
1676 if (!formattable)
return ctx.
begin();
1677 using formatted_type = conditional_t<formattable, mapped_type, int>;
1678 return formatter<formatted_type, Char>().parse(ctx);
1683 template <
typename Char,
int NUM_ARGS,
int NUM_NAMED_ARGS,
bool DYNAMIC_NAMES>
1686 type types_[max_of(1, NUM_ARGS)];
1691 parse_func parse_funcs_[max_of(1, NUM_ARGS)];
1694 template <
typename... T>
1699 context_(fmt, NUM_ARGS, types_),
1700 parse_funcs_{&invoke_parse<T, Char>...} {
1701 int arg_index = 0, named_arg_index = 0;
1702 FMTQUILL_APPLY_VARIADIC(
1703 init_static_named_arg<T>(named_args_, arg_index, named_arg_index));
1704 ignore_unused(arg_index, named_arg_index);
1707 FMTQUILL_CONSTEXPR
void on_text(
const Char*,
const Char*) {}
1709 FMTQUILL_CONSTEXPR
auto on_arg_id() ->
int {
return context_.next_arg_id(); }
1710 FMTQUILL_CONSTEXPR
auto on_arg_id(
int id) ->
int {
1711 context_.check_arg_id(
id);
1715 for (
int i = 0; i < NUM_NAMED_ARGS; ++i) {
1716 if (named_args_[i].name ==
id)
return named_args_[i].id;
1718 if (!DYNAMIC_NAMES) on_error(
"argument not found");
1722 FMTQUILL_CONSTEXPR
void on_replacement_field(
int id,
const Char* begin) {
1723 on_format_specs(
id, begin, begin);
1726 FMTQUILL_CONSTEXPR
auto on_format_specs(
int id,
const Char* begin,
const Char* end)
1729 if (
id >= 0 &&
id < NUM_ARGS)
return parse_funcs_[id](context_);
1734 for (
int bracket_count = 0;
1735 begin != end && (bracket_count > 0 || *begin !=
'}'); ++begin) {
1738 else if (*begin ==
'}')
1744 FMTQUILL_NORETURN FMTQUILL_CONSTEXPR
void on_error(
const char* message) {
1745 report_error(message);
1757 using grow_fun = void (*)(
buffer& buf,
size_t capacity);
1762 FMTQUILL_MSC_WARNING(suppress : 26495)
1763 FMTQUILL_CONSTEXPR
buffer(grow_fun grow,
size_t sz) noexcept
1764 : size_(sz), capacity_(sz), grow_(grow) {}
1766 constexpr
buffer(grow_fun grow, T* p =
nullptr,
size_t sz = 0,
1767 size_t cap = 0) noexcept
1768 : ptr_(p), size_(sz), capacity_(cap), grow_(grow) {}
1770 FMTQUILL_CONSTEXPR20 ~
buffer() =
default;
1774 FMTQUILL_CONSTEXPR
void set(T* buf_data,
size_t buf_capacity) noexcept {
1776 capacity_ = buf_capacity;
1780 using value_type = T;
1781 using const_reference =
const T&;
1784 void operator=(
const buffer&) =
delete;
1786 auto begin() noexcept -> T* {
return ptr_; }
1787 auto end() noexcept -> T* {
return ptr_ + size_; }
1789 auto begin()
const noexcept ->
const T* {
return ptr_; }
1790 auto end()
const noexcept ->
const T* {
return ptr_ + size_; }
1793 constexpr
auto size() const noexcept ->
size_t {
return size_; }
1796 constexpr
auto capacity() const noexcept ->
size_t {
return capacity_; }
1799 FMTQUILL_CONSTEXPR
auto data() noexcept -> T* {
return ptr_; }
1800 FMTQUILL_CONSTEXPR
auto data()
const noexcept ->
const T* {
return ptr_; }
1803 FMTQUILL_CONSTEXPR
void clear() { size_ = 0; }
1807 FMTQUILL_CONSTEXPR
void try_resize(
size_t count) {
1809 size_ = min_of(count, capacity_);
1816 FMTQUILL_CONSTEXPR
void try_reserve(
size_t new_capacity) {
1817 if (new_capacity > capacity_) grow_(*
this, new_capacity);
1820 FMTQUILL_CONSTEXPR
void push_back(
const T& value) {
1821 try_reserve(size_ + 1);
1822 ptr_[size_++] = value;
1826 template <
typename U>
1829 #if !FMTQUILL_MSC_VERSION || FMTQUILL_MSC_VERSION >= 1940 1830 FMTQUILL_CONSTEXPR20
1834 while (begin != end) {
1835 auto count = to_unsigned(end - begin);
1836 try_reserve(size_ + count);
1837 auto free_cap = capacity_ - size_;
1838 if (free_cap < count) count = free_cap;
1839 if constexpr (std::is_same<T, U>::value) {
1840 memcpy(ptr_ + size_, begin, count *
sizeof(T));
1842 T* out = ptr_ + size_;
1843 for (
size_t i = 0; i < count; ++i) out[i] = begin[i];
1850 template <
typename Idx> FMTQUILL_CONSTEXPR
auto operator[](Idx index) -> T& {
1853 template <
typename Idx>
1854 FMTQUILL_CONSTEXPR
auto operator[](Idx index)
const ->
const T& {
1861 constexpr
auto count()
const ->
size_t {
return 0; }
1862 constexpr
auto limit(
size_t size)
const ->
size_t {
return size; }
1872 constexpr
auto count()
const ->
size_t {
return count_; }
1873 FMTQUILL_CONSTEXPR
auto limit(
size_t size) ->
size_t {
1874 size_t n = limit_ > count_ ? limit_ - count_ : 0;
1876 return min_of(size, n);
1881 template <
typename OutputIt,
typename T,
typename Traits = buffer_traits>
1885 enum { buffer_size = 256 };
1886 T data_[buffer_size];
1888 static FMTQUILL_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
1889 if (buf.
size() == buffer_size) static_cast<iterator_buffer&>(buf).flush();
1893 auto size = this->size();
1895 const T* begin = data_;
1896 const T* end = begin + this->limit(size);
1897 while (begin != end) *out_++ = *begin++;
1902 : Traits(n),
buffer<T>(grow, data_, 0, buffer_size), out_(out) {}
1909 FMTQUILL_TRY { flush(); }
1910 FMTQUILL_CATCH(...) {}
1913 auto out() -> OutputIt {
1917 auto count()
const ->
size_t {
return Traits::count() + this->size(); }
1920 template <
typename T>
1925 enum { buffer_size = 256 };
1926 T data_[buffer_size];
1928 static FMTQUILL_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
1930 static_cast<iterator_buffer&>(buf).flush();
1934 size_t n = this->limit(this->size());
1935 if (this->data() == out_) {
1937 this->
set(data_, buffer_size);
1949 if (this->data() != out_) {
1950 this->
set(data_, buffer_size);
1960 auto count()
const ->
size_t {
1961 return fixed_buffer_traits::count() + this->size();
1970 auto out() -> T* {
return &*this->end(); }
1973 template <
typename Container>
1976 using value_type =
typename Container::value_type;
1980 self.container.resize(capacity);
1981 self.set(&
self.container[0], capacity);
1985 Container& container;
1992 template <
typename OutputIt>
1997 typename OutputIt::container_type::value_type>>
2005 :
base(get_container(out)) {}
2007 auto out() -> OutputIt {
return OutputIt(this->container); }
2013 enum { buffer_size = 256 };
2014 T data_[buffer_size];
2017 static FMTQUILL_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
2018 if (buf.
size() != buffer_size)
return;
2026 constexpr
auto count()
const noexcept ->
size_t {
2027 return count_ + this->size();
2031 template <
typename T>
2034 template <
typename OutputIt,
typename InputIt,
typename =
void>
2036 template <
typename OutputIt,
typename InputIt>
2039 void_t<decltype(get_container(std::declval<OutputIt>())
2040 .append(std::declval<InputIt>(),
2041 std::declval<InputIt>()))>> : std::true_type {};
2044 template <
typename T,
typename InputIt,
typename OutputIt,
2047 OutputIt, InputIt>::value)>
2048 FMTQUILL_CONSTEXPR20
auto copy(InputIt begin, InputIt end, OutputIt out)
2050 get_container(out).append(begin, end);
2054 template <
typename T,
typename InputIt,
typename OutputIt,
2057 OutputIt, InputIt>::value)>
2058 FMTQUILL_CONSTEXPR20
auto copy(InputIt begin, InputIt end, OutputIt out)
2060 auto& c = get_container(out);
2061 c.insert(c.end(), begin, end);
2065 template <
typename T,
typename InputIt,
typename OutputIt,
2067 FMTQUILL_CONSTEXPR
auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
2068 #if defined(__GNUC__) && !defined(__clang__) 2069 #pragma GCC diagnostic push 2070 #pragma GCC diagnostic ignored "-Wstringop-overflow" 2073 while (begin != end) *out++ =
static_cast<T
>(*begin++);
2075 #if defined(__GNUC__) && !defined(__clang__) 2076 #pragma GCC diagnostic pop 2082 template <
typename T,
typename V,
typename OutputIt>
2084 return copy<T>(s.begin(), s.end(), out);
2087 template <
typename It,
typename Enable = std::true_type>
2089 template <
typename It>
2093 std::is_base_of<buffer<typename It::container_type::value_type>,
2094 typename It::container_type>
::value>>
2095 : std::true_type {};
2098 template <
typename T,
typename OutputIt,
2103 template <
typename T,
typename OutputIt,
2105 auto get_buffer(OutputIt out) ->
buffer<T>& {
2106 return get_container(out);
2109 template <
typename Buf,
typename OutputIt>
2110 auto get_iterator(Buf& buf, OutputIt) -> decltype(buf.out()) {
2113 template <
typename T,
typename OutputIt>
2114 auto get_iterator(
buffer<T>&, OutputIt out) -> OutputIt {
2128 using char_type =
typename Context::char_type;
2140 #if !FMTQUILL_BUILTIN_TYPES 2141 # define FMTQUILL_BUILTIN , monostate 2143 # define FMTQUILL_BUILTIN 2147 template <
typename Context>
class value {
2149 using char_type =
typename Context::char_type;
2154 unsigned uint_value;
2155 long long long_long_value;
2156 unsigned long long ulong_long_value;
2157 int128_opt int128_value;
2158 uint128_opt uint128_value;
2160 char_type char_value;
2162 double double_value;
2163 long double long_double_value;
2164 const void* pointer;
2170 constexpr FMTQUILL_INLINE value() : no_value() {}
2171 constexpr FMTQUILL_INLINE value(
signed char x) : int_value(x) {}
2172 constexpr FMTQUILL_INLINE value(
unsigned char x FMTQUILL_BUILTIN) : uint_value(x) {}
2173 constexpr FMTQUILL_INLINE value(
signed short x) : int_value(x) {}
2174 constexpr FMTQUILL_INLINE value(
unsigned short x FMTQUILL_BUILTIN) : uint_value(x) {}
2175 constexpr FMTQUILL_INLINE value(
int x) : int_value(x) {}
2176 constexpr FMTQUILL_INLINE value(
unsigned x FMTQUILL_BUILTIN) : uint_value(x) {}
2177 FMTQUILL_CONSTEXPR FMTQUILL_INLINE value(
long x FMTQUILL_BUILTIN) : value(long_type(x)) {}
2178 FMTQUILL_CONSTEXPR FMTQUILL_INLINE value(
unsigned long x FMTQUILL_BUILTIN)
2179 : value(ulong_type(x)) {}
2180 constexpr FMTQUILL_INLINE value(
long long x FMTQUILL_BUILTIN) : long_long_value(x) {}
2181 constexpr FMTQUILL_INLINE value(
unsigned long long x FMTQUILL_BUILTIN)
2182 : ulong_long_value(x) {}
2183 FMTQUILL_INLINE value(int128_opt x FMTQUILL_BUILTIN) : int128_value(x) {}
2184 FMTQUILL_INLINE value(uint128_opt x FMTQUILL_BUILTIN) : uint128_value(x) {}
2185 constexpr FMTQUILL_INLINE value(
bool x FMTQUILL_BUILTIN) : bool_value(x) {}
2188 constexpr FMTQUILL_INLINE value(
bitint<N> x FMTQUILL_BUILTIN) : long_long_value(x) {
2189 static_assert(N <= 64,
"unsupported _BitInt");
2192 constexpr FMTQUILL_INLINE value(
ubitint<N> x FMTQUILL_BUILTIN) : ulong_long_value(x) {
2193 static_assert(N <= 64,
"unsupported _BitInt");
2196 template <typename T, FMTQUILL_ENABLE_IF(is_char<T>::value)>
2197 constexpr FMTQUILL_INLINE value(T x FMTQUILL_BUILTIN) : char_value(x) {
2199 std::is_same<T, char>::value || std::is_same<T, char_type>::value,
2200 "mixing character types is disallowed");
2203 constexpr FMTQUILL_INLINE value(
float x FMTQUILL_BUILTIN) : float_value(x) {}
2204 constexpr FMTQUILL_INLINE value(
double x FMTQUILL_BUILTIN) : double_value(x) {}
2205 FMTQUILL_INLINE value(
long double x FMTQUILL_BUILTIN) : long_double_value(x) {}
2207 FMTQUILL_CONSTEXPR FMTQUILL_INLINE value(char_type* x FMTQUILL_BUILTIN) {
2209 if (is_constant_evaluated())
string.size = 0;
2211 FMTQUILL_CONSTEXPR FMTQUILL_INLINE value(
const char_type* x FMTQUILL_BUILTIN) {
2213 if (is_constant_evaluated())
string.size = 0;
2215 template <
typename T,
typename C =
char_t<T>,
2216 FMTQUILL_ENABLE_IF(!std::is_po
inter<T>::value)>
2217 FMTQUILL_CONSTEXPR value(
const T& x FMTQUILL_BUILTIN) {
2218 static_assert(std::is_same<C, char_type>::value,
2219 "mixing character types is disallowed");
2220 auto sv = to_string_view(x);
2221 string.data = sv.data();
2222 string.size = sv.size();
2224 FMTQUILL_INLINE value(
void* x FMTQUILL_BUILTIN) : pointer(x) {}
2225 FMTQUILL_INLINE value(
const void* x FMTQUILL_BUILTIN) : pointer(x) {}
2226 FMTQUILL_INLINE value(
volatile void* x FMTQUILL_BUILTIN)
2227 : pointer(const_cast<const void*>(x)) {}
2228 FMTQUILL_INLINE value(
const volatile void* x FMTQUILL_BUILTIN)
2229 : pointer(const_cast<const void*>(x)) {}
2230 FMTQUILL_INLINE value(nullptr_t) : pointer(
nullptr) {}
2232 template <typename T, FMTQUILL_ENABLE_IF(std::is_pointer<T>::value ||
2233 std::is_member_pointer<T>::value)>
2238 static_assert(
sizeof(T) == 0,
2239 "formatting of non-void pointers is disallowed");
2242 template <typename T, FMTQUILL_ENABLE_IF(use_format_as<T>::value)>
2243 value(
const T& x) : value(format_as(x)) {}
2244 template <typename T, FMTQUILL_ENABLE_IF(use_format_as_member<T>::value)>
2245 value(
const T& x) : value(formatter<T>::format_as(x)) {}
2247 template <typename T, FMTQUILL_ENABLE_IF(is_named_arg<T>::value)>
2248 value(
const T&
named_arg) : value(named_arg.value) {}
2250 template <
typename T,
2251 FMTQUILL_ENABLE_IF(use_formatter<T>::value || !FMTQUILL_BUILTIN_TYPES)>
2252 FMTQUILL_CONSTEXPR20 FMTQUILL_INLINE value(T& x) : value(x,
custom_tag()) {}
2255 : named_args{args, size} {}
2258 template <
typename T, FMTQUILL_ENABLE_IF(has_formatter<T,
char_type>())>
2260 using value_type = remove_const_t<T>;
2262 if (!is_constant_evaluated()) {
2264 const_cast<char*
>(&
reinterpret_cast<const volatile char&
>(x));
2266 custom.value =
nullptr;
2267 #if defined(__cpp_if_constexpr) 2268 if constexpr (std::is_same<decltype(&x), remove_reference_t<T>*>::value)
2269 custom.value =
const_cast<value_type*
>(&x);
2272 custom.format = format_custom<value_type, formatter<value_type, char_type>>;
2275 template <
typename T, FMTQUILL_ENABLE_IF(!has_formatter<T,
char_type>())>
2276 FMTQUILL_CONSTEXPR value(
const T&,
custom_tag) {
2283 template <
typename T,
typename Formatter>
2286 auto f = Formatter();
2288 using qualified_type =
2289 conditional_t<has_formatter<const T, char_type>(),
const T, T>;
2292 ctx.advance_to(cf.format(*static_cast<qualified_type*>(arg), ctx));
2296 enum { packed_arg_bits = 4 };
2298 enum { max_packed_args = 62 / packed_arg_bits };
2299 enum :
unsigned long long { is_unpacked_bit = 1ULL << 63 };
2300 enum :
unsigned long long { has_named_args_bit = 1ULL << 62 };
2302 template <
typename It,
typename T,
typename Enable =
void>
2307 template <
typename It,
typename T>
2310 enable_if_t<std::is_assignable<decltype(*std::declval<decay_t<It>&>()++),
2311 T>
::value>> : std::true_type {};
2313 #ifndef FMTQUILL_USE_LOCALE 2314 # define FMTQUILL_USE_LOCALE (FMTQUILL_OPTIMIZE_SIZE <= 1) 2319 #if FMTQUILL_USE_LOCALE 2321 const void* locale_;
2325 template <
typename Locale> locale_ref(
const Locale& loc);
2327 inline explicit operator bool()
const noexcept {
return locale_ !=
nullptr; }
2328 #endif // FMTQUILL_USE_LOCALE 2331 template <
typename Locale>
auto get()
const -> Locale;
2334 template <
typename> constexpr
auto encode_types() ->
unsigned long long {
2338 template <
typename Context,
typename Arg,
typename... Args>
2339 constexpr
auto encode_types() ->
unsigned long long {
2340 return static_cast<unsigned>(stored_type_constant<Arg, Context>::value) |
2341 (encode_types<Context, Args...>() << packed_arg_bits);
2344 template <
typename Context,
typename... T,
size_t NUM_ARGS =
sizeof...(T)>
2345 constexpr
auto make_descriptor() ->
unsigned long long {
2346 return NUM_ARGS <= max_packed_args ? encode_types<Context, T...>()
2347 : is_unpacked_bit | NUM_ARGS;
2350 template <
typename Context,
int NUM_ARGS>
2351 using arg_t = conditional_t<NUM_ARGS <= max_packed_args, value<Context>,
2354 template <
typename Context,
int NUM_ARGS,
int NUM_NAMED_ARGS,
2355 unsigned long long DESC>
2358 arg_t<Context, NUM_ARGS> args[1 + NUM_ARGS];
2361 template <
typename... T>
2362 FMTQUILL_CONSTEXPR FMTQUILL_ALWAYS_INLINE
named_arg_store(T&... values)
2363 : args{{named_args, NUM_NAMED_ARGS}, values...} {
2364 int arg_index = 0, named_arg_index = 0;
2365 FMTQUILL_APPLY_VARIADIC(
2366 init_named_arg(named_args, arg_index, named_arg_index, values));
2369 named_arg_store(named_arg_store&& rhs) {
2370 args[0] = {named_args, NUM_NAMED_ARGS};
2371 for (
size_t i = 1; i <
sizeof(args) /
sizeof(*args); ++i)
2372 args[i] = rhs.args[i];
2373 for (
size_t i = 0; i < NUM_NAMED_ARGS; ++i)
2374 named_args[i] = rhs.named_args[i];
2377 named_arg_store(
const named_arg_store& rhs) =
delete;
2378 named_arg_store& operator=(
const named_arg_store& rhs) =
delete;
2379 named_arg_store& operator=(named_arg_store&& rhs) =
delete;
2380 operator const arg_t<Context, NUM_ARGS>*()
const {
return args + 1; }
2386 template <
typename Context,
int NUM_ARGS,
int NUM_NAMED_ARGS,
2387 unsigned long long DESC>
2391 conditional_t<NUM_NAMED_ARGS == 0,
2392 arg_t<Context, NUM_ARGS>[max_of(1, NUM_ARGS)],
2403 using nonlocking = void;
2407 auto end = parse_format_specs(ctx.
begin(), ctx.
end(), specs_, ctx, TYPE);
2408 if (const_check(TYPE == type::char_type)) check_char_specs(specs_);
2412 template <type U = TYPE,
2413 FMTQUILL_ENABLE_IF(U == type::string_type || U == type::cstring_type ||
2414 U == type::char_type)>
2415 FMTQUILL_CONSTEXPR
void set_debug_format(
bool set =
true) {
2416 specs_.set_type(
set ? presentation_type::debug : presentation_type::none);
2419 FMTQUILL_PRAGMA_CLANG(diagnostic ignored
"-Wundefined-inline")
2420 template <
typename FormatContext>
2421 FMTQUILL_CONSTEXPR
auto format(
const T& val, FormatContext& ctx)
const 2422 -> decltype(ctx.out());
2425 template <
typename T,
typename Enable =
void>
2427 : bool_constant<mapped_type_constant<T>::value == type::custom_type> {};
2428 template <
typename T>
2429 struct locking<T, void_t<typename formatter<remove_cvref_t<T>>::nonlocking>>
2430 : std::false_type {};
2432 template <
typename T =
int> FMTQUILL_CONSTEXPR
inline auto is_locking() ->
bool {
2435 template <
typename T1,
typename T2,
typename... Tail>
2436 FMTQUILL_CONSTEXPR
inline auto is_locking() ->
bool {
2445 #else // format_args is passed by reference since it is defined later. 2452 template <
typename Char>
2456 if (detail::is_constant_evaluated() && use_constexpr_cast) {
2458 if (arg_id >= ctx->num_args()) report_error(
"argument not found");
2462 template <
typename Char>
2465 if (detail::is_constant_evaluated() && use_constexpr_cast)
2469 FMTQUILL_BEGIN_EXPORT
2482 FMTQUILL_CONSTEXPR20
auto operator=(T c) -> basic_appender& {
2483 container->push_back(c);
2486 FMTQUILL_CONSTEXPR20
auto operator*() -> basic_appender& {
return *
this; }
2487 FMTQUILL_CONSTEXPR20
auto operator++() -> basic_appender& {
return *
this; }
2488 FMTQUILL_CONSTEXPR20
auto operator++(
int) -> basic_appender {
return *
this; }
2500 using char_type =
typename Context::char_type;
2511 custom_.format(custom_.value, parse_ctx, ctx);
2517 : value_(args, size) {}
2518 template <
typename T>
2519 basic_format_arg(T&& val)
2520 : value_(val), type_(detail::stored_type_constant<T, Context>::value) {}
2522 constexpr
explicit operator bool()
const noexcept {
2523 return type_ != detail::type::none_type;
2525 auto type()
const -> detail::type {
return type_; }
2532 template <
typename Visitor>
2533 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
auto visit(Visitor&& vis)
const -> decltype(vis(0)) {
2536 case detail::type::none_type:
break;
2537 case detail::type::int_type:
return vis(value_.int_value);
2538 case detail::type::uint_type:
return vis(value_.uint_value);
2539 case detail::type::long_long_type:
return vis(value_.long_long_value);
2540 case detail::type::ulong_long_type:
return vis(value_.ulong_long_value);
2541 case detail::type::int128_type:
return vis(map(value_.int128_value));
2542 case detail::type::uint128_type:
return vis(map(value_.uint128_value));
2543 case detail::type::bool_type:
return vis(value_.bool_value);
2544 case detail::type::char_type:
return vis(value_.char_value);
2545 case detail::type::float_type:
return vis(value_.float_value);
2546 case detail::type::double_type:
return vis(value_.double_value);
2547 case detail::type::long_double_type:
return vis(value_.long_double_value);
2548 case detail::type::cstring_type:
return vis(value_.string.data);
2549 case detail::type::string_type:
return vis(value_.string.str());
2550 case detail::type::pointer_type:
return vis(value_.pointer);
2551 case detail::type::custom_type:
return vis(handle(value_.custom));
2556 auto format_custom(
const char_type* parse_begin,
2559 if (type_ != detail::type::custom_type)
return false;
2561 value_.custom.format(value_.custom.value, parse_ctx, ctx);
2580 unsigned long long desc_;
2591 constexpr
auto is_packed()
const ->
bool {
2592 return (desc_ & detail::is_unpacked_bit) == 0;
2594 constexpr
auto has_named_args()
const ->
bool {
2595 return (desc_ & detail::has_named_args_bit) != 0;
2598 FMTQUILL_CONSTEXPR
auto type(
int index)
const -> detail::type {
2599 int shift = index * detail::packed_arg_bits;
2600 unsigned mask = (1 << detail::packed_arg_bits) - 1;
2601 return static_cast<detail::type
>((desc_ >> shift) & mask);
2604 template <
int NUM_ARGS,
int NUM_NAMED_ARGS,
unsigned long long DESC>
2614 template <
int NUM_ARGS,
int NUM_NAMED_ARGS,
unsigned long long DESC,
2615 FMTQUILL_ENABLE_IF(NUM_ARGS <= detail::max_packed_args)>
2618 : desc_(DESC | (NUM_NAMED_ARGS != 0 ? +
detail::has_named_args_bit : 0)),
2621 template <
int NUM_ARGS,
int NUM_NAMED_ARGS,
unsigned long long DESC,
2622 FMTQUILL_ENABLE_IF(NUM_ARGS > detail::max_packed_args)>
2624 : desc_(DESC | (NUM_NAMED_ARGS != 0 ? +detail::has_named_args_bit : 0)),
2629 bool has_named =
false)
2630 : desc_(
detail::is_unpacked_bit |
detail::to_unsigned(count) |
2631 (has_named ? +
detail::has_named_args_bit : 0)),
2638 if (
id < max_size()) arg = args_[id];
2641 if (static_cast<unsigned>(
id) >= detail::max_packed_args)
return arg;
2642 arg.type_ = type(
id);
2643 if (arg.type_ != detail::type::none_type) arg.value_ = values_[id];
2647 template <
typename Char>
2649 int id = get_id(name);
2653 template <
typename Char>
2655 if (!has_named_args())
return -1;
2656 const auto& named_args =
2657 (is_packed() ? values_[-1] : args_[-1].value_).named_args;
2658 for (
size_t i = 0; i < named_args.size; ++i) {
2659 if (named_args.data[i].name == name)
return named_args.data[i].id;
2664 auto max_size()
const ->
int {
2665 unsigned long long max_packed = detail::max_packed_args;
2666 return static_cast<int>(is_packed() ? max_packed
2667 : desc_ & ~
detail::is_unpacked_bit);
2680 using char_type = char;
2685 template <
typename T>
using formatter_type FMTQUILL_DEPRECATED =
formatter<T>;
2686 enum { builtin_types = FMTQUILL_BUILTIN_TYPES };
2692 : out_(out), args_(args), loc_(loc) {}
2693 context(context&&) =
default;
2694 context(
const context&) =
delete;
2695 void operator=(
const context&) =
delete;
2697 FMTQUILL_CONSTEXPR
auto arg(
int id)
const ->
format_arg {
return args_.
get(
id); }
2699 return args_.
get(name);
2701 FMTQUILL_CONSTEXPR
auto arg_id(
string_view name)
const ->
int {
2702 return args_.get_id(name);
2704 auto args()
const ->
const format_args& {
return args_; }
2707 FMTQUILL_CONSTEXPR
auto out()
const ->
iterator {
return out_; }
2710 FMTQUILL_CONSTEXPR
void advance_to(
iterator) {}
2733 static constexpr
int num_static_named_args =
2734 detail::count_static_named_args<T...>();
2737 char,
static_cast<int>(
sizeof...(T)), num_static_named_args,
2738 num_static_named_args != detail::count_named_args<T...>()>;
2748 FMTQUILL_CONSTEVAL FMTQUILL_ALWAYS_INLINE
fstring(
const char (&s)[N]) : str(s, N - 1) {
2750 static_assert(count<(
is_view<remove_cvref_t<T>>::
value &&
2751 std::is_reference<T>::value)...>() == 0,
2752 "passing views as lvalues is disallowed");
2753 if (FMTQUILL_USE_CONSTEVAL) parse_format_string<char>(s,
checker(s,
arg_pack()));
2754 #ifdef FMTQUILL_ENFORCE_COMPILE_STRING 2756 FMTQUILL_USE_CONSTEVAL &&
sizeof(s) != 0,
2757 "FMTQUILL_ENFORCE_COMPILE_STRING requires format strings to use FMTQUILL_STRING");
2760 template <
typename S,
2761 FMTQUILL_ENABLE_IF(std::is_convertible<const S&, string_view>::value)>
2762 FMTQUILL_CONSTEVAL FMTQUILL_ALWAYS_INLINE fstring(
const S& s) : str(s) {
2764 if (FMTQUILL_USE_CONSTEVAL)
2766 #ifdef FMTQUILL_ENFORCE_COMPILE_STRING 2768 FMTQUILL_USE_CONSTEVAL &&
sizeof(s) != 0,
2769 "FMTQUILL_ENFORCE_COMPILE_STRING requires format strings to use FMTQUILL_STRING");
2772 template <
typename S,
2773 FMTQUILL_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
2774 std::is_same<typename S::char_type, char>::value)>
2775 FMTQUILL_ALWAYS_INLINE fstring(
const S&) : str(S()) {
2777 FMTQUILL_CONSTEXPR
int unused =
2779 detail::ignore_unused(unused);
2784 FMTQUILL_ALWAYS_INLINE
operator const string_view&()
const {
return str; }
2788 template <
typename... T>
using format_string =
typename fstring<T...>
::t;
2790 template <
typename T,
typename Char =
char>
2791 using is_formattable = bool_constant<!std::is_same<
2792 detail::mapped_t<conditional_t<std::is_void<T>::value,
int*, T>, Char>,
2794 #ifdef __cpp_concepts 2795 template <
typename T,
typename Char =
char>
2796 concept formattable = is_formattable<remove_reference_t<T>, Char>::value;
2799 template <
typename T,
typename Char>
2800 using has_formatter FMTQUILL_DEPRECATED = std::is_constructible<formatter<T, Char>>;
2803 template <
typename T,
typename Char>
2804 struct formatter<T, Char,
2806 detail::type::custom_type>>
2817 template <
typename Context = context,
typename... T,
2818 int NUM_ARGS =
sizeof...(T),
2819 int NUM_NAMED_ARGS = detail::count_named_args<T...>(),
2820 unsigned long long DESC = detail::make_descriptor<Context, T...>()>
2821 constexpr FMTQUILL_ALWAYS_INLINE
auto make_format_args(T&... args)
2824 FMTQUILL_PRAGMA_GCC(diagnostic ignored
"-Wconversion")
2828 template <
typename... T>
2831 detail::count_named_args<T...>(),
2832 detail::make_descriptor<context, T...>()>;
2842 template <
typename Char,
typename T>
2848 template <
typename OutputIt,
2852 -> remove_cvref_t<OutputIt> {
2853 auto&& buf = detail::get_buffer<char>(out);
2854 detail::vformat_to(buf, fmt, args, {});
2855 return detail::get_iterator(buf, out);
2868 template <
typename OutputIt,
typename... T,
2871 FMTQUILL_INLINE
auto format_to(OutputIt&& out, format_string<T...> fmt, T&&... args)
2872 -> remove_cvref_t<OutputIt> {
2873 return vformat_to(out, fmt.str,
vargs<T...>{{args...}});
2883 template <
typename OutputIt,
typename... T,
2889 detail::vformat_to(buf, fmt, args, {});
2890 return {buf.out(), buf.count()};
2899 template <
typename OutputIt,
typename... T,
2901 FMTQUILL_INLINE
auto format_to_n(OutputIt out,
size_t n, format_string<T...> fmt,
2903 return vformat_to_n(out, n, fmt.str,
vargs<T...>{{args...}});
2912 FMTQUILL_CONSTEXPR
operator char*()
const {
2914 if (truncated) report_error(
"output is truncated");
2922 auto result = vformat_to_n(out, N, fmt, args);
2923 return {result.out, result.size > N};
2926 template <
size_t N,
typename... T>
2927 FMTQUILL_INLINE
auto format_to(
char (&out)[N], format_string<T...> fmt, T&&... args)
2929 auto result = vformat_to_n(out, N, fmt.str,
vargs<T...>{{args...}});
2930 return {result.out, result.size > N};
2934 template <
typename... T>
2935 FMTQUILL_NODISCARD FMTQUILL_INLINE
auto formatted_size(format_string<T...> fmt,
2936 T&&... args) ->
size_t {
2938 detail::vformat_to(buf, fmt.str,
vargs<T...>{{args...}}, {});
2955 template <
typename... T>
2956 FMTQUILL_INLINE
void print(format_string<T...> fmt, T&&... args) {
2957 vargs<T...> va = {{args...}};
2958 if (detail::const_check(!detail::use_utf8))
2959 return detail::vprint_mojibake(stdout, fmt.str, va,
false);
2960 return detail::is_locking<T...>() ? vprint_buffered(stdout, fmt.str, va)
2961 : vprint(fmt.str, va);
2972 template <
typename... T>
2973 FMTQUILL_INLINE
void print(FILE* f, format_string<T...> fmt, T&&... args) {
2974 vargs<T...> va = {{args...}};
2975 if (detail::const_check(!detail::use_utf8))
2976 return detail::vprint_mojibake(f, fmt.str, va,
false);
2977 return detail::is_locking<T...>() ? vprint_buffered(f, fmt.str, va)
2978 : vprint(f, fmt.str, va);
2983 template <
typename... T>
2984 FMTQUILL_INLINE
void println(FILE* f, format_string<T...> fmt, T&&... args) {
2985 vargs<T...> va = {{args...}};
2986 return detail::const_check(detail::use_utf8)
2987 ? vprintln(f, fmt.str, va)
2988 : detail::vprint_mojibake(f, fmt.str, va,
true);
2993 template <
typename... T>
2994 FMTQUILL_INLINE
void println(format_string<T...> fmt, T&&... args) {
2995 return fmtquill::println(stdout, fmt, static_cast<T&&>(args)...);
2999 FMTQUILL_PRAGMA_CLANG(diagnostic pop)
3000 FMTQUILL_PRAGMA_GCC(pop_options)
3001 FMTQUILL_END_NAMESPACE
3004 #endif // FMTQUILL_BASE_H_
FMTQUILL_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition: base.h:1799
A compile-time format string.
Definition: base.h:2731
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition: base.h:644
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:914
FMTQUILL_CONSTEXPR20 basic_string_view(const Char *s)
Constructs a string view object from a C string.
Definition: base.h:544
FMTQUILL_CONSTEXPR20 void append(const U *begin, const U *end)
Appends data to the end of the buffer.
Definition: base.h:1833
Definition: LogFunctions.h:177
FMTQUILL_CONSTEXPR context(iterator out, format_args args, detail::locale_ref loc={})
Constructs a context object.
Definition: base.h:2690
constexpr auto data() const noexcept -> const Char *
Returns a pointer to the string data.
Definition: base.h:565
FMTQUILL_CONSTEXPR void advance_to(iterator it)
Advances the begin iterator to it.
Definition: base.h:896
constexpr auto size() const noexcept -> size_t
Returns the string size.
Definition: base.h:568
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:902
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:523
FMTQUILL_CONSTEXPR void clear()
Clears this buffer.
Definition: base.h:1803
constexpr auto end() const noexcept -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition: base.h:893
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition: base.h:1793
typename V::value_type char_t
String's character (code unit) type. detail:: is intentional to prevent ADL.
Definition: base.h:961
constexpr auto capacity() const noexcept -> size_t
Returns the capacity of this buffer.
Definition: base.h:1796
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:535
constexpr auto begin() const noexcept -> iterator
Returns an iterator to the beginning of the format string range being parsed.
Definition: base.h:890
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:561
A contiguous memory buffer with an optional growing ability.
Definition: base.h:1751