File indexing completed on 2026-05-03 08:13:50
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef _LIBCPP___FORMAT_PARSER_STD_FORMAT_SPEC_H
0011 #define _LIBCPP___FORMAT_PARSER_STD_FORMAT_SPEC_H
0012
0013
0014
0015
0016
0017
0018
0019 #include <__algorithm/copy_n.h>
0020 #include <__algorithm/min.h>
0021 #include <__assert>
0022 #include <__concepts/arithmetic.h>
0023 #include <__concepts/same_as.h>
0024 #include <__config>
0025 #include <__format/format_arg.h>
0026 #include <__format/format_error.h>
0027 #include <__format/format_parse_context.h>
0028 #include <__format/format_string.h>
0029 #include <__format/unicode.h>
0030 #include <__format/width_estimation_table.h>
0031 #include <__iterator/concepts.h>
0032 #include <__iterator/iterator_traits.h> // iter_value_t
0033 #include <__memory/addressof.h>
0034 #include <__type_traits/common_type.h>
0035 #include <__type_traits/is_constant_evaluated.h>
0036 #include <__type_traits/is_trivially_copyable.h>
0037 #include <__variant/monostate.h>
0038 #include <cstdint>
0039 #include <string>
0040 #include <string_view>
0041
0042 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0043 # pragma GCC system_header
0044 #endif
0045
0046 _LIBCPP_PUSH_MACROS
0047 #include <__undef_macros>
0048
0049 _LIBCPP_BEGIN_NAMESPACE_STD
0050
0051 #if _LIBCPP_STD_VER >= 20
0052
0053 namespace __format_spec {
0054
0055 [[noreturn]] _LIBCPP_HIDE_FROM_ABI inline void
0056 __throw_invalid_option_format_error(const char* __id, const char* __option) {
0057 std::__throw_format_error(
0058 (string("The format specifier for ") + __id + " does not allow the " + __option + " option").c_str());
0059 }
0060
0061 [[noreturn]] _LIBCPP_HIDE_FROM_ABI inline void __throw_invalid_type_format_error(const char* __id) {
0062 std::__throw_format_error(
0063 (string("The type option contains an invalid value for ") + __id + " formatting argument").c_str());
0064 }
0065
0066 template <contiguous_iterator _Iterator, class _ParseContext>
0067 _LIBCPP_HIDE_FROM_ABI constexpr __format::__parse_number_result<_Iterator>
0068 __parse_arg_id(_Iterator __begin, _Iterator __end, _ParseContext& __ctx) {
0069 using _CharT = iter_value_t<_Iterator>;
0070
0071
0072 if (__begin == __end)
0073 std::__throw_format_error("End of input while parsing an argument index");
0074
0075 __format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __ctx);
0076
0077 if (__r.__last == __end || *__r.__last != _CharT('}'))
0078 std::__throw_format_error("The argument index is invalid");
0079
0080 ++__r.__last;
0081 return __r;
0082 }
0083
0084 template <class _Context>
0085 _LIBCPP_HIDE_FROM_ABI constexpr uint32_t __substitute_arg_id(basic_format_arg<_Context> __format_arg) {
0086
0087
0088
0089
0090
0091
0092
0093
0094 return std::__visit_format_arg(
0095 [](auto __arg) -> uint32_t {
0096 using _Type = decltype(__arg);
0097 if constexpr (same_as<_Type, monostate>)
0098 std::__throw_format_error("The argument index value is too large for the number of arguments supplied");
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110 if constexpr (same_as<_Type, int> || same_as<_Type, unsigned int> ||
0111 same_as<_Type, long long> || same_as<_Type, unsigned long long>) {
0112 if constexpr (signed_integral<_Type>) {
0113 if (__arg < 0)
0114 std::__throw_format_error("An argument index may not have a negative value");
0115 }
0116
0117 using _CT = common_type_t<_Type, decltype(__format::__number_max)>;
0118 if (static_cast<_CT>(__arg) > static_cast<_CT>(__format::__number_max))
0119 std::__throw_format_error("The value of the argument index exceeds its maximum value");
0120
0121 return __arg;
0122 } else
0123 std::__throw_format_error("Replacement argument isn't a standard signed or unsigned integer type");
0124 },
0125 __format_arg);
0126 }
0127
0128
0129
0130
0131
0132 struct _LIBCPP_HIDE_FROM_ABI __fields {
0133 uint16_t __sign_ : 1 {false};
0134 uint16_t __alternate_form_ : 1 {false};
0135 uint16_t __zero_padding_ : 1 {false};
0136 uint16_t __precision_ : 1 {false};
0137 uint16_t __locale_specific_form_ : 1 {false};
0138 uint16_t __type_ : 1 {false};
0139
0140
0141
0142
0143
0144
0145 uint16_t __use_range_fill_ : 1 {false};
0146 uint16_t __clear_brackets_ : 1 {false};
0147 uint16_t __consume_all_ : 1 {false};
0148 };
0149
0150
0151
0152 inline constexpr __fields __fields_bool{.__locale_specific_form_ = true, .__type_ = true, .__consume_all_ = true};
0153 inline constexpr __fields __fields_integral{
0154 .__sign_ = true,
0155 .__alternate_form_ = true,
0156 .__zero_padding_ = true,
0157 .__locale_specific_form_ = true,
0158 .__type_ = true,
0159 .__consume_all_ = true};
0160 inline constexpr __fields __fields_floating_point{
0161 .__sign_ = true,
0162 .__alternate_form_ = true,
0163 .__zero_padding_ = true,
0164 .__precision_ = true,
0165 .__locale_specific_form_ = true,
0166 .__type_ = true,
0167 .__consume_all_ = true};
0168 inline constexpr __fields __fields_string{.__precision_ = true, .__type_ = true, .__consume_all_ = true};
0169 inline constexpr __fields __fields_pointer{.__zero_padding_ = true, .__type_ = true, .__consume_all_ = true};
0170
0171 # if _LIBCPP_STD_VER >= 23
0172 inline constexpr __fields __fields_tuple{.__use_range_fill_ = true, .__clear_brackets_ = true};
0173 inline constexpr __fields __fields_range{.__use_range_fill_ = true, .__clear_brackets_ = true};
0174 inline constexpr __fields __fields_fill_align_width{};
0175 # endif
0176
0177 enum class __alignment : uint8_t {
0178
0179 __default,
0180 __left,
0181 __center,
0182 __right,
0183 __zero_padding
0184 };
0185
0186 enum class __sign : uint8_t {
0187
0188
0189
0190
0191
0192 __default,
0193 __minus,
0194 __plus,
0195 __space
0196 };
0197
0198 enum class __type : uint8_t {
0199 __default = 0,
0200 __string,
0201 __binary_lower_case,
0202 __binary_upper_case,
0203 __octal,
0204 __decimal,
0205 __hexadecimal_lower_case,
0206 __hexadecimal_upper_case,
0207 __pointer_lower_case,
0208 __pointer_upper_case,
0209 __char,
0210 __hexfloat_lower_case,
0211 __hexfloat_upper_case,
0212 __scientific_lower_case,
0213 __scientific_upper_case,
0214 __fixed_lower_case,
0215 __fixed_upper_case,
0216 __general_lower_case,
0217 __general_upper_case,
0218 __debug
0219 };
0220
0221 _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __create_type_mask(__type __t) {
0222 uint32_t __shift = static_cast<uint32_t>(__t);
0223 if (__shift == 0)
0224 return 1;
0225
0226 if (__shift > 31)
0227 std::__throw_format_error("The type does not fit in the mask");
0228
0229 return 1 << __shift;
0230 }
0231
0232 inline constexpr uint32_t __type_mask_integer =
0233 __create_type_mask(__type::__binary_lower_case) |
0234 __create_type_mask(__type::__binary_upper_case) |
0235 __create_type_mask(__type::__decimal) |
0236 __create_type_mask(__type::__octal) |
0237 __create_type_mask(__type::__hexadecimal_lower_case) |
0238 __create_type_mask(__type::__hexadecimal_upper_case);
0239
0240 struct __std {
0241 __alignment __alignment_ : 3;
0242 __sign __sign_ : 2;
0243 bool __alternate_form_ : 1;
0244 bool __locale_specific_form_ : 1;
0245 __type __type_;
0246 };
0247
0248 struct __chrono {
0249 __alignment __alignment_ : 3;
0250 bool __locale_specific_form_ : 1;
0251 bool __hour_ : 1;
0252 bool __weekday_name_ : 1;
0253 bool __weekday_ : 1;
0254 bool __day_of_year_ : 1;
0255 bool __week_of_year_ : 1;
0256 bool __month_name_ : 1;
0257 };
0258
0259
0260
0261
0262
0263 template <class _CharT>
0264 struct __code_point;
0265
0266 template <>
0267 struct __code_point<char> {
0268 char __data[4] = {' '};
0269 };
0270
0271 # if _LIBCPP_HAS_WIDE_CHARACTERS
0272 template <>
0273 struct __code_point<wchar_t> {
0274 wchar_t __data[4 / sizeof(wchar_t)] = {L' '};
0275 };
0276 # endif
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287 template <class _CharT>
0288 struct __parsed_specifications {
0289 union {
0290
0291
0292
0293
0294
0295
0296 __alignment __alignment_ : 3;
0297 __std __std_;
0298 __chrono __chrono_;
0299 };
0300
0301
0302
0303
0304
0305 int32_t __width_;
0306
0307
0308
0309
0310
0311 int32_t __precision_;
0312
0313 __code_point<_CharT> __fill_;
0314
0315 _LIBCPP_HIDE_FROM_ABI constexpr bool __has_width() const { return __width_ > 0; }
0316
0317 _LIBCPP_HIDE_FROM_ABI constexpr bool __has_precision() const { return __precision_ >= 0; }
0318 };
0319
0320
0321
0322 static_assert(sizeof(__parsed_specifications<char>) == 16);
0323 static_assert(is_trivially_copyable_v<__parsed_specifications<char>>);
0324 # if _LIBCPP_HAS_WIDE_CHARACTERS
0325 static_assert(sizeof(__parsed_specifications<wchar_t>) == 16);
0326 static_assert(is_trivially_copyable_v<__parsed_specifications<wchar_t>>);
0327 # endif
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337 template <class _CharT>
0338 class _LIBCPP_TEMPLATE_VIS __parser {
0339 public:
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353 template <class _ParseContext>
0354 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator __parse(_ParseContext& __ctx, __fields __fields) {
0355 auto __begin = __ctx.begin();
0356 auto __end = __ctx.end();
0357 if (__begin == __end || *__begin == _CharT('}') || (__fields.__use_range_fill_ && *__begin == _CharT(':')))
0358 return __begin;
0359
0360 if (__parse_fill_align(__begin, __end) && __begin == __end)
0361 return __begin;
0362
0363 if (__fields.__sign_) {
0364 if (__parse_sign(__begin) && __begin == __end)
0365 return __begin;
0366 } else if (std::is_constant_evaluated() && __parse_sign(__begin)) {
0367 std::__throw_format_error("The format specification does not allow the sign option");
0368 }
0369
0370 if (__fields.__alternate_form_) {
0371 if (__parse_alternate_form(__begin) && __begin == __end)
0372 return __begin;
0373 } else if (std::is_constant_evaluated() && __parse_alternate_form(__begin)) {
0374 std::__throw_format_error("The format specifier does not allow the alternate form option");
0375 }
0376
0377 if (__fields.__zero_padding_) {
0378 if (__parse_zero_padding(__begin) && __begin == __end)
0379 return __begin;
0380 } else if (std::is_constant_evaluated() && __parse_zero_padding(__begin)) {
0381 std::__throw_format_error("The format specifier does not allow the zero-padding option");
0382 }
0383
0384 if (__parse_width(__begin, __end, __ctx) && __begin == __end)
0385 return __begin;
0386
0387 if (__fields.__precision_) {
0388 if (__parse_precision(__begin, __end, __ctx) && __begin == __end)
0389 return __begin;
0390 } else if (std::is_constant_evaluated() && __parse_precision(__begin, __end, __ctx)) {
0391 std::__throw_format_error("The format specifier does not allow the precision option");
0392 }
0393
0394 if (__fields.__locale_specific_form_) {
0395 if (__parse_locale_specific_form(__begin) && __begin == __end)
0396 return __begin;
0397 } else if (std::is_constant_evaluated() && __parse_locale_specific_form(__begin)) {
0398 std::__throw_format_error("The format specifier does not allow the locale-specific form option");
0399 }
0400
0401 if (__fields.__clear_brackets_) {
0402 if (__parse_clear_brackets(__begin) && __begin == __end)
0403 return __begin;
0404 } else if (std::is_constant_evaluated() && __parse_clear_brackets(__begin)) {
0405 std::__throw_format_error("The format specifier does not allow the n option");
0406 }
0407
0408 if (__fields.__type_)
0409 __parse_type(__begin);
0410
0411 if (!__fields.__consume_all_)
0412 return __begin;
0413
0414 if (__begin != __end && *__begin != _CharT('}'))
0415 std::__throw_format_error("The format specifier should consume the input or end with a '}'");
0416
0417 return __begin;
0418 }
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450 _LIBCPP_HIDE_FROM_ABI constexpr void
0451 __validate(__fields __fields, const char* __id, uint32_t __type_mask = -1) const {
0452 if (!__fields.__sign_ && __sign_ != __sign::__default) {
0453 if (std::is_constant_evaluated())
0454 std::__throw_format_error("The format specifier does not allow the sign option");
0455 else
0456 __format_spec::__throw_invalid_option_format_error(__id, "sign");
0457 }
0458
0459 if (!__fields.__alternate_form_ && __alternate_form_) {
0460 if (std::is_constant_evaluated())
0461 std::__throw_format_error("The format specifier does not allow the alternate form option");
0462 else
0463 __format_spec::__throw_invalid_option_format_error(__id, "alternate form");
0464 }
0465
0466 if (!__fields.__zero_padding_ && __alignment_ == __alignment::__zero_padding) {
0467 if (std::is_constant_evaluated())
0468 std::__throw_format_error("The format specifier does not allow the zero-padding option");
0469 else
0470 __format_spec::__throw_invalid_option_format_error(__id, "zero-padding");
0471 }
0472
0473 if (!__fields.__precision_ && __precision_ != -1) {
0474 if (std::is_constant_evaluated())
0475 std::__throw_format_error("The format specifier does not allow the precision option");
0476 else
0477 __format_spec::__throw_invalid_option_format_error(__id, "precision");
0478 }
0479
0480 if (!__fields.__locale_specific_form_ && __locale_specific_form_) {
0481 if (std::is_constant_evaluated())
0482 std::__throw_format_error("The format specifier does not allow the locale-specific form option");
0483 else
0484 __format_spec::__throw_invalid_option_format_error(__id, "locale-specific form");
0485 }
0486
0487 if ((__create_type_mask(__type_) & __type_mask) == 0) {
0488 if (std::is_constant_evaluated())
0489 std::__throw_format_error("The format specifier uses an invalid value for the type option");
0490 else
0491 __format_spec::__throw_invalid_type_format_error(__id);
0492 }
0493 }
0494
0495
0496 _LIBCPP_HIDE_FROM_ABI __parsed_specifications<_CharT> __get_parsed_std_specifications(auto& __ctx) const {
0497 return __parsed_specifications<_CharT>{
0498 .__std_ = __std{.__alignment_ = __alignment_,
0499 .__sign_ = __sign_,
0500 .__alternate_form_ = __alternate_form_,
0501 .__locale_specific_form_ = __locale_specific_form_,
0502 .__type_ = __type_},
0503 .__width_{__get_width(__ctx)},
0504 .__precision_{__get_precision(__ctx)},
0505 .__fill_{__fill_}};
0506 }
0507
0508 _LIBCPP_HIDE_FROM_ABI __parsed_specifications<_CharT> __get_parsed_chrono_specifications(auto& __ctx) const {
0509 return __parsed_specifications<_CharT>{
0510 .__chrono_ =
0511 __chrono{.__alignment_ = __alignment_,
0512 .__locale_specific_form_ = __locale_specific_form_,
0513 .__hour_ = __hour_,
0514 .__weekday_name_ = __weekday_name_,
0515 .__weekday_ = __weekday_,
0516 .__day_of_year_ = __day_of_year_,
0517 .__week_of_year_ = __week_of_year_,
0518 .__month_name_ = __month_name_},
0519 .__width_{__get_width(__ctx)},
0520 .__precision_{__get_precision(__ctx)},
0521 .__fill_{__fill_}};
0522 }
0523
0524 __alignment __alignment_ : 3 {__alignment::__default};
0525 __sign __sign_ : 2 {__sign::__default};
0526 bool __alternate_form_ : 1 {false};
0527 bool __locale_specific_form_ : 1 {false};
0528 bool __clear_brackets_ : 1 {false};
0529 __type __type_{__type::__default};
0530
0531
0532
0533 bool __hour_ : 1 {false};
0534
0535 bool __weekday_name_ : 1 {false};
0536 bool __weekday_ : 1 {false};
0537
0538 bool __day_of_year_ : 1 {false};
0539 bool __week_of_year_ : 1 {false};
0540
0541 bool __month_name_ : 1 {false};
0542
0543 uint8_t __reserved_0_ : 2 {0};
0544 uint8_t __reserved_1_ : 6 {0};
0545
0546
0547 bool __width_as_arg_ : 1 {false};
0548 bool __precision_as_arg_ : 1 {false};
0549
0550
0551 int32_t __width_{0};
0552
0553
0554 int32_t __precision_{-1};
0555
0556 __code_point<_CharT> __fill_{};
0557
0558 private:
0559 _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_alignment(_CharT __c) {
0560 switch (__c) {
0561 case _CharT('<'):
0562 __alignment_ = __alignment::__left;
0563 return true;
0564
0565 case _CharT('^'):
0566 __alignment_ = __alignment::__center;
0567 return true;
0568
0569 case _CharT('>'):
0570 __alignment_ = __alignment::__right;
0571 return true;
0572 }
0573 return false;
0574 }
0575
0576 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_fill_character(_CharT __fill) {
0577
0578
0579 if (__fill == _CharT('{'))
0580 std::__throw_format_error("The fill option contains an invalid value");
0581 }
0582
0583 # if _LIBCPP_HAS_UNICODE
0584
0585 template <contiguous_iterator _Iterator>
0586 requires same_as<_CharT, char>
0587 # if _LIBCPP_HAS_WIDE_CHARACTERS
0588 || (same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2)
0589 # endif
0590 _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) {
0591 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0592 __begin != __end,
0593 "when called with an empty input the function will cause "
0594 "undefined behavior by evaluating data not in the input");
0595 __unicode::__code_point_view<_CharT> __view{__begin, __end};
0596 __unicode::__consume_result __consumed = __view.__consume();
0597 if (__consumed.__status != __unicode::__consume_result::__ok)
0598 std::__throw_format_error("The format specifier contains malformed Unicode characters");
0599
0600 if (__view.__position() < __end && __parse_alignment(*__view.__position())) {
0601 ptrdiff_t __code_units = __view.__position() - __begin;
0602 if (__code_units == 1)
0603
0604
0605
0606 __validate_fill_character(*__begin);
0607
0608 std::copy_n(__begin, __code_units, std::addressof(__fill_.__data[0]));
0609 __begin += __code_units + 1;
0610 return true;
0611 }
0612
0613 if (!__parse_alignment(*__begin))
0614 return false;
0615
0616 ++__begin;
0617 return true;
0618 }
0619
0620 # if _LIBCPP_HAS_WIDE_CHARACTERS
0621 template <contiguous_iterator _Iterator>
0622 requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4)
0623 _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) {
0624 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0625 __begin != __end,
0626 "when called with an empty input the function will cause "
0627 "undefined behavior by evaluating data not in the input");
0628 if (__begin + 1 != __end && __parse_alignment(*(__begin + 1))) {
0629 if (!__unicode::__is_scalar_value(*__begin))
0630 std::__throw_format_error("The fill option contains an invalid value");
0631
0632 __validate_fill_character(*__begin);
0633
0634 __fill_.__data[0] = *__begin;
0635 __begin += 2;
0636 return true;
0637 }
0638
0639 if (!__parse_alignment(*__begin))
0640 return false;
0641
0642 ++__begin;
0643 return true;
0644 }
0645
0646 # endif
0647
0648 # else
0649
0650 template <contiguous_iterator _Iterator>
0651 _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) {
0652 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0653 __begin != __end,
0654 "when called with an empty input the function will cause "
0655 "undefined behavior by evaluating data not in the input");
0656 if (__begin + 1 != __end) {
0657 if (__parse_alignment(*(__begin + 1))) {
0658 __validate_fill_character(*__begin);
0659
0660 __fill_.__data[0] = *__begin;
0661 __begin += 2;
0662 return true;
0663 }
0664 }
0665
0666 if (!__parse_alignment(*__begin))
0667 return false;
0668
0669 ++__begin;
0670 return true;
0671 }
0672
0673 # endif
0674
0675 template <contiguous_iterator _Iterator>
0676 _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_sign(_Iterator& __begin) {
0677 switch (*__begin) {
0678 case _CharT('-'):
0679 __sign_ = __sign::__minus;
0680 break;
0681 case _CharT('+'):
0682 __sign_ = __sign::__plus;
0683 break;
0684 case _CharT(' '):
0685 __sign_ = __sign::__space;
0686 break;
0687 default:
0688 return false;
0689 }
0690 ++__begin;
0691 return true;
0692 }
0693
0694 template <contiguous_iterator _Iterator>
0695 _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_alternate_form(_Iterator& __begin) {
0696 if (*__begin != _CharT('#'))
0697 return false;
0698
0699 __alternate_form_ = true;
0700 ++__begin;
0701 return true;
0702 }
0703
0704 template <contiguous_iterator _Iterator>
0705 _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_zero_padding(_Iterator& __begin) {
0706 if (*__begin != _CharT('0'))
0707 return false;
0708
0709 if (__alignment_ == __alignment::__default)
0710 __alignment_ = __alignment::__zero_padding;
0711 ++__begin;
0712 return true;
0713 }
0714
0715 template <contiguous_iterator _Iterator>
0716 _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_width(_Iterator& __begin, _Iterator __end, auto& __ctx) {
0717 if (*__begin == _CharT('0'))
0718 std::__throw_format_error("The width option should not have a leading zero");
0719
0720 if (*__begin == _CharT('{')) {
0721 __format::__parse_number_result __r = __format_spec::__parse_arg_id(++__begin, __end, __ctx);
0722 __width_as_arg_ = true;
0723 __width_ = __r.__value;
0724 __begin = __r.__last;
0725 return true;
0726 }
0727
0728 if (*__begin < _CharT('0') || *__begin > _CharT('9'))
0729 return false;
0730
0731 __format::__parse_number_result __r = __format::__parse_number(__begin, __end);
0732 __width_ = __r.__value;
0733 _LIBCPP_ASSERT_INTERNAL(__width_ != 0,
0734 "A zero value isn't allowed and should be impossible, "
0735 "due to validations in this function");
0736 __begin = __r.__last;
0737 return true;
0738 }
0739
0740 template <contiguous_iterator _Iterator>
0741 _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_precision(_Iterator& __begin, _Iterator __end, auto& __ctx) {
0742 if (*__begin != _CharT('.'))
0743 return false;
0744
0745 ++__begin;
0746 if (__begin == __end)
0747 std::__throw_format_error("End of input while parsing format specifier precision");
0748
0749 if (*__begin == _CharT('{')) {
0750 __format::__parse_number_result __arg_id = __format_spec::__parse_arg_id(++__begin, __end, __ctx);
0751 __precision_as_arg_ = true;
0752 __precision_ = __arg_id.__value;
0753 __begin = __arg_id.__last;
0754 return true;
0755 }
0756
0757 if (*__begin < _CharT('0') || *__begin > _CharT('9'))
0758 std::__throw_format_error("The precision option does not contain a value or an argument index");
0759
0760 __format::__parse_number_result __r = __format::__parse_number(__begin, __end);
0761 __precision_ = __r.__value;
0762 __precision_as_arg_ = false;
0763 __begin = __r.__last;
0764 return true;
0765 }
0766
0767 template <contiguous_iterator _Iterator>
0768 _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_locale_specific_form(_Iterator& __begin) {
0769 if (*__begin != _CharT('L'))
0770 return false;
0771
0772 __locale_specific_form_ = true;
0773 ++__begin;
0774 return true;
0775 }
0776
0777 template <contiguous_iterator _Iterator>
0778 _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_clear_brackets(_Iterator& __begin) {
0779 if (*__begin != _CharT('n'))
0780 return false;
0781
0782 __clear_brackets_ = true;
0783 ++__begin;
0784 return true;
0785 }
0786
0787 template <contiguous_iterator _Iterator>
0788 _LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(_Iterator& __begin) {
0789
0790
0791
0792
0793
0794 switch (*__begin) {
0795 case 'A':
0796 __type_ = __type::__hexfloat_upper_case;
0797 break;
0798 case 'B':
0799 __type_ = __type::__binary_upper_case;
0800 break;
0801 case 'E':
0802 __type_ = __type::__scientific_upper_case;
0803 break;
0804 case 'F':
0805 __type_ = __type::__fixed_upper_case;
0806 break;
0807 case 'G':
0808 __type_ = __type::__general_upper_case;
0809 break;
0810 case 'X':
0811 __type_ = __type::__hexadecimal_upper_case;
0812 break;
0813 case 'a':
0814 __type_ = __type::__hexfloat_lower_case;
0815 break;
0816 case 'b':
0817 __type_ = __type::__binary_lower_case;
0818 break;
0819 case 'c':
0820 __type_ = __type::__char;
0821 break;
0822 case 'd':
0823 __type_ = __type::__decimal;
0824 break;
0825 case 'e':
0826 __type_ = __type::__scientific_lower_case;
0827 break;
0828 case 'f':
0829 __type_ = __type::__fixed_lower_case;
0830 break;
0831 case 'g':
0832 __type_ = __type::__general_lower_case;
0833 break;
0834 case 'o':
0835 __type_ = __type::__octal;
0836 break;
0837 case 'p':
0838 __type_ = __type::__pointer_lower_case;
0839 break;
0840 case 'P':
0841 __type_ = __type::__pointer_upper_case;
0842 break;
0843 case 's':
0844 __type_ = __type::__string;
0845 break;
0846 case 'x':
0847 __type_ = __type::__hexadecimal_lower_case;
0848 break;
0849 # if _LIBCPP_STD_VER >= 23
0850 case '?':
0851 __type_ = __type::__debug;
0852 break;
0853 # endif
0854 default:
0855 return;
0856 }
0857 ++__begin;
0858 }
0859
0860 _LIBCPP_HIDE_FROM_ABI int32_t __get_width(auto& __ctx) const {
0861 if (!__width_as_arg_)
0862 return __width_;
0863
0864 return __format_spec::__substitute_arg_id(__ctx.arg(__width_));
0865 }
0866
0867 _LIBCPP_HIDE_FROM_ABI int32_t __get_precision(auto& __ctx) const {
0868 if (!__precision_as_arg_)
0869 return __precision_;
0870
0871 return __format_spec::__substitute_arg_id(__ctx.arg(__precision_));
0872 }
0873 };
0874
0875
0876 static_assert(sizeof(__parser<char>) == 16);
0877 # if _LIBCPP_HAS_WIDE_CHARACTERS
0878 static_assert(sizeof(__parser<wchar_t>) == 16);
0879 # endif
0880
0881 _LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_string(__format_spec::__type __type) {
0882 switch (__type) {
0883 case __format_spec::__type::__default:
0884 case __format_spec::__type::__string:
0885 case __format_spec::__type::__debug:
0886 break;
0887
0888 default:
0889 std::__throw_format_error("The type option contains an invalid value for a string formatting argument");
0890 }
0891 }
0892
0893 template <class _CharT>
0894 _LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_bool_string(__parser<_CharT>& __parser, const char* __id) {
0895 __parser.__validate(__format_spec::__fields_bool, __id);
0896 if (__parser.__alignment_ == __alignment::__default)
0897 __parser.__alignment_ = __alignment::__left;
0898 }
0899
0900 template <class _CharT>
0901 _LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_char(__parser<_CharT>& __parser, const char* __id) {
0902 __format_spec::__process_display_type_bool_string(__parser, __id);
0903 }
0904
0905 template <class _CharT>
0906 _LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_bool(__parser<_CharT>& __parser, const char* __id) {
0907 switch (__parser.__type_) {
0908 case __format_spec::__type::__default:
0909 case __format_spec::__type::__string:
0910 __format_spec::__process_display_type_bool_string(__parser, __id);
0911 break;
0912
0913 case __format_spec::__type::__binary_lower_case:
0914 case __format_spec::__type::__binary_upper_case:
0915 case __format_spec::__type::__octal:
0916 case __format_spec::__type::__decimal:
0917 case __format_spec::__type::__hexadecimal_lower_case:
0918 case __format_spec::__type::__hexadecimal_upper_case:
0919 break;
0920
0921 default:
0922 __format_spec::__throw_invalid_type_format_error(__id);
0923 }
0924 }
0925
0926 template <class _CharT>
0927 _LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_char(__parser<_CharT>& __parser, const char* __id) {
0928 switch (__parser.__type_) {
0929 case __format_spec::__type::__default:
0930 case __format_spec::__type::__char:
0931 case __format_spec::__type::__debug:
0932 __format_spec::__process_display_type_char(__parser, __id);
0933 break;
0934
0935 case __format_spec::__type::__binary_lower_case:
0936 case __format_spec::__type::__binary_upper_case:
0937 case __format_spec::__type::__octal:
0938 case __format_spec::__type::__decimal:
0939 case __format_spec::__type::__hexadecimal_lower_case:
0940 case __format_spec::__type::__hexadecimal_upper_case:
0941 break;
0942
0943 default:
0944 __format_spec::__throw_invalid_type_format_error(__id);
0945 }
0946 }
0947
0948 template <class _CharT>
0949 _LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_integer(__parser<_CharT>& __parser, const char* __id) {
0950 switch (__parser.__type_) {
0951 case __format_spec::__type::__default:
0952 case __format_spec::__type::__binary_lower_case:
0953 case __format_spec::__type::__binary_upper_case:
0954 case __format_spec::__type::__octal:
0955 case __format_spec::__type::__decimal:
0956 case __format_spec::__type::__hexadecimal_lower_case:
0957 case __format_spec::__type::__hexadecimal_upper_case:
0958 break;
0959
0960 case __format_spec::__type::__char:
0961 __format_spec::__process_display_type_char(__parser, __id);
0962 break;
0963
0964 default:
0965 __format_spec::__throw_invalid_type_format_error(__id);
0966 }
0967 }
0968
0969 template <class _CharT>
0970 _LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_floating_point(__parser<_CharT>& __parser, const char* __id) {
0971 switch (__parser.__type_) {
0972 case __format_spec::__type::__default:
0973 case __format_spec::__type::__hexfloat_lower_case:
0974 case __format_spec::__type::__hexfloat_upper_case:
0975
0976 break;
0977 case __format_spec::__type::__scientific_lower_case:
0978 case __format_spec::__type::__scientific_upper_case:
0979 case __format_spec::__type::__fixed_lower_case:
0980 case __format_spec::__type::__fixed_upper_case:
0981 case __format_spec::__type::__general_lower_case:
0982 case __format_spec::__type::__general_upper_case:
0983 if (!__parser.__precision_as_arg_ && __parser.__precision_ == -1)
0984
0985 __parser.__precision_ = 6;
0986 break;
0987
0988 default:
0989 __format_spec::__throw_invalid_type_format_error(__id);
0990 }
0991 }
0992
0993 _LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_pointer(__format_spec::__type __type, const char* __id) {
0994 switch (__type) {
0995 case __format_spec::__type::__default:
0996 case __format_spec::__type::__pointer_lower_case:
0997 case __format_spec::__type::__pointer_upper_case:
0998 break;
0999
1000 default:
1001 __format_spec::__throw_invalid_type_format_error(__id);
1002 }
1003 }
1004
1005 template <contiguous_iterator _Iterator>
1006 struct __column_width_result {
1007
1008 size_t __width_;
1009
1010
1011
1012 _Iterator __last_;
1013 };
1014
1015 template <contiguous_iterator _Iterator>
1016 __column_width_result(size_t, _Iterator) -> __column_width_result<_Iterator>;
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027 enum class __column_width_rounding { __down, __up };
1028
1029 # if _LIBCPP_HAS_UNICODE
1030
1031 namespace __detail {
1032 template <contiguous_iterator _Iterator>
1033 _LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_Iterator> __estimate_column_width_grapheme_clustering(
1034 _Iterator __first, _Iterator __last, size_t __maximum, __column_width_rounding __rounding) noexcept {
1035 using _CharT = iter_value_t<_Iterator>;
1036 __unicode::__extended_grapheme_cluster_view<_CharT> __view{__first, __last};
1037
1038 __column_width_result<_Iterator> __result{0, __first};
1039 while (__result.__last_ != __last && __result.__width_ <= __maximum) {
1040 typename __unicode::__extended_grapheme_cluster_view<_CharT>::__cluster __cluster = __view.__consume();
1041 int __width = __width_estimation_table::__estimated_width(__cluster.__code_point_);
1042
1043
1044
1045
1046
1047
1048 if (__rounding == __column_width_rounding::__down && __result.__width_ + __width > __maximum)
1049 return __result;
1050
1051 __result.__width_ += __width;
1052 __result.__last_ = __cluster.__last_;
1053 }
1054
1055 return __result;
1056 }
1057
1058 }
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089 _LIBCPP_HIDE_FROM_ABI constexpr bool __is_ascii(char32_t __c) { return __c < 0x80; }
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105 template <class _CharT, class _Iterator = typename basic_string_view<_CharT>::const_iterator>
1106 _LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_Iterator> __estimate_column_width(
1107 basic_string_view<_CharT> __str, size_t __maximum, __column_width_rounding __rounding) noexcept {
1108
1109
1110
1111
1112
1113
1114
1115 if (__str.empty() || __maximum == 0)
1116 return {0, __str.begin()};
1117
1118
1119
1120
1121
1122
1123
1124
1125 auto __it = __str.begin();
1126 if (__format_spec::__is_ascii(*__it)) {
1127 do {
1128 --__maximum;
1129 ++__it;
1130 if (__it == __str.end())
1131 return {__str.size(), __str.end()};
1132
1133 if (__maximum == 0) {
1134 if (__format_spec::__is_ascii(*__it))
1135 return {static_cast<size_t>(__it - __str.begin()), __it};
1136
1137 break;
1138 }
1139 } while (__format_spec::__is_ascii(*__it));
1140 --__it;
1141 ++__maximum;
1142 }
1143
1144 ptrdiff_t __ascii_size = __it - __str.begin();
1145 __column_width_result __result =
1146 __detail::__estimate_column_width_grapheme_clustering(__it, __str.end(), __maximum, __rounding);
1147
1148 __result.__width_ += __ascii_size;
1149 return __result;
1150 }
1151 # else
1152 template <class _CharT>
1153 _LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<typename basic_string_view<_CharT>::const_iterator>
1154 __estimate_column_width(basic_string_view<_CharT> __str, size_t __maximum, __column_width_rounding) noexcept {
1155
1156
1157
1158 size_t __width = std::min(__str.size(), __maximum);
1159 return {__width, __str.begin() + __width};
1160 }
1161
1162 # endif
1163
1164 }
1165
1166 #endif
1167
1168 _LIBCPP_END_NAMESPACE_STD
1169
1170 _LIBCPP_POP_MACROS
1171
1172 #endif