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_MSC_WARNING(push)
238 FMTQUILL_MSC_WARNING(disable : 4702)
239 FMTQUILL_PRAGMA_GCC(push_options)
240 #if !defined(__OPTIMIZE__) && !defined(__CUDACC__) && !defined(FMTQUILL_MODULE) 241 FMTQUILL_PRAGMA_GCC(optimize(
"Og"))
242 # define FMTQUILL_GCC_OPTIMIZED 244 FMTQUILL_PRAGMA_CLANG(diagnostic push)
245 FMTQUILL_PRAGMA_GCC(diagnostic push)
247 #ifdef FMTQUILL_ALWAYS_INLINE 249 #elif FMTQUILL_GCC_VERSION || FMTQUILL_CLANG_VERSION 250 # define FMTQUILL_ALWAYS_INLINE inline __attribute__((always_inline)) 252 # define FMTQUILL_ALWAYS_INLINE inline 255 #if defined(NDEBUG) || defined(FMTQUILL_GCC_OPTIMIZED) 256 # define FMTQUILL_INLINE FMTQUILL_ALWAYS_INLINE 258 # define FMTQUILL_INLINE inline 261 #ifndef FMTQUILL_BEGIN_NAMESPACE 262 # define FMTQUILL_BEGIN_NAMESPACE \ 263 namespace fmtquill { \ 264 inline namespace v12 { 265 # define FMTQUILL_END_NAMESPACE \ 270 #ifndef FMTQUILL_EXPORT 271 # define FMTQUILL_EXPORT 272 # define FMTQUILL_BEGIN_EXPORT 273 # define FMTQUILL_END_EXPORT 277 # define FMTQUILL_WIN32 1 279 # define FMTQUILL_WIN32 0 282 #if !defined(FMTQUILL_HEADER_ONLY) && FMTQUILL_WIN32 283 # if defined(FMTQUILL_LIB_EXPORT) 284 # define FMTQUILL_API __declspec(dllexport) 285 # elif defined(FMTQUILL_SHARED) 286 # define FMTQUILL_API __declspec(dllimport) 288 #elif defined(FMTQUILL_LIB_EXPORT) || defined(FMTQUILL_SHARED) 289 # define FMTQUILL_API FMTQUILL_VISIBILITY("default") 292 # define FMTQUILL_API 295 #ifndef FMTQUILL_OPTIMIZE_SIZE 296 # define FMTQUILL_OPTIMIZE_SIZE 0 301 #ifndef FMTQUILL_BUILTIN_TYPES 302 # define FMTQUILL_BUILTIN_TYPES 1 305 #define FMTQUILL_APPLY_VARIADIC(expr) \ 306 using unused = int[]; \ 307 (void)unused { 0, (expr, 0)... } 309 FMTQUILL_BEGIN_NAMESPACE
312 template <
bool B,
typename T =
void>
313 using enable_if_t =
typename std::enable_if<B, T>::type;
314 template <
bool B,
typename T,
typename F>
315 using conditional_t =
typename std::conditional<B, T, F>::type;
316 template <
bool B>
using bool_constant = std::integral_constant<bool, B>;
317 template <
typename T>
318 using remove_reference_t =
typename std::remove_reference<T>::type;
319 template <
typename T>
320 using remove_const_t =
typename std::remove_const<T>::type;
321 template <
typename T>
322 using remove_cvref_t =
typename std::remove_cv<remove_reference_t<T>>::type;
323 template <
typename T>
324 using make_unsigned_t =
typename std::make_unsigned<T>::type;
325 template <
typename T>
326 using underlying_t =
typename std::underlying_type<T>::type;
327 template <
typename T>
using decay_t =
typename std::decay<T>::type;
328 using nullptr_t = decltype(
nullptr);
330 #if (FMTQUILL_GCC_VERSION && FMTQUILL_GCC_VERSION < 500) || FMTQUILL_MSC_VERSION 332 template <
typename...>
struct void_t_impl {
335 template <
typename... T>
using void_t =
typename void_t_impl<T...>::type;
337 template <
typename...>
using void_t = void;
348 # define FMTQUILL_ENABLE_IF(...) 350 # define FMTQUILL_ENABLE_IF(...) fmtquill::enable_if_t<(__VA_ARGS__), int> = 0 353 template <
typename T> constexpr
auto min_of(T a, T b) -> T {
354 return a < b ? a : b;
356 template <
typename T> constexpr
auto max_of(T a, T b) -> T {
357 return a > b ? a : b;
360 FMTQUILL_NORETURN FMTQUILL_API
void assert_fail(
const char* file,
int line,
361 const char* message);
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::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 #ifdef FMTQUILL_USE_BITINT 428 #elif FMTQUILL_CLANG_VERSION >= 1500 && !defined(__CUDACC__) 429 # define FMTQUILL_USE_BITINT 1 431 # define FMTQUILL_USE_BITINT 0 434 #if FMTQUILL_USE_BITINT 435 FMTQUILL_PRAGMA_CLANG(diagnostic ignored
"-Wbit-int-extension")
436 template <
int N>
using bitint = _BitInt(N);
437 template <
int N>
using ubitint =
unsigned _BitInt(N);
439 template <
int N>
struct bitint {};
440 template <
int N>
struct ubitint {};
441 #endif // FMTQUILL_USE_BITINT 444 template <
typename Int>
445 FMTQUILL_CONSTEXPR
auto to_unsigned(Int
value) -> make_unsigned_t<Int> {
446 FMTQUILL_ASSERT(std::is_unsigned<Int>::value || value >= 0,
"negative value");
447 return static_cast<make_unsigned_t<Int>
>(value);
450 template <
typename Char>
451 using unsigned_char = conditional_t<sizeof(Char) == 1, unsigned char, unsigned>;
455 template <
typename T,
typename Enable =
void>
457 template <
typename T>
459 typename T::value_type(), 0))>>
460 : std::is_convertible<decltype(std::declval<T>().data()),
461 const typename T::value_type*> {};
464 enum { is_utf8_enabled =
"\u00A7"[1] ==
'\xA7' };
465 enum { use_utf8 = !FMTQUILL_WIN32 || is_utf8_enabled };
467 #ifndef FMTQUILL_UNICODE 468 # define FMTQUILL_UNICODE 0 471 static_assert(!FMTQUILL_UNICODE || use_utf8,
472 "Unicode support requires compiling with /utf-8");
474 template <
typename T> constexpr
auto narrow(T*) ->
char* {
return nullptr; }
475 constexpr FMTQUILL_ALWAYS_INLINE
auto narrow(
const char* s) ->
const char* {
479 template <
typename Char>
480 FMTQUILL_CONSTEXPR
auto compare(
const Char* s1,
const Char* s2,
size_t n) ->
int {
481 if (!is_constant_evaluated() &&
sizeof(Char) == 1)
return memcmp(s1, s2, n);
482 for (; n != 0; ++s1, ++s2, --n) {
483 if (*s1 < *s2)
return -1;
484 if (*s1 > *s2)
return 1;
492 template <
typename Container>
493 auto invoke_back_inserter()
494 -> decltype(back_inserter(std::declval<Container&>()));
497 template <
typename It,
typename Enable = std::true_type>
500 template <
typename It>
502 It, bool_constant<
std::is_same<
503 decltype(adl::invoke_back_inserter<typename It::container_type>()),
504 It>
::value>> : std::true_type {};
507 template <
typename OutputIt>
508 inline FMTQUILL_CONSTEXPR20
auto get_container(OutputIt it) ->
509 typename OutputIt::container_type& {
510 struct accessor : OutputIt {
511 FMTQUILL_CONSTEXPR20 accessor(OutputIt base) : OutputIt(base) {}
512 using OutputIt::container;
514 return *accessor(it).container;
519 FMTQUILL_BEGIN_EXPORT
534 using value_type = Char;
535 using iterator =
const Char*;
541 : data_(s), size_(count) {}
546 #if FMTQUILL_GCC_VERSION 547 FMTQUILL_ALWAYS_INLINE
550 #if FMTQUILL_HAS_BUILTIN(__builtin_strlen) || FMTQUILL_GCC_VERSION || FMTQUILL_CLANG_VERSION 551 if (std::is_same<Char, char>::value && !detail::is_constant_evaluated()) {
552 size_ = __builtin_strlen(detail::narrow(s));
563 template <
typename S,
565 typename S::value_type, Char>::value)>
567 : data_(s.data()), size_(s.size()) {}
570 constexpr
auto data() const noexcept -> const Char* {
return data_; }
573 constexpr
auto size() const noexcept ->
size_t {
return size_; }
575 constexpr
auto begin()
const noexcept -> iterator {
return data_; }
576 constexpr
auto end()
const noexcept -> iterator {
return data_ + size_; }
578 constexpr
auto operator[](
size_t pos)
const noexcept ->
const Char& {
582 FMTQUILL_CONSTEXPR
void remove_prefix(
size_t n) noexcept {
589 return size_ >= sv.size_ && detail::compare(data_, sv.data_, sv.size_) == 0;
591 FMTQUILL_CONSTEXPR
auto starts_with(Char c)
const noexcept ->
bool {
592 return size_ >= 1 && *data_ == c;
594 FMTQUILL_CONSTEXPR
auto starts_with(
const Char* s)
const ->
bool {
600 detail::compare(data_, other.data_, min_of(size_, other.size_));
601 if (result != 0)
return result;
602 return size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
607 return lhs.compare(rhs) == 0;
610 return lhs.compare(rhs) != 0;
613 return lhs.compare(rhs) < 0;
616 return lhs.compare(rhs) <= 0;
619 return lhs.compare(rhs) > 0;
622 return lhs.compare(rhs) >= 0;
641 template <
typename OutputIt,
typename Char>
642 using basic_format_context =
643 conditional_t<std::is_same<OutputIt, appender>::value,
context,
647 template <
typename Char>
648 using buffered_context =
649 conditional_t<std::is_same<Char, char>::value, context,
660 template <
typename T,
typename Char =
char,
typename Enable =
void>
669 FMTQUILL_NORETURN FMTQUILL_API
void report_error(
const char* message);
671 enum class presentation_type : unsigned char {
694 enum class align { none, left, right, center, numeric };
695 enum class sign { none, minus, plus, space };
696 enum class arg_id_kind { none, index, name };
720 align_mask = 0x00038,
721 width_mask = 0x000C0,
722 precision_mask = 0x00300,
724 uppercase_mask = 0x01000,
725 alternate_mask = 0x02000,
726 localized_mask = 0x04000,
727 fill_size_mask = 0x38000,
733 fill_size_shift = 15,
738 unsigned data_ = 1 << fill_size_shift;
739 static_assert(
sizeof(basic_specs::data_) * CHAR_BIT >= 18,
"");
742 char fill_data_[max_fill_size] = {
' '};
744 FMTQUILL_CONSTEXPR
void set_fill_size(
size_t size) {
745 data_ = (data_ & ~fill_size_mask) |
746 (static_cast<unsigned>(size) << fill_size_shift);
750 constexpr
auto type()
const -> presentation_type {
751 return static_cast<presentation_type
>(data_ & type_mask);
753 FMTQUILL_CONSTEXPR
void set_type(presentation_type t) {
754 data_ = (data_ & ~type_mask) | static_cast<unsigned>(t);
757 constexpr
auto align()
const -> align {
758 return static_cast<fmtquill::align
>((data_ & align_mask) >> align_shift);
760 FMTQUILL_CONSTEXPR
void set_align(fmtquill::align a) {
761 data_ = (data_ & ~align_mask) | (static_cast<unsigned>(a) << align_shift);
764 constexpr
auto dynamic_width()
const -> arg_id_kind {
765 return static_cast<arg_id_kind
>((data_ & width_mask) >> width_shift);
767 FMTQUILL_CONSTEXPR
void set_dynamic_width(arg_id_kind w) {
768 data_ = (data_ & ~width_mask) | (static_cast<unsigned>(w) << width_shift);
771 FMTQUILL_CONSTEXPR
auto dynamic_precision()
const -> arg_id_kind {
772 return static_cast<arg_id_kind
>((data_ & precision_mask) >>
775 FMTQUILL_CONSTEXPR
void set_dynamic_precision(arg_id_kind p) {
776 data_ = (data_ & ~precision_mask) |
777 (static_cast<unsigned>(p) << precision_shift);
780 constexpr
auto dynamic()
const ->
bool {
781 return (data_ & (width_mask | precision_mask)) != 0;
784 constexpr
auto sign()
const -> sign {
785 return static_cast<fmtquill::sign
>((data_ & sign_mask) >> sign_shift);
787 FMTQUILL_CONSTEXPR
void set_sign(fmtquill::sign s) {
788 data_ = (data_ & ~sign_mask) | (static_cast<unsigned>(s) << sign_shift);
791 constexpr
auto upper()
const ->
bool {
return (data_ & uppercase_mask) != 0; }
792 FMTQUILL_CONSTEXPR
void set_upper() { data_ |= uppercase_mask; }
794 constexpr
auto alt()
const ->
bool {
return (data_ & alternate_mask) != 0; }
795 FMTQUILL_CONSTEXPR
void set_alt() { data_ |= alternate_mask; }
796 FMTQUILL_CONSTEXPR
void clear_alt() { data_ &= ~alternate_mask; }
798 constexpr
auto localized()
const ->
bool {
799 return (data_ & localized_mask) != 0;
801 FMTQUILL_CONSTEXPR
void set_localized() { data_ |= localized_mask; }
803 constexpr
auto fill_size()
const ->
size_t {
804 return (data_ & fill_size_mask) >> fill_size_shift;
807 template <typename Char, FMTQUILL_ENABLE_IF(std::is_same<Char, char>::value)>
808 constexpr
auto fill()
const ->
const Char* {
811 template <typename Char, FMTQUILL_ENABLE_IF(!std::is_same<Char, char>::value)>
812 constexpr
auto fill()
const ->
const Char* {
816 template <
typename Char> constexpr
auto fill_unit()
const -> Char {
817 using uchar =
unsigned char;
818 return static_cast<Char
>(
static_cast<uchar
>(fill_data_[0]) |
819 (static_cast<uchar>(fill_data_[1]) << 8) |
820 (static_cast<uchar>(fill_data_[2]) << 16));
823 FMTQUILL_CONSTEXPR
void set_fill(
char c) {
828 template <
typename Char>
830 auto size = s.
size();
833 unsigned uchar =
static_cast<detail::unsigned_char<Char>
>(s[0]);
834 fill_data_[0] =
static_cast<char>(uchar);
835 fill_data_[1] =
static_cast<char>(uchar >> 8);
836 fill_data_[2] =
static_cast<char>(uchar >> 16);
839 FMTQUILL_ASSERT(size <= max_fill_size,
"invalid fill");
840 for (
size_t i = 0; i < size; ++i)
841 fill_data_[i & 3] = static_cast<char>(s[i]);
844 FMTQUILL_CONSTEXPR
void copy_fill_from(
const basic_specs& specs) {
845 set_fill_size(specs.fill_size());
846 for (
size_t i = 0; i < max_fill_size; ++i)
847 fill_data_[i] = specs.fill_data_[i];
868 enum { use_constexpr_cast = !FMTQUILL_GCC_VERSION || FMTQUILL_GCC_VERSION >= 1200 };
870 FMTQUILL_CONSTEXPR
void do_check_arg_id(
int arg_id);
873 using char_type = Char;
874 using iterator =
const Char*;
878 : fmt_(fmt), next_arg_id_(next_arg_id) {}
882 constexpr
auto begin() const noexcept -> iterator {
return fmt_.begin(); }
885 constexpr
auto end() const noexcept -> iterator {
return fmt_.end(); }
889 fmt_.remove_prefix(detail::to_unsigned(it - begin()));
895 if (next_arg_id_ < 0) {
896 report_error(
"cannot switch from manual to automatic argument indexing");
899 int id = next_arg_id_++;
907 if (next_arg_id_ > 0) {
908 report_error(
"cannot switch from automatic to manual argument indexing");
917 FMTQUILL_CONSTEXPR
void check_dynamic_spec(
int arg_id);
920 #ifndef FMTQUILL_USE_LOCALE 921 # define FMTQUILL_USE_LOCALE (FMTQUILL_OPTIMIZE_SIZE <= 1) 926 #if FMTQUILL_USE_LOCALE 933 template <
typename Locale, FMTQUILL_ENABLE_IF(sizeof(Locale::collate) != 0)>
934 locale_ref(
const Locale& loc) : locale_(&loc) {
939 inline explicit operator bool()
const noexcept {
return locale_ !=
nullptr; }
940 #endif // FMTQUILL_USE_LOCALE 943 template <
typename Locale>
auto get()
const -> Locale;
957 template <>
struct is_code_unit<char8_t> : bool_constant<is_utf8_enabled> {};
963 template <typename Char, FMTQUILL_ENABLE_IF(is_code_unit<Char>::value)>
967 template <typename T, FMTQUILL_ENABLE_IF(is_std_string_like<T>::value)>
968 constexpr
auto to_string_view(
const T& s)
972 template <
typename Char>
978 template <
typename T,
typename Enable =
void>
981 template <
typename T>
983 T, void_t<decltype(
detail::to_string_view(std::declval<T>()))>>
987 template <
typename S,
988 typename V = decltype(detail::to_string_view(std::declval<S>()))>
1002 last_integer_type = char_type,
1007 last_numeric_type = long_double_type,
1015 template <
typename T,
typename Char>
1018 #define FMTQUILL_TYPE_CONSTANT(Type, constant) \ 1019 template <typename Char> \ 1020 struct type_constant<Type, Char> \ 1021 : std::integral_constant<type, type::constant> {} 1023 FMTQUILL_TYPE_CONSTANT(
int, int_type);
1024 FMTQUILL_TYPE_CONSTANT(
unsigned, uint_type);
1025 FMTQUILL_TYPE_CONSTANT(
long long, long_long_type);
1026 FMTQUILL_TYPE_CONSTANT(
unsigned long long, ulong_long_type);
1027 FMTQUILL_TYPE_CONSTANT(int128_opt, int128_type);
1028 FMTQUILL_TYPE_CONSTANT(uint128_opt, uint128_type);
1029 FMTQUILL_TYPE_CONSTANT(
bool, bool_type);
1030 FMTQUILL_TYPE_CONSTANT(Char, char_type);
1031 FMTQUILL_TYPE_CONSTANT(
float, float_type);
1032 FMTQUILL_TYPE_CONSTANT(
double, double_type);
1033 FMTQUILL_TYPE_CONSTANT(
long double, long_double_type);
1034 FMTQUILL_TYPE_CONSTANT(
const Char*, cstring_type);
1036 FMTQUILL_TYPE_CONSTANT(
const void*, pointer_type);
1038 constexpr
auto is_integral_type(type t) ->
bool {
1039 return t > type::none_type && t <= type::last_integer_type;
1041 constexpr
auto is_arithmetic_type(type t) ->
bool {
1042 return t > type::none_type && t <= type::last_numeric_type;
1045 constexpr
auto set(type rhs) ->
int {
return 1 <<
static_cast<int>(rhs); }
1046 constexpr
auto in(type t,
int set) ->
bool {
1047 return ((
set >> static_cast<int>(t)) & 1) != 0;
1053 set(type::int_type) |
set(type::long_long_type) |
set(type::int128_type),
1054 uint_set =
set(type::uint_type) |
set(type::ulong_long_type) |
1055 set(type::uint128_type),
1056 bool_set =
set(type::bool_type),
1057 char_set =
set(type::char_type),
1058 float_set =
set(type::float_type) |
set(type::double_type) |
1059 set(type::long_double_type),
1060 string_set =
set(type::string_type),
1061 cstring_set =
set(type::cstring_type),
1062 pointer_set =
set(type::pointer_type)
1067 template <
typename T,
typename Enable = std::true_type>
1069 template <
typename T>
1070 struct is_view<T, bool_constant<sizeof(T) != 0>> : std::is_base_of<view, T> {};
1076 template <
typename Char,
typename T>
1079 template <
typename Char,
typename T>
struct named_arg :
view {
1083 named_arg(
const Char* n,
const T& v) : name(n), value(v) {}
1087 template <
bool B = false> constexpr
auto count() ->
int {
return B ? 1 : 0; }
1088 template <
bool B1,
bool B2,
bool... Tail> constexpr
auto count() ->
int {
1089 return (B1 ? 1 : 0) + count<B2, Tail...>();
1092 template <
typename... T> constexpr
auto count_named_args() ->
int {
1093 return count<is_named_arg<T>::value...>();
1095 template <
typename... T> constexpr
auto count_static_named_args() ->
int {
1096 return count<is_static_named_arg<T>::value...>();
1105 template <
typename Char>
1107 int named_arg_index,
1109 for (
int i = 0; i < named_arg_index; ++i) {
1110 if (named_args[i].name == arg_name) report_error(
"duplicate named arg");
1114 template <typename Char, typename T, FMTQUILL_ENABLE_IF(!is_named_arg<T>::value)>
1118 template <typename Char, typename T, FMTQUILL_ENABLE_IF(is_named_arg<T>::value)>
1120 int& named_arg_index,
const T& arg) {
1121 check_for_duplicate<Char>(named_args, named_arg_index, arg.name);
1122 named_args[named_arg_index++] = {arg.name, arg_index++};
1125 template <
typename T,
typename Char,
1131 template <
typename T,
typename Char,
1134 int& arg_index,
int& named_arg_index) {
1135 check_for_duplicate<Char>(named_args, named_arg_index, T::name);
1136 named_args[named_arg_index++] = {T::name, arg_index++};
1141 enum { long_short =
sizeof(long) ==
sizeof(
int) && FMTQUILL_BUILTIN_TYPES };
1142 using long_type = conditional_t<long_short, int, long long>;
1143 using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
1145 template <
typename T>
1146 using format_as_result =
1147 remove_cvref_t<decltype(format_as(std::declval<const T&>()))>;
1148 template <
typename T>
1149 using format_as_member_result =
1150 remove_cvref_t<decltype(formatter<T>::format_as(std::declval<const T&>()))>;
1152 template <
typename T,
typename Enable = std::true_type>
1155 template <
typename T,
typename Enable = std::true_type>
1159 template <
typename T>
1161 T, bool_constant<
std::is_arithmetic<format_as_result<T>>
::value>>
1162 : std::true_type {};
1163 template <
typename T>
1165 T, bool_constant<std::is_arithmetic<format_as_member_result<T>>
::value>>
1166 : std::true_type {};
1168 template <
typename T,
typename U = remove_const_t<T>>
1169 using use_formatter =
1170 bool_constant<(std::is_class<T>::value || std::is_enum<T>::value ||
1171 std::is_union<T>::value || std::is_array<T>::value) &&
1175 template <
typename Char,
typename T,
typename U = remove_const_t<T>>
1176 auto has_formatter_impl(T* p, buffered_context<Char>* ctx =
nullptr)
1178 template <
typename Char>
auto has_formatter_impl(...) -> std::false_type;
1181 template <
typename T,
typename Char> constexpr
auto has_formatter() ->
bool {
1182 return decltype(has_formatter_impl<Char>(static_cast<T*>(
nullptr)))::
value;
1188 static auto map(
signed char) -> int;
1189 static auto map(
unsigned char) -> unsigned;
1190 static auto map(
short) -> int;
1191 static auto map(
unsigned short) -> unsigned;
1192 static auto map(
int) -> int;
1193 static auto map(
unsigned) -> unsigned;
1194 static auto map(
long) -> long_type;
1195 static auto map(
unsigned long) -> ulong_type;
1196 static auto map(
long long) ->
long long;
1197 static auto map(
unsigned long long) ->
unsigned long long;
1198 static auto map(int128_opt) -> int128_opt;
1199 static auto map(uint128_opt) -> uint128_opt;
1200 static auto map(
bool) -> bool;
1203 static auto map(
bitint<N>) -> conditional_t<N <= 64, long long, void>;
1206 -> conditional_t<N <= 64, unsigned long long, void>;
1208 template <typename T, FMTQUILL_ENABLE_IF(is_code_unit<T>::value)>
1209 static auto map(T) -> conditional_t<
1210 std::is_same<T, char>::value || std::is_same<T, Char>::value, Char,
void>;
1212 static auto map(
float) -> float;
1213 static auto map(
double) -> double;
1214 static auto map(
long double) ->
long double;
1216 static auto map(Char*) ->
const Char*;
1217 static auto map(
const Char*) ->
const Char*;
1218 template <
typename T,
typename C =
char_t<T>,
1219 FMTQUILL_ENABLE_IF(!std::is_po
inter<T>::value)>
1220 static auto map(
const T&) -> conditional_t<std::is_same<C, Char>::value,
1223 static auto map(
void*) ->
const void*;
1224 static auto map(
const void*) ->
const void*;
1225 static auto map(
volatile void*) ->
const void*;
1226 static auto map(
const volatile void*) ->
const void*;
1227 static auto map(nullptr_t) ->
const void*;
1228 template <typename T, FMTQUILL_ENABLE_IF(std::is_pointer<T>::value ||
1229 std::is_member_pointer<T>::value)>
1230 static auto map(
const T&) -> void;
1232 template <typename T, FMTQUILL_ENABLE_IF(use_format_as<T>::value)>
1233 static auto map(
const T& x) -> decltype(map(format_as(x)));
1234 template <typename T, FMTQUILL_ENABLE_IF(use_format_as_member<T>::value)>
1237 template <typename T, FMTQUILL_ENABLE_IF(use_formatter<T>::value)>
1238 static auto map(T&) -> conditional_t<has_formatter<T, Char>(), T&,
void>;
1240 template <typename T, FMTQUILL_ENABLE_IF(is_named_arg<T>::value)>
1241 static auto map(
const T&
named_arg) -> decltype(map(named_arg.value));
1245 template <
typename T,
typename Char>
1249 template <
typename T,
typename Char =
char>
1252 template <
typename T,
typename Context,
1255 using stored_type_constant = std::integral_constant<
1256 type, Context::builtin_types || TYPE == type::int_type ? TYPE
1257 : type::custom_type>;
1259 template <
typename Char>
1268 int num_args,
const type* types,
1269 int next_arg_id = 0)
1270 :
base(fmt, next_arg_id), num_args_(num_args), types_(types) {}
1272 constexpr
auto num_args()
const ->
int {
return num_args_; }
1273 constexpr
auto arg_type(
int id)
const -> type {
return types_[id]; }
1275 FMTQUILL_CONSTEXPR
auto next_arg_id() ->
int {
1276 int id = base::next_arg_id();
1277 if (
id >= num_args_) report_error(
"argument not found");
1281 FMTQUILL_CONSTEXPR
void check_arg_id(
int id) {
1282 base::check_arg_id(
id);
1283 if (
id >= num_args_) report_error(
"argument not found");
1285 using base::check_arg_id;
1287 FMTQUILL_CONSTEXPR
void check_dynamic_spec(
int arg_id) {
1288 ignore_unused(arg_id);
1289 if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
1290 report_error(
"width/precision is not integer");
1296 FMTQUILL_CONSTEXPR
arg_ref(
int idx = 0) : index(idx) {}
1312 template <typename Char, FMTQUILL_ENABLE_IF(std::is_integral<Char>::value)>
1313 constexpr
auto to_ascii(Char c) ->
char {
1314 return c <= 0xff ? static_cast<char>(c) :
'\0';
1318 template <
typename Char>
1319 FMTQUILL_CONSTEXPR
auto code_point_length(
const Char* begin) ->
int {
1320 if (const_check(
sizeof(Char) != 1))
return 1;
1321 auto c =
static_cast<unsigned char>(*begin);
1322 return static_cast<int>((0x3a55000000000000ull >> (2 * (c >> 3))) & 3) + 1;
1327 template <
typename Char>
1328 FMTQUILL_CONSTEXPR
auto parse_nonnegative_int(
const Char*& begin,
const Char* end,
1329 int error_value) noexcept ->
int {
1330 FMTQUILL_ASSERT(begin != end &&
'0' <= *begin && *begin <=
'9',
"");
1331 unsigned value = 0, prev = 0;
1335 value = value * 10 + unsigned(*p -
'0');
1337 }
while (p != end &&
'0' <= *p && *p <=
'9');
1338 auto num_digits = p - begin;
1340 int digits10 =
static_cast<int>(
sizeof(int) * CHAR_BIT * 3 / 10);
1341 if (num_digits <= digits10)
return static_cast<int>(value);
1343 unsigned max = INT_MAX;
1344 return num_digits == digits10 + 1 &&
1345 prev * 10ull + unsigned(p[-1] -
'0') <= max
1346 ?
static_cast<int>(value)
1350 FMTQUILL_CONSTEXPR
inline auto parse_align(
char c) -> align {
1352 case '<':
return align::left;
1353 case '>':
return align::right;
1354 case '^':
return align::center;
1359 template <
typename Char> constexpr
auto is_name_start(Char c) ->
bool {
1360 return (
'a' <= c && c <=
'z') || (
'A' <= c && c <=
'Z') || c ==
'_';
1363 template <
typename Char,
typename Handler>
1364 FMTQUILL_CONSTEXPR
auto parse_arg_id(
const Char* begin,
const Char* end,
1365 Handler&& handler) ->
const Char* {
1367 if (c >=
'0' && c <=
'9') {
1370 index = parse_nonnegative_int(begin, end, INT_MAX);
1373 if (begin == end || (*begin !=
'}' && *begin !=
':'))
1374 report_error(
"invalid format string");
1376 handler.on_index(index);
1379 if (FMTQUILL_OPTIMIZE_SIZE > 1 || !is_name_start(c)) {
1380 report_error(
"invalid format string");
1386 }
while (it != end && (is_name_start(*it) || (
'0' <= *it && *it <=
'9')));
1387 handler.on_name({begin, to_unsigned(it - begin)});
1396 FMTQUILL_CONSTEXPR
void on_index(
int id) {
1398 kind = arg_id_kind::index;
1400 ctx.check_dynamic_spec(
id);
1404 kind = arg_id_kind::name;
1415 template <
typename Char>
1416 FMTQUILL_CONSTEXPR
auto parse_dynamic_spec(
const Char* begin,
const Char* end,
1420 FMTQUILL_ASSERT(begin != end,
"");
1421 auto kind = arg_id_kind::none;
1422 if (
'0' <= *begin && *begin <=
'9') {
1423 int val = parse_nonnegative_int(begin, end, -1);
1424 if (val == -1) report_error(
"number is too big");
1427 if (*begin ==
'{') {
1431 if (c ==
'}' || c ==
':') {
1434 kind = arg_id_kind::index;
1435 ctx.check_dynamic_spec(
id);
1437 begin = parse_arg_id(begin, end,
1441 if (begin != end && *begin ==
'}')
return {++begin, kind};
1443 report_error(
"invalid format string");
1445 return {begin, kind};
1448 template <
typename Char>
1449 FMTQUILL_CONSTEXPR
auto parse_width(
const Char* begin,
const Char* end,
1452 auto result = parse_dynamic_spec(begin, end, specs.width, width_ref, ctx);
1453 specs.set_dynamic_width(result.kind);
1457 template <
typename Char>
1458 FMTQUILL_CONSTEXPR
auto parse_precision(
const Char* begin,
const Char* end,
1464 report_error(
"invalid precision");
1468 parse_dynamic_spec(begin, end, specs.precision, precision_ref, ctx);
1469 specs.set_dynamic_precision(result.kind);
1473 enum class state { start, align, sign, hash, zero, width, precision, locale };
1476 template <
typename Char>
1477 FMTQUILL_CONSTEXPR
auto parse_format_specs(
const Char* begin,
const Char* end,
1482 if (end - begin > 1) {
1483 auto next = to_ascii(begin[1]);
1484 c = parse_align(next) == align::none ? to_ascii(*begin) :
'\0';
1486 if (begin == end)
return begin;
1487 c = to_ascii(*begin);
1491 state current_state = state::start;
1492 FMTQUILL_CONSTEXPR
void operator()(state s,
bool valid =
true) {
1493 if (current_state >= s || !valid)
1494 report_error(
"invalid format specifier");
1499 using pres = presentation_type;
1500 constexpr
auto integral_set = sint_set | uint_set | bool_set | char_set;
1506 FMTQUILL_CONSTEXPR
auto operator()(pres pres_type,
int set) ->
const Char* {
1507 if (!in(arg_type,
set)) report_error(
"invalid format specifier");
1508 specs.set_type(pres_type);
1511 } parse_presentation_type{begin, specs, arg_type};
1518 enter_state(state::align);
1519 specs.set_align(parse_align(c));
1524 specs.set_sign(c ==
' ' ? sign::space : sign::plus);
1525 FMTQUILL_FALLTHROUGH;
1527 enter_state(state::sign, in(arg_type, sint_set | float_set));
1531 enter_state(state::hash, is_arithmetic_type(arg_type));
1536 enter_state(state::zero);
1537 if (!is_arithmetic_type(arg_type))
1538 report_error(
"format specifier requires numeric argument");
1539 if (specs.align() == align::none) {
1541 specs.set_align(align::numeric);
1542 specs.set_fill(
'0');
1547 case '1':
case '2':
case '3':
case '4':
case '5':
1548 case '6':
case '7':
case '8':
case '9':
case '{':
1550 enter_state(state::width);
1551 begin = parse_width(begin, end, specs, specs.width_ref, ctx);
1554 enter_state(state::precision,
1555 in(arg_type, float_set | string_set | cstring_set));
1556 begin = parse_precision(begin, end, specs, specs.precision_ref, ctx);
1559 enter_state(state::locale, is_arithmetic_type(arg_type));
1560 specs.set_localized();
1563 case 'd':
return parse_presentation_type(pres::dec, integral_set);
1564 case 'X': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1565 case 'x':
return parse_presentation_type(pres::hex, integral_set);
1566 case 'o':
return parse_presentation_type(pres::oct, integral_set);
1567 case 'B': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1568 case 'b':
return parse_presentation_type(pres::bin, integral_set);
1569 case 'E': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1570 case 'e':
return parse_presentation_type(pres::exp, float_set);
1571 case 'F': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1572 case 'f':
return parse_presentation_type(pres::fixed, float_set);
1573 case 'G': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1574 case 'g':
return parse_presentation_type(pres::general, float_set);
1575 case 'A': specs.set_upper(); FMTQUILL_FALLTHROUGH;
1576 case 'a':
return parse_presentation_type(pres::hexfloat, float_set);
1578 if (arg_type == type::bool_type) report_error(
"invalid format specifier");
1579 return parse_presentation_type(pres::chr, integral_set);
1581 return parse_presentation_type(pres::string,
1582 bool_set | string_set | cstring_set);
1584 return parse_presentation_type(pres::pointer, pointer_set | cstring_set);
1586 return parse_presentation_type(pres::debug,
1587 char_set | string_set | cstring_set);
1588 case '}':
return begin;
1590 if (*begin ==
'}')
return begin;
1592 auto fill_end = begin + code_point_length(begin);
1593 if (end - fill_end <= 0) {
1594 report_error(
"invalid format specifier");
1597 if (*begin ==
'{') {
1598 report_error(
"invalid fill character '{'");
1601 auto alignment = parse_align(to_ascii(*fill_end));
1602 enter_state(state::align, alignment != align::none);
1605 specs.set_align(alignment);
1606 begin = fill_end + 1;
1609 if (begin == end)
return begin;
1610 c = to_ascii(*begin);
1614 template <
typename Char,
typename Handler>
1615 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
auto parse_replacement_field(
const Char* begin,
1621 handler.on_error(
"invalid format string");
1627 handler.on_replacement_field(handler.on_arg_id(), begin);
1629 case '{': handler.on_text(begin, begin + 1);
return begin + 1;
1630 case ':': arg_id = handler.on_arg_id();
break;
1636 FMTQUILL_CONSTEXPR
void on_index(
int id) { arg_id = handler.on_arg_id(
id); }
1638 arg_id = handler.on_arg_id(
id);
1640 } adapter = {handler, 0};
1641 begin = parse_arg_id(begin, end, adapter);
1642 arg_id = adapter.arg_id;
1643 Char c = begin != end ? *begin : Char();
1645 handler.on_replacement_field(arg_id, begin);
1649 handler.on_error(
"missing '}' in format string");
1655 begin = handler.on_format_specs(arg_id, begin + 1, end);
1656 if (begin == end || *begin !=
'}')
1657 return handler.on_error(
"unknown format specifier"), end;
1661 template <
typename Char,
typename Handler>
1663 Handler&& handler) {
1664 auto begin = fmt.
data(), end = begin + fmt.
size();
1669 handler.on_text(begin, p - 1);
1670 begin = p = parse_replacement_field(p - 1, end, handler);
1671 }
else if (c ==
'}') {
1672 if (p == end || *p !=
'}')
1673 return handler.on_error(
"unmatched '}' in format string");
1674 handler.on_text(begin, p);
1678 handler.on_text(begin, end);
1682 FMTQUILL_CONSTEXPR
inline auto check_char_specs(
const format_specs& specs) ->
bool {
1683 auto type = specs.type();
1684 if (type != presentation_type::none && type != presentation_type::chr &&
1685 type != presentation_type::debug) {
1688 if (specs.align() == align::numeric || specs.sign() != sign::none ||
1690 report_error(
"invalid format specifier for char");
1698 template <
typename T,
typename Char>
1699 FMTQUILL_VISIBILITY(
"hidden")
1701 using mapped_type = remove_cvref_t<mapped_t<T, Char>>;
1702 constexpr
bool formattable =
1703 std::is_constructible<formatter<mapped_type, Char>>
::value;
1704 if (!formattable)
return ctx.
begin();
1705 using formatted_type = conditional_t<formattable, mapped_type, int>;
1711 template <
typename Char,
int NUM_ARGS,
int NUM_NAMED_ARGS,
bool DYNAMIC_NAMES>
1714 type types_[max_of<size_t>(1, NUM_ARGS)];
1719 parse_func parse_funcs_[max_of<size_t>(1, NUM_ARGS)];
1722 template <
typename... T>
1727 context_(fmt, NUM_ARGS, types_),
1728 parse_funcs_{&invoke_parse<T, Char>...} {
1729 int arg_index = 0, named_arg_index = 0;
1730 FMTQUILL_APPLY_VARIADIC(
1731 init_static_named_arg<T>(named_args_, arg_index, named_arg_index));
1732 ignore_unused(arg_index, named_arg_index);
1735 FMTQUILL_CONSTEXPR
void on_text(
const Char*,
const Char*) {}
1737 FMTQUILL_CONSTEXPR
auto on_arg_id() ->
int {
return context_.next_arg_id(); }
1738 FMTQUILL_CONSTEXPR
auto on_arg_id(
int id) ->
int {
1739 context_.check_arg_id(
id);
1743 for (
int i = 0; i < NUM_NAMED_ARGS; ++i) {
1744 if (named_args_[i].name ==
id)
return named_args_[i].id;
1746 if (!DYNAMIC_NAMES) on_error(
"argument not found");
1750 FMTQUILL_CONSTEXPR
void on_replacement_field(
int id,
const Char* begin) {
1751 on_format_specs(
id, begin, begin);
1754 FMTQUILL_CONSTEXPR
auto on_format_specs(
int id,
const Char* begin,
const Char* end)
1756 context_.advance_to(begin);
1757 if (
id >= 0 &&
id < NUM_ARGS)
return parse_funcs_[id](context_);
1762 for (
int bracket_count = 0;
1763 begin != end && (bracket_count > 0 || *begin !=
'}'); ++begin) {
1766 else if (*begin ==
'}')
1772 FMTQUILL_NORETURN FMTQUILL_CONSTEXPR
void on_error(
const char* message) {
1773 report_error(message);
1785 using grow_fun = void (*)(
buffer& buf,
size_t capacity);
1790 FMTQUILL_MSC_WARNING(suppress : 26495)
1791 FMTQUILL_CONSTEXPR
buffer(grow_fun grow,
size_t sz) noexcept
1792 : size_(sz), capacity_(sz), grow_(grow) {}
1794 constexpr
buffer(grow_fun grow, T* p =
nullptr,
size_t sz = 0,
1795 size_t cap = 0) noexcept
1796 : ptr_(p), size_(sz), capacity_(cap), grow_(grow) {}
1798 FMTQUILL_CONSTEXPR20 ~
buffer() =
default;
1802 FMTQUILL_CONSTEXPR
void set(T* buf_data,
size_t buf_capacity) noexcept {
1804 capacity_ = buf_capacity;
1808 using value_type = T;
1809 using const_reference =
const T&;
1812 void operator=(
const buffer&) =
delete;
1814 auto begin() noexcept -> T* {
return ptr_; }
1815 auto end() noexcept -> T* {
return ptr_ + size_; }
1817 auto begin()
const noexcept ->
const T* {
return ptr_; }
1818 auto end()
const noexcept ->
const T* {
return ptr_ + size_; }
1821 constexpr
auto size() const noexcept ->
size_t {
return size_; }
1824 constexpr
auto capacity() const noexcept ->
size_t {
return capacity_; }
1827 FMTQUILL_CONSTEXPR
auto data() noexcept -> T* {
return ptr_; }
1828 FMTQUILL_CONSTEXPR
auto data()
const noexcept ->
const T* {
return ptr_; }
1831 FMTQUILL_CONSTEXPR
void clear() { size_ = 0; }
1835 FMTQUILL_CONSTEXPR
void try_resize(
size_t count) {
1837 size_ = min_of(count, capacity_);
1844 FMTQUILL_CONSTEXPR
void try_reserve(
size_t new_capacity) {
1845 if (new_capacity > capacity_) grow_(*
this, new_capacity);
1848 FMTQUILL_CONSTEXPR
void push_back(
const T& value) {
1849 try_reserve(size_ + 1);
1850 ptr_[size_++] = value;
1854 template <
typename U>
1857 #if !FMTQUILL_MSC_VERSION || FMTQUILL_MSC_VERSION >= 1940 1858 FMTQUILL_CONSTEXPR20
1862 while (begin != end) {
1864 auto free_cap = capacity_ - size;
1865 auto count = to_unsigned(end - begin);
1867 if (free_cap < count) {
1868 grow_(*
this, size + count);
1870 free_cap = capacity_ - size;
1871 count = count < free_cap ? count : free_cap;
1874 if constexpr (std::is_same<T, U>::value) {
1875 memcpy(ptr_ + size_, begin, count *
sizeof(T));
1877 T* out = ptr_ + size_;
1878 for (
size_t i = 0; i < count; ++i) out[i] = begin[i];
1886 template <
typename Idx> FMTQUILL_CONSTEXPR
auto operator[](Idx index) -> T& {
1889 template <
typename Idx>
1890 FMTQUILL_CONSTEXPR
auto operator[](Idx index)
const ->
const T& {
1897 constexpr
auto count()
const ->
size_t {
return 0; }
1898 constexpr
auto limit(
size_t size)
const ->
size_t {
return size; }
1908 constexpr
auto count()
const ->
size_t {
return count_; }
1909 FMTQUILL_CONSTEXPR
auto limit(
size_t size) ->
size_t {
1910 size_t n = limit_ > count_ ? limit_ - count_ : 0;
1912 return min_of(size, n);
1917 template <
typename OutputIt,
typename T,
typename Traits = buffer_traits>
1921 enum { buffer_size = 256 };
1922 T data_[buffer_size];
1924 static FMTQUILL_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
1925 if (buf.
size() == buffer_size) static_cast<iterator_buffer&>(buf).flush();
1929 auto size = this->size();
1931 const T* begin = data_;
1932 const T* end = begin + this->limit(size);
1933 while (begin != end) *out_++ = *begin++;
1938 : Traits(n),
buffer<T>(grow, data_, 0, buffer_size), out_(out) {}
1945 FMTQUILL_TRY { flush(); }
1946 FMTQUILL_CATCH(...) {}
1949 auto out() -> OutputIt {
1953 auto count()
const ->
size_t {
return Traits::count() + this->size(); }
1956 template <
typename T>
1961 enum { buffer_size = 256 };
1962 T data_[buffer_size];
1964 static FMTQUILL_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
1966 static_cast<iterator_buffer&>(buf).flush();
1970 size_t n = this->limit(this->size());
1971 if (this->data() == out_) {
1973 this->
set(data_, buffer_size);
1985 if (this->data() != out_) {
1986 this->
set(data_, buffer_size);
1996 auto count()
const ->
size_t {
1997 return fixed_buffer_traits::count() + this->size();
2006 auto out() -> T* {
return &*this->end(); }
2009 template <
typename Container>
2012 using value_type =
typename Container::value_type;
2016 self.container.resize(capacity);
2017 self.set(&
self.container[0], capacity);
2021 Container& container;
2028 template <
typename OutputIt>
2033 typename OutputIt::container_type::value_type>>
2041 :
base(get_container(out)) {}
2043 auto out() -> OutputIt {
return OutputIt(this->container); }
2049 enum { buffer_size = 256 };
2050 T data_[buffer_size];
2053 static FMTQUILL_CONSTEXPR
void grow(
buffer<T>& buf,
size_t) {
2054 if (buf.
size() != buffer_size)
return;
2062 constexpr
auto count()
const noexcept ->
size_t {
2063 return count_ + this->size();
2067 template <
typename T>
2070 template <
typename OutputIt,
typename InputIt,
typename =
void>
2072 template <
typename OutputIt,
typename InputIt>
2075 void_t<decltype(get_container(std::declval<OutputIt>())
2076 .append(std::declval<InputIt>(),
2077 std::declval<InputIt>()))>> : std::true_type {};
2079 template <
typename OutputIt,
typename InputIt,
typename =
void>
2082 template <
typename OutputIt,
typename InputIt>
2085 void_t<decltype(get_container(std::declval<OutputIt>())
2086 .insert(get_container(std::declval<OutputIt>()).end(),
2087 std::declval<InputIt>(),
2088 std::declval<InputIt>()))>> : std::true_type {};
2091 template <
typename T,
typename InputIt,
typename OutputIt,
2094 OutputIt, InputIt>::value)>
2095 FMTQUILL_CONSTEXPR20
auto copy(InputIt begin, InputIt end, OutputIt out)
2097 get_container(out).append(begin, end);
2101 template <
typename T,
typename InputIt,
typename OutputIt,
2104 OutputIt, InputIt>::value &&
2106 OutputIt, InputIt>::value)>
2107 FMTQUILL_CONSTEXPR20
auto copy(InputIt begin, InputIt end, OutputIt out)
2109 auto& c = get_container(out);
2110 c.insert(c.end(), begin, end);
2114 template <
typename T,
typename InputIt,
typename OutputIt,
2117 OutputIt, InputIt>::value ||
2119 OutputIt, InputIt>::value)))>
2120 FMTQUILL_CONSTEXPR
auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
2121 #if defined(__GNUC__) && !defined(__clang__) 2122 #pragma GCC diagnostic push 2123 #pragma GCC diagnostic ignored "-Wstringop-overflow" 2126 while (begin != end) *out++ =
static_cast<T
>(*begin++);
2128 #if defined(__GNUC__) && !defined(__clang__) 2129 #pragma GCC diagnostic pop 2135 template <
typename T,
typename V,
typename OutputIt>
2137 return copy<T>(s.begin(), s.end(), out);
2140 template <
typename It,
typename Enable = std::true_type>
2142 template <
typename It>
2146 std::is_base_of<buffer<typename It::container_type::value_type>,
2147 typename It::container_type>
::value>>
2148 : std::true_type {};
2151 template <
typename T,
typename OutputIt,
2156 template <
typename T,
typename OutputIt,
2158 auto get_buffer(OutputIt out) ->
buffer<T>& {
2159 return get_container(out);
2162 template <
typename Buf,
typename OutputIt>
2163 auto get_iterator(Buf& buf, OutputIt) -> decltype(buf.out()) {
2166 template <
typename T,
typename OutputIt>
2167 auto get_iterator(
buffer<T>&, OutputIt out) -> OutputIt {
2181 using char_type =
typename Context::char_type;
2193 #if !FMTQUILL_BUILTIN_TYPES 2194 # define FMTQUILL_BUILTIN , monostate 2196 # define FMTQUILL_BUILTIN 2200 template <
typename Context>
class value {
2202 using char_type =
typename Context::char_type;
2207 unsigned uint_value;
2208 long long long_long_value;
2209 unsigned long long ulong_long_value;
2210 int128_opt int128_value;
2211 uint128_opt uint128_value;
2213 char_type char_value;
2215 double double_value;
2216 long double long_double_value;
2217 const void* pointer;
2223 constexpr FMTQUILL_INLINE value() : no_value() {}
2224 constexpr FMTQUILL_INLINE value(
signed char x) : int_value(x) {}
2225 constexpr FMTQUILL_INLINE value(
unsigned char x FMTQUILL_BUILTIN) : uint_value(x) {}
2226 constexpr FMTQUILL_INLINE value(
signed short x) : int_value(x) {}
2227 constexpr FMTQUILL_INLINE value(
unsigned short x FMTQUILL_BUILTIN) : uint_value(x) {}
2228 constexpr FMTQUILL_INLINE value(
int x) : int_value(x) {}
2229 constexpr FMTQUILL_INLINE value(
unsigned x FMTQUILL_BUILTIN) : uint_value(x) {}
2230 FMTQUILL_CONSTEXPR FMTQUILL_INLINE value(
long x FMTQUILL_BUILTIN) : value(long_type(x)) {}
2231 FMTQUILL_CONSTEXPR FMTQUILL_INLINE value(
unsigned long x FMTQUILL_BUILTIN)
2232 : value(ulong_type(x)) {}
2233 constexpr FMTQUILL_INLINE value(
long long x FMTQUILL_BUILTIN) : long_long_value(x) {}
2234 constexpr FMTQUILL_INLINE value(
unsigned long long x FMTQUILL_BUILTIN)
2235 : ulong_long_value(x) {}
2236 FMTQUILL_INLINE value(int128_opt x FMTQUILL_BUILTIN) : int128_value(x) {}
2237 FMTQUILL_INLINE value(uint128_opt x FMTQUILL_BUILTIN) : uint128_value(x) {}
2238 constexpr FMTQUILL_INLINE value(
bool x FMTQUILL_BUILTIN) : bool_value(x) {}
2241 constexpr FMTQUILL_INLINE value(
bitint<N> x FMTQUILL_BUILTIN) : long_long_value(x) {
2242 static_assert(N <= 64,
"unsupported _BitInt");
2245 constexpr FMTQUILL_INLINE value(
ubitint<N> x FMTQUILL_BUILTIN) : ulong_long_value(x) {
2246 static_assert(N <= 64,
"unsupported _BitInt");
2249 template <typename T, FMTQUILL_ENABLE_IF(is_code_unit<T>::value)>
2250 constexpr FMTQUILL_INLINE value(T x FMTQUILL_BUILTIN) : char_value(x) {
2252 std::is_same<T, char>::value || std::is_same<T, char_type>::value,
2253 "mixing character types is disallowed");
2256 constexpr FMTQUILL_INLINE value(
float x FMTQUILL_BUILTIN) : float_value(x) {}
2257 constexpr FMTQUILL_INLINE value(
double x FMTQUILL_BUILTIN) : double_value(x) {}
2258 FMTQUILL_INLINE value(
long double x FMTQUILL_BUILTIN) : long_double_value(x) {}
2260 FMTQUILL_CONSTEXPR FMTQUILL_INLINE value(char_type* x FMTQUILL_BUILTIN) {
2262 if (is_constant_evaluated())
string.size = 0;
2264 FMTQUILL_CONSTEXPR FMTQUILL_INLINE value(
const char_type* x FMTQUILL_BUILTIN) {
2266 if (is_constant_evaluated())
string.size = 0;
2268 template <
typename T,
typename C =
char_t<T>,
2269 FMTQUILL_ENABLE_IF(!std::is_po
inter<T>::value)>
2270 FMTQUILL_CONSTEXPR value(
const T& x FMTQUILL_BUILTIN) {
2271 static_assert(std::is_same<C, char_type>::value,
2272 "mixing character types is disallowed");
2273 auto sv = to_string_view(x);
2274 string.data = sv.data();
2275 string.size = sv.size();
2277 FMTQUILL_INLINE value(
void* x FMTQUILL_BUILTIN) : pointer(x) {}
2278 FMTQUILL_INLINE value(
const void* x FMTQUILL_BUILTIN) : pointer(x) {}
2279 FMTQUILL_INLINE value(
volatile void* x FMTQUILL_BUILTIN)
2280 : pointer(const_cast<const void*>(x)) {}
2281 FMTQUILL_INLINE value(
const volatile void* x FMTQUILL_BUILTIN)
2282 : pointer(const_cast<const void*>(x)) {}
2283 FMTQUILL_INLINE value(nullptr_t) : pointer(
nullptr) {}
2285 template <typename T, FMTQUILL_ENABLE_IF(std::is_pointer<T>::value ||
2286 std::is_member_pointer<T>::value)>
2291 static_assert(
sizeof(T) == 0,
2292 "formatting of non-void pointers is disallowed");
2295 template <typename T, FMTQUILL_ENABLE_IF(use_format_as<T>::value)>
2296 value(
const T& x) : value(format_as(x)) {}
2297 template <typename T, FMTQUILL_ENABLE_IF(use_format_as_member<T>::value)>
2300 template <typename T, FMTQUILL_ENABLE_IF(is_named_arg<T>::value)>
2301 value(
const T&
named_arg) : value(named_arg.value) {}
2303 template <
typename T,
2304 FMTQUILL_ENABLE_IF(use_formatter<T>::value || !FMTQUILL_BUILTIN_TYPES)>
2305 FMTQUILL_CONSTEXPR20 FMTQUILL_INLINE value(T& x) : value(x,
custom_tag()) {}
2308 : named_args{args, size} {}
2311 template <
typename T, FMTQUILL_ENABLE_IF(has_formatter<T,
char_type>())>
2313 using value_type = remove_const_t<T>;
2315 if (!is_constant_evaluated()) {
2317 const_cast<char*
>(&
reinterpret_cast<const volatile char&
>(x));
2320 #if defined(__cpp_if_constexpr) 2321 if constexpr (std::is_same<decltype(&x), remove_reference_t<T>*>::value)
2322 custom.value =
const_cast<value_type*
>(&x);
2325 custom.format = format_custom<value_type>;
2328 template <
typename T, FMTQUILL_ENABLE_IF(!has_formatter<T,
char_type>())>
2329 FMTQUILL_CONSTEXPR value(
const T&,
custom_tag) {
2336 template <
typename T>
2341 using qualified_type =
2342 conditional_t<has_formatter<const T, char_type>(),
const T, T>;
2345 ctx.advance_to(cf.format(*static_cast<qualified_type*>(arg), ctx));
2349 enum { packed_arg_bits = 4 };
2351 enum { max_packed_args = 62 / packed_arg_bits };
2352 enum :
unsigned long long { is_unpacked_bit = 1ULL << 63 };
2353 enum :
unsigned long long { has_named_args_bit = 1ULL << 62 };
2355 template <
typename It,
typename T,
typename Enable =
void>
2360 template <
typename It,
typename T>
2363 enable_if_t<std::is_assignable<decltype(*std::declval<decay_t<It>&>()++),
2364 T>
::value>> : std::true_type {};
2366 template <
typename> constexpr
auto encode_types() ->
unsigned long long {
2370 template <
typename Context,
typename First,
typename... T>
2371 constexpr
auto encode_types() ->
unsigned long long {
2372 return static_cast<unsigned>(stored_type_constant<First, Context>::value) |
2373 (encode_types<Context, T...>() << packed_arg_bits);
2376 template <
typename Context,
typename... T,
size_t NUM_ARGS =
sizeof...(T)>
2377 constexpr
auto make_descriptor() ->
unsigned long long {
2378 return NUM_ARGS <= max_packed_args ? encode_types<Context, T...>()
2379 : is_unpacked_bit | NUM_ARGS;
2382 template <
typename Context,
int NUM_ARGS>
2383 using arg_t = conditional_t<NUM_ARGS <= max_packed_args, value<Context>,
2386 template <
typename Context,
int NUM_ARGS,
int NUM_NAMED_ARGS,
2387 unsigned long long DESC>
2390 arg_t<Context, NUM_ARGS> args[1u + NUM_ARGS];
2392 named_args[
static_cast<size_t>(NUM_NAMED_ARGS)];
2394 template <
typename... T>
2395 FMTQUILL_CONSTEXPR FMTQUILL_ALWAYS_INLINE
named_arg_store(T&... values)
2396 : args{{named_args, NUM_NAMED_ARGS}, values...} {
2397 int arg_index = 0, named_arg_index = 0;
2398 FMTQUILL_APPLY_VARIADIC(
2399 init_named_arg(named_args, arg_index, named_arg_index, values));
2402 named_arg_store(named_arg_store&& rhs) {
2403 args[0] = {named_args, NUM_NAMED_ARGS};
2404 for (
size_t i = 1; i <
sizeof(args) /
sizeof(*args); ++i)
2405 args[i] = rhs.args[i];
2406 for (
size_t i = 0; i < NUM_NAMED_ARGS; ++i)
2407 named_args[i] = rhs.named_args[i];
2410 named_arg_store(
const named_arg_store& rhs) =
delete;
2411 auto operator=(
const named_arg_store& rhs) -> named_arg_store& =
delete;
2412 auto operator=(named_arg_store&& rhs) -> named_arg_store& =
delete;
2413 operator const arg_t<Context, NUM_ARGS>*()
const {
return args + 1; }
2419 template <
typename Context,
int NUM_ARGS,
int NUM_NAMED_ARGS,
2420 unsigned long long DESC>
2424 conditional_t<NUM_NAMED_ARGS == 0,
2425 arg_t<Context, NUM_ARGS>[max_of<size_t>(1, NUM_ARGS)],
2436 using nonlocking = void;
2440 auto end = parse_format_specs(ctx.
begin(), ctx.
end(), specs_, ctx, TYPE);
2441 if (const_check(TYPE == type::char_type)) check_char_specs(specs_);
2445 template <type U = TYPE,
2446 FMTQUILL_ENABLE_IF(U == type::string_type || U == type::cstring_type ||
2447 U == type::char_type)>
2448 FMTQUILL_CONSTEXPR
void set_debug_format(
bool set =
true) {
2449 specs_.set_type(
set ? presentation_type::debug : presentation_type::none);
2452 FMTQUILL_PRAGMA_CLANG(diagnostic ignored
"-Wundefined-inline")
2453 template <
typename FormatContext>
2454 FMTQUILL_CONSTEXPR
auto format(
const T& val, FormatContext& ctx)
const 2455 -> decltype(ctx.out());
2458 template <
typename T,
typename Enable =
void>
2460 : bool_constant<mapped_type_constant<T>::value == type::custom_type> {};
2461 template <
typename T>
2463 : std::false_type {};
2465 template <
typename T =
int> FMTQUILL_CONSTEXPR
inline auto is_locking() ->
bool {
2468 template <
typename T1,
typename T2,
typename... Tail>
2469 FMTQUILL_CONSTEXPR
inline auto is_locking() ->
bool {
2478 #else // format_args is passed by reference since it is defined later. 2485 template <
typename Char>
2489 if (detail::is_constant_evaluated() && use_constexpr_cast) {
2491 if (arg_id >= ctx->num_args()) report_error(
"argument not found");
2495 template <
typename Char>
2498 if (detail::is_constant_evaluated() && use_constexpr_cast)
2502 FMTQUILL_BEGIN_EXPORT
2515 FMTQUILL_CONSTEXPR20
auto operator=(T c) -> basic_appender& {
2516 container->push_back(c);
2519 FMTQUILL_CONSTEXPR20
auto operator*() -> basic_appender& {
return *
this; }
2520 FMTQUILL_CONSTEXPR20
auto operator++() -> basic_appender& {
return *
this; }
2521 FMTQUILL_CONSTEXPR20
auto operator++(
int) -> basic_appender {
return *
this; }
2533 using char_type =
typename Context::char_type;
2544 custom_.format(custom_.value, parse_ctx, ctx);
2550 : value_(args, size) {}
2551 template <
typename T>
2552 basic_format_arg(T&& val)
2553 : value_(val), type_(detail::stored_type_constant<T, Context>::value) {}
2555 constexpr
explicit operator bool()
const noexcept {
2556 return type_ != detail::type::none_type;
2558 auto type()
const -> detail::type {
return type_; }
2565 template <
typename Visitor>
2566 FMTQUILL_CONSTEXPR FMTQUILL_INLINE
auto visit(Visitor&& vis)
const -> decltype(vis(0)) {
2569 case detail::type::none_type:
break;
2570 case detail::type::int_type:
return vis(value_.int_value);
2571 case detail::type::uint_type:
return vis(value_.uint_value);
2572 case detail::type::long_long_type:
return vis(value_.long_long_value);
2573 case detail::type::ulong_long_type:
return vis(value_.ulong_long_value);
2574 case detail::type::int128_type:
return vis(map(value_.int128_value));
2575 case detail::type::uint128_type:
return vis(map(value_.uint128_value));
2576 case detail::type::bool_type:
return vis(value_.bool_value);
2577 case detail::type::char_type:
return vis(value_.char_value);
2578 case detail::type::float_type:
return vis(value_.float_value);
2579 case detail::type::double_type:
return vis(value_.double_value);
2580 case detail::type::long_double_type:
return vis(value_.long_double_value);
2581 case detail::type::cstring_type:
return vis(value_.string.data);
2582 case detail::type::string_type:
return vis(value_.string.str());
2583 case detail::type::pointer_type:
return vis(value_.pointer);
2584 case detail::type::custom_type:
return vis(handle(value_.custom));
2589 auto format_custom(
const char_type* parse_begin,
2592 if (type_ != detail::type::custom_type)
return false;
2594 value_.custom.format(value_.custom.value, parse_ctx, ctx);
2613 unsigned long long desc_;
2624 constexpr
auto is_packed()
const ->
bool {
2625 return (desc_ & detail::is_unpacked_bit) == 0;
2627 constexpr
auto has_named_args()
const ->
bool {
2628 return (desc_ & detail::has_named_args_bit) != 0;
2631 FMTQUILL_CONSTEXPR
auto type(
int index)
const -> detail::type {
2632 int shift = index * detail::packed_arg_bits;
2633 unsigned mask = (1 << detail::packed_arg_bits) - 1;
2634 return static_cast<detail::type
>((desc_ >> shift) & mask);
2637 template <
int NUM_ARGS,
int NUM_NAMED_ARGS,
unsigned long long DESC>
2647 template <
int NUM_ARGS,
int NUM_NAMED_ARGS,
unsigned long long DESC,
2648 FMTQUILL_ENABLE_IF(NUM_ARGS <= detail::max_packed_args)>
2651 : desc_(DESC | (NUM_NAMED_ARGS != 0 ? +
detail::has_named_args_bit : 0)),
2654 template <
int NUM_ARGS,
int NUM_NAMED_ARGS,
unsigned long long DESC,
2655 FMTQUILL_ENABLE_IF(NUM_ARGS > detail::max_packed_args)>
2657 : desc_(DESC | (NUM_NAMED_ARGS != 0 ? +detail::has_named_args_bit : 0)),
2662 bool has_named =
false)
2663 : desc_(
detail::is_unpacked_bit |
detail::to_unsigned(count) |
2664 (has_named ? +
detail::has_named_args_bit : 0)),
2671 if (
id < max_size()) arg = args_[id];
2674 if (static_cast<unsigned>(
id) >= detail::max_packed_args)
return arg;
2675 arg.type_ = type(
id);
2676 if (arg.type_ != detail::type::none_type) arg.value_ = values_[id];
2680 template <
typename Char>
2682 int id = get_id(name);
2686 template <
typename Char>
2688 if (!has_named_args())
return -1;
2689 const auto& named_args =
2690 (is_packed() ? values_[-1] : args_[-1].value_).named_args;
2691 for (
size_t i = 0; i < named_args.size; ++i) {
2692 if (named_args.data[i].name == name)
return named_args.data[i].id;
2697 auto max_size()
const ->
int {
2698 unsigned long long max_packed = detail::max_packed_args;
2699 return static_cast<int>(is_packed() ? max_packed
2700 : desc_ & ~
detail::is_unpacked_bit);
2712 using char_type = char;
2715 enum { builtin_types = FMTQUILL_BUILTIN_TYPES };
2720 : out_(out), args_(args), loc_(loc) {}
2721 context(context&&) =
default;
2722 context(
const context&) =
delete;
2723 void operator=(
const context&) =
delete;
2725 FMTQUILL_CONSTEXPR
auto arg(
int id)
const ->
format_arg {
return args_.
get(
id); }
2727 return args_.
get(name);
2729 FMTQUILL_CONSTEXPR
auto arg_id(
string_view name)
const ->
int {
2730 return args_.get_id(name);
2732 auto args()
const ->
const format_args& {
return args_; }
2735 FMTQUILL_CONSTEXPR
auto out()
const ->
iterator {
return out_; }
2738 FMTQUILL_CONSTEXPR
void advance_to(
iterator) {}
2740 FMTQUILL_CONSTEXPR
auto locale()
const ->
locale_ref {
return loc_; }
2761 static constexpr
int num_static_named_args =
2762 detail::count_static_named_args<T...>();
2765 char,
static_cast<int>(
sizeof...(T)), num_static_named_args,
2766 num_static_named_args != detail::count_named_args<T...>()>;
2776 FMTQUILL_CONSTEVAL FMTQUILL_ALWAYS_INLINE
fstring(
const char (&s)[N]) : str(s, N - 1) {
2778 static_assert(count<(
is_view<remove_cvref_t<T>>::
value &&
2779 std::is_reference<T>::value)...>() == 0,
2780 "passing views as lvalues is disallowed");
2781 if (FMTQUILL_USE_CONSTEVAL) parse_format_string<char>(s,
checker(s,
arg_pack()));
2782 #ifdef FMTQUILL_ENFORCE_COMPILE_STRING 2784 FMTQUILL_USE_CONSTEVAL &&
sizeof(s) != 0,
2785 "FMTQUILL_ENFORCE_COMPILE_STRING requires format strings to use FMTQUILL_STRING");
2788 template <
typename S,
2789 FMTQUILL_ENABLE_IF(std::is_convertible<const S&, string_view>::value)>
2790 FMTQUILL_CONSTEVAL FMTQUILL_ALWAYS_INLINE fstring(
const S& s) : str(s) {
2792 if (FMTQUILL_USE_CONSTEVAL)
2794 #ifdef FMTQUILL_ENFORCE_COMPILE_STRING 2796 FMTQUILL_USE_CONSTEVAL &&
sizeof(s) != 0,
2797 "FMTQUILL_ENFORCE_COMPILE_STRING requires format strings to use FMTQUILL_STRING");
2800 template <
typename S,
2801 FMTQUILL_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
2802 std::is_same<typename S::char_type, char>::value)>
2803 FMTQUILL_ALWAYS_INLINE fstring(
const S&) : str(S()) {
2805 FMTQUILL_CONSTEXPR
int unused =
2807 detail::ignore_unused(unused);
2812 FMTQUILL_ALWAYS_INLINE
operator const string_view&()
const {
return str; }
2816 template <
typename... T>
using format_string =
typename fstring<T...>
::t;
2818 template <
typename T,
typename Char =
char>
2819 using is_formattable = bool_constant<!std::is_same<
2820 detail::mapped_t<conditional_t<std::is_void<T>::value,
int*, T>, Char>,
2822 #ifdef __cpp_concepts 2823 template <
typename T,
typename Char =
char>
2824 concept formattable = is_formattable<remove_reference_t<T>, Char>::value;
2828 template <
typename T,
typename Char>
2831 detail::type::custom_type>>
2842 template <
typename Context = context,
typename... T,
2843 int NUM_ARGS =
sizeof...(T),
2844 int NUM_NAMED_ARGS = detail::count_named_args<T...>(),
2845 unsigned long long DESC = detail::make_descriptor<Context, T...>()>
2846 constexpr FMTQUILL_ALWAYS_INLINE
auto make_format_args(T&... args)
2849 FMTQUILL_PRAGMA_GCC(diagnostic ignored
"-Wconversion")
2853 template <
typename... T>
2856 detail::count_named_args<T...>(),
2857 detail::make_descriptor<context, T...>()>;
2867 template <
typename Char,
typename T>
2873 template <
typename OutputIt,
2877 -> remove_cvref_t<OutputIt> {
2878 auto&& buf = detail::get_buffer<char>(out);
2879 detail::vformat_to(buf, fmt, args, {});
2880 return detail::get_iterator(buf, out);
2893 template <
typename OutputIt,
typename... T,
2896 FMTQUILL_INLINE
auto format_to(OutputIt&& out, format_string<T...> fmt, T&&... args)
2897 -> remove_cvref_t<OutputIt> {
2898 return vformat_to(out, fmt.str,
vargs<T...>{{args...}});
2908 template <
typename OutputIt,
typename... T,
2914 detail::vformat_to(buf, fmt, args, {});
2915 return {buf.out(), buf.count()};
2924 template <
typename OutputIt,
typename... T,
2926 FMTQUILL_INLINE
auto format_to_n(OutputIt out,
size_t n, format_string<T...> fmt,
2928 return vformat_to_n(out, n, fmt.str,
vargs<T...>{{args...}});
2937 FMTQUILL_CONSTEXPR
operator char*()
const {
2939 if (truncated) report_error(
"output is truncated");
2947 auto result = vformat_to_n(out, N, fmt, args);
2948 return {result.out, result.size > N};
2951 template <
size_t N,
typename... T>
2952 FMTQUILL_INLINE
auto format_to(
char (&out)[N], format_string<T...> fmt, T&&... args)
2954 auto result = vformat_to_n(out, N, fmt.str,
vargs<T...>{{args...}});
2955 return {result.out, result.size > N};
2959 template <
typename... T>
2960 FMTQUILL_NODISCARD FMTQUILL_INLINE
auto formatted_size(format_string<T...> fmt,
2961 T&&... args) ->
size_t {
2963 detail::vformat_to(buf, fmt.str,
vargs<T...>{{args...}}, {});
2980 template <
typename... T>
2981 FMTQUILL_INLINE
void print(format_string<T...> fmt, T&&... args) {
2982 vargs<T...> va = {{args...}};
2983 if (detail::const_check(!detail::use_utf8))
2984 return detail::vprint_mojibake(stdout, fmt.str, va,
false);
2985 return detail::is_locking<T...>() ? vprint_buffered(stdout, fmt.str, va)
2986 : vprint(fmt.str, va);
2997 template <
typename... T>
2998 FMTQUILL_INLINE
void print(FILE* f, format_string<T...> fmt, T&&... args) {
2999 vargs<T...> va = {{args...}};
3000 if (detail::const_check(!detail::use_utf8))
3001 return detail::vprint_mojibake(f, fmt.str, va,
false);
3002 return detail::is_locking<T...>() ? vprint_buffered(f, fmt.str, va)
3003 : vprint(f, fmt.str, va);
3008 template <
typename... T>
3009 FMTQUILL_INLINE
void println(FILE* f, format_string<T...> fmt, T&&... args) {
3010 vargs<T...> va = {{args...}};
3011 return detail::const_check(detail::use_utf8)
3012 ? vprintln(f, fmt.str, va)
3013 : detail::vprint_mojibake(f, fmt.str, va,
true);
3018 template <
typename... T>
3019 FMTQUILL_INLINE
void println(format_string<T...> fmt, T&&... args) {
3020 return fmtquill::println(stdout, fmt, static_cast<T&&>(args)...);
3023 FMTQUILL_PRAGMA_GCC(diagnostic pop)
3024 FMTQUILL_PRAGMA_CLANG(diagnostic pop)
3025 FMTQUILL_PRAGMA_GCC(pop_options)
3026 FMTQUILL_MSC_WARNING(pop)
3028 FMTQUILL_END_NAMESPACE
3030 #endif // FMTQUILL_BASE_H_
FMTQUILL_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition: base.h:1827
A compile-time format string.
Definition: base.h:2759
FMTQUILL_CONSTEXPR context(iterator out, format_args args, locale_ref loc={})
Constructs a context object.
Definition: base.h:2719
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition: base.h:636
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:906
FMTQUILL_CONSTEXPR20 basic_string_view(const Char *s)
Constructs a string view object from a C string.
Definition: base.h:549
FMTQUILL_CONSTEXPR20 void append(const U *begin, const U *end)
Appends data to the end of the buffer.
Definition: base.h:1861
Definition: LogFunctions.h:185
constexpr auto data() const noexcept -> const Char *
Returns a pointer to the string data.
Definition: base.h:570
FMTQUILL_CONSTEXPR void advance_to(iterator it)
Advances the begin iterator to it.
Definition: base.h:888
constexpr auto size() const noexcept -> size_t
Returns the string size.
Definition: base.h:573
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:894
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:28
An implementation of std::basic_string_view for pre-C++17.
Definition: base.h:528
FMTQUILL_CONSTEXPR void clear()
Clears this buffer.
Definition: base.h:1831
constexpr auto end() const noexcept -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition: base.h:885
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition: base.h:1821
typename V::value_type char_t
String's character (code unit) type. detail:: is intentional to prevent ADL.
Definition: base.h:989
constexpr auto capacity() const noexcept -> size_t
Returns the capacity of this buffer.
Definition: base.h:1824
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:540
constexpr auto begin() const noexcept -> iterator
Returns an iterator to the beginning of the format string range being parsed.
Definition: base.h:882
This example shows deferred formatting for a user-defined type while sharing formatting customisation...
Definition: user_defined_types_logging_deferred_format_as.cpp:30
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:566
A contiguous memory buffer with an optional growing ability.
Definition: base.h:1779