#ifndef _LIBCPP___FORMAT_PARSER_STD_FORMAT_SPEC_H
#define _LIBCPP___FORMAT_PARSER_STD_FORMAT_SPEC_H
#include <__algorithm/copy_n.h>
#include <__algorithm/min.h>
#include <__assert>
#include <__concepts/arithmetic.h>
#include <__concepts/same_as.h>
#include <__config>
#include <__format/format_arg.h>
#include <__format/format_error.h>
#include <__format/format_parse_context.h>
#include <__format/format_string.h>
#include <__format/unicode.h>
#include <__format/width_estimation_table.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__memory/addressof.h>
#include <__type_traits/common_type.h>
#include <__type_traits/is_constant_evaluated.h>
#include <__type_traits/is_trivially_copyable.h>
#include <__variant/monostate.h>
#include <cstdint>
#include <string>
#include <string_view>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
namespace __format_spec {
_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI inline void
__throw_invalid_option_format_error(const char* __id, const char* __option) {
std::__throw_format_error(
(string("The format specifier for ") + __id + " does not allow the " + __option + " option").c_str());
}
_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI inline void __throw_invalid_type_format_error(const char* __id) {
std::__throw_format_error(
(string("The type option contains an invalid value for ") + __id + " formatting argument").c_str());
}
template <contiguous_iterator _Iterator, class _ParseContext>
_LIBCPP_HIDE_FROM_ABI constexpr __format::__parse_number_result<_Iterator>
__parse_arg_id(_Iterator __begin, _Iterator __end, _ParseContext& __ctx) {
using _CharT = iter_value_t<_Iterator>;
if (__begin == __end)
std::__throw_format_error("End of input while parsing an argument index");
__format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __ctx);
if (__r.__last == __end || *__r.__last != _CharT('}'))
std::__throw_format_error("The argument index is invalid");
++__r.__last;
return __r;
}
template <class _Context>
_LIBCPP_HIDE_FROM_ABI constexpr uint32_t __substitute_arg_id(basic_format_arg<_Context> __format_arg) {
return std::__visit_format_arg(
[](auto __arg) -> uint32_t {
using _Type = decltype(__arg);
if constexpr (same_as<_Type, monostate>)
std::__throw_format_error("The argument index value is too large for the number of arguments supplied");
if constexpr (same_as<_Type, int> || same_as<_Type, unsigned int> ||
same_as<_Type, long long> || same_as<_Type, unsigned long long>) {
if constexpr (signed_integral<_Type>) {
if (__arg < 0)
std::__throw_format_error("An argument index may not have a negative value");
}
using _CT = common_type_t<_Type, decltype(__format::__number_max)>;
if (static_cast<_CT>(__arg) > static_cast<_CT>(__format::__number_max))
std::__throw_format_error("The value of the argument index exceeds its maximum value");
return __arg;
} else
std::__throw_format_error("Replacement argument isn't a standard signed or unsigned integer type");
},
__format_arg);
}
struct _LIBCPP_HIDE_FROM_ABI __fields {
uint16_t __sign_ : 1 {false};
uint16_t __alternate_form_ : 1 {false};
uint16_t __zero_padding_ : 1 {false};
uint16_t __precision_ : 1 {false};
uint16_t __locale_specific_form_ : 1 {false};
uint16_t __type_ : 1 {false};
uint16_t __use_range_fill_ : 1 {false};
uint16_t __clear_brackets_ : 1 {false};
uint16_t __consume_all_ : 1 {false};
};
inline constexpr __fields __fields_bool{.__locale_specific_form_ = true, .__type_ = true, .__consume_all_ = true};
inline constexpr __fields __fields_integral{
.__sign_ = true,
.__alternate_form_ = true,
.__zero_padding_ = true,
.__locale_specific_form_ = true,
.__type_ = true,
.__consume_all_ = true};
inline constexpr __fields __fields_floating_point{
.__sign_ = true,
.__alternate_form_ = true,
.__zero_padding_ = true,
.__precision_ = true,
.__locale_specific_form_ = true,
.__type_ = true,
.__consume_all_ = true};
inline constexpr __fields __fields_string{.__precision_ = true, .__type_ = true, .__consume_all_ = true};
inline constexpr __fields __fields_pointer{.__zero_padding_ = true, .__type_ = true, .__consume_all_ = true};
# if _LIBCPP_STD_VER >= 23
inline constexpr __fields __fields_tuple{.__use_range_fill_ = true, .__clear_brackets_ = true};
inline constexpr __fields __fields_range{.__use_range_fill_ = true, .__clear_brackets_ = true};
inline constexpr __fields __fields_fill_align_width{};
# endif
enum class __alignment : uint8_t {
__default,
__left,
__center,
__right,
__zero_padding
};
enum class __sign : uint8_t {
__default,
__minus,
__plus,
__space
};
enum class __type : uint8_t {
__default = 0,
__string,
__binary_lower_case,
__binary_upper_case,
__octal,
__decimal,
__hexadecimal_lower_case,
__hexadecimal_upper_case,
__pointer_lower_case,
__pointer_upper_case,
__char,
__hexfloat_lower_case,
__hexfloat_upper_case,
__scientific_lower_case,
__scientific_upper_case,
__fixed_lower_case,
__fixed_upper_case,
__general_lower_case,
__general_upper_case,
__debug
};
_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __create_type_mask(__type __t) {
uint32_t __shift = static_cast<uint32_t>(__t);
if (__shift == 0)
return 1;
if (__shift > 31)
std::__throw_format_error("The type does not fit in the mask");
return 1 << __shift;
}
inline constexpr uint32_t __type_mask_integer =
__create_type_mask(__type::__binary_lower_case) |
__create_type_mask(__type::__binary_upper_case) |
__create_type_mask(__type::__decimal) |
__create_type_mask(__type::__octal) |
__create_type_mask(__type::__hexadecimal_lower_case) |
__create_type_mask(__type::__hexadecimal_upper_case);
struct __std {
__alignment __alignment_ : 3;
__sign __sign_ : 2;
bool __alternate_form_ : 1;
bool __locale_specific_form_ : 1;
__type __type_;
};
struct __chrono {
__alignment __alignment_ : 3;
bool __locale_specific_form_ : 1;
bool __hour_ : 1;
bool __weekday_name_ : 1;
bool __weekday_ : 1;
bool __day_of_year_ : 1;
bool __week_of_year_ : 1;
bool __month_name_ : 1;
};
template <class _CharT>
struct __code_point;
template <>
struct __code_point<char> {
char __data[4] = {' '};
};
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <>
struct __code_point<wchar_t> {
wchar_t __data[4 / sizeof(wchar_t)] = {L' '};
};
# endif
template <class _CharT>
struct __parsed_specifications {
union {
__alignment __alignment_ : 3;
__std __std_;
__chrono __chrono_;
};
int32_t __width_;
int32_t __precision_;
__code_point<_CharT> __fill_;
_LIBCPP_HIDE_FROM_ABI constexpr bool __has_width() const { return __width_ > 0; }
_LIBCPP_HIDE_FROM_ABI constexpr bool __has_precision() const { return __precision_ >= 0; }
};
static_assert(sizeof(__parsed_specifications<char>) == 16);
static_assert(is_trivially_copyable_v<__parsed_specifications<char>>);
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
static_assert(sizeof(__parsed_specifications<wchar_t>) == 16);
static_assert(is_trivially_copyable_v<__parsed_specifications<wchar_t>>);
# endif
template <class _CharT>
class _LIBCPP_TEMPLATE_VIS __parser {
public:
template <class _ParseContext>
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator __parse(_ParseContext& __ctx, __fields __fields) {
auto __begin = __ctx.begin();
auto __end = __ctx.end();
if (__begin == __end || *__begin == _CharT('}') || (__fields.__use_range_fill_ && *__begin == _CharT(':')))
return __begin;
if (__parse_fill_align(__begin, __end) && __begin == __end)
return __begin;
if (__fields.__sign_) {
if (__parse_sign(__begin) && __begin == __end)
return __begin;
} else if (std::is_constant_evaluated() && __parse_sign(__begin)) {
std::__throw_format_error("The format specification does not allow the sign option");
}
if (__fields.__alternate_form_) {
if (__parse_alternate_form(__begin) && __begin == __end)
return __begin;
} else if (std::is_constant_evaluated() && __parse_alternate_form(__begin)) {
std::__throw_format_error("The format specifier does not allow the alternate form option");
}
if (__fields.__zero_padding_) {
if (__parse_zero_padding(__begin) && __begin == __end)
return __begin;
} else if (std::is_constant_evaluated() && __parse_zero_padding(__begin)) {
std::__throw_format_error("The format specifier does not allow the zero-padding option");
}
if (__parse_width(__begin, __end, __ctx) && __begin == __end)
return __begin;
if (__fields.__precision_) {
if (__parse_precision(__begin, __end, __ctx) && __begin == __end)
return __begin;
} else if (std::is_constant_evaluated() && __parse_precision(__begin, __end, __ctx)) {
std::__throw_format_error("The format specifier does not allow the precision option");
}
if (__fields.__locale_specific_form_) {
if (__parse_locale_specific_form(__begin) && __begin == __end)
return __begin;
} else if (std::is_constant_evaluated() && __parse_locale_specific_form(__begin)) {
std::__throw_format_error("The format specifier does not allow the locale-specific form option");
}
if (__fields.__clear_brackets_) {
if (__parse_clear_brackets(__begin) && __begin == __end)
return __begin;
} else if (std::is_constant_evaluated() && __parse_clear_brackets(__begin)) {
std::__throw_format_error("The format specifier does not allow the n option");
}
if (__fields.__type_)
__parse_type(__begin);
if (!__fields.__consume_all_)
return __begin;
if (__begin != __end && *__begin != _CharT('}'))
std::__throw_format_error("The format specifier should consume the input or end with a '}'");
return __begin;
}
_LIBCPP_HIDE_FROM_ABI constexpr void
__validate(__fields __fields, const char* __id, uint32_t __type_mask = -1) const {
if (!__fields.__sign_ && __sign_ != __sign::__default) {
if (std::is_constant_evaluated())
std::__throw_format_error("The format specifier does not allow the sign option");
else
__format_spec::__throw_invalid_option_format_error(__id, "sign");
}
if (!__fields.__alternate_form_ && __alternate_form_) {
if (std::is_constant_evaluated())
std::__throw_format_error("The format specifier does not allow the alternate form option");
else
__format_spec::__throw_invalid_option_format_error(__id, "alternate form");
}
if (!__fields.__zero_padding_ && __alignment_ == __alignment::__zero_padding) {
if (std::is_constant_evaluated())
std::__throw_format_error("The format specifier does not allow the zero-padding option");
else
__format_spec::__throw_invalid_option_format_error(__id, "zero-padding");
}
if (!__fields.__precision_ && __precision_ != -1) {
if (std::is_constant_evaluated())
std::__throw_format_error("The format specifier does not allow the precision option");
else
__format_spec::__throw_invalid_option_format_error(__id, "precision");
}
if (!__fields.__locale_specific_form_ && __locale_specific_form_) {
if (std::is_constant_evaluated())
std::__throw_format_error("The format specifier does not allow the locale-specific form option");
else
__format_spec::__throw_invalid_option_format_error(__id, "locale-specific form");
}
if ((__create_type_mask(__type_) & __type_mask) == 0) {
if (std::is_constant_evaluated())
std::__throw_format_error("The format specifier uses an invalid value for the type option");
else
__format_spec::__throw_invalid_type_format_error(__id);
}
}
_LIBCPP_HIDE_FROM_ABI __parsed_specifications<_CharT> __get_parsed_std_specifications(auto& __ctx) const {
return __parsed_specifications<_CharT>{
.__std_ = __std{.__alignment_ = __alignment_,
.__sign_ = __sign_,
.__alternate_form_ = __alternate_form_,
.__locale_specific_form_ = __locale_specific_form_,
.__type_ = __type_},
.__width_{__get_width(__ctx)},
.__precision_{__get_precision(__ctx)},
.__fill_{__fill_}};
}
_LIBCPP_HIDE_FROM_ABI __parsed_specifications<_CharT> __get_parsed_chrono_specifications(auto& __ctx) const {
return __parsed_specifications<_CharT>{
.__chrono_ =
__chrono{.__alignment_ = __alignment_,
.__locale_specific_form_ = __locale_specific_form_,
.__hour_ = __hour_,
.__weekday_name_ = __weekday_name_,
.__weekday_ = __weekday_,
.__day_of_year_ = __day_of_year_,
.__week_of_year_ = __week_of_year_,
.__month_name_ = __month_name_},
.__width_{__get_width(__ctx)},
.__precision_{__get_precision(__ctx)},
.__fill_{__fill_}};
}
__alignment __alignment_ : 3 {__alignment::__default};
__sign __sign_ : 2 {__sign::__default};
bool __alternate_form_ : 1 {false};
bool __locale_specific_form_ : 1 {false};
bool __clear_brackets_ : 1 {false};
__type __type_{__type::__default};
bool __hour_ : 1 {false};
bool __weekday_name_ : 1 {false};
bool __weekday_ : 1 {false};
bool __day_of_year_ : 1 {false};
bool __week_of_year_ : 1 {false};
bool __month_name_ : 1 {false};
uint8_t __reserved_0_ : 2 {0};
uint8_t __reserved_1_ : 6 {0};
bool __width_as_arg_ : 1 {false};
bool __precision_as_arg_ : 1 {false};
int32_t __width_{0};
int32_t __precision_{-1};
__code_point<_CharT> __fill_{};
private:
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_alignment(_CharT __c) {
switch (__c) {
case _CharT('<'):
__alignment_ = __alignment::__left;
return true;
case _CharT('^'):
__alignment_ = __alignment::__center;
return true;
case _CharT('>'):
__alignment_ = __alignment::__right;
return true;
}
return false;
}
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_fill_character(_CharT __fill) {
if (__fill == _CharT('{'))
std::__throw_format_error("The fill option contains an invalid value");
}
# ifndef _LIBCPP_HAS_NO_UNICODE
template <contiguous_iterator _Iterator>
requires same_as<_CharT, char>
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|| (same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2)
# endif
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__begin != __end,
"when called with an empty input the function will cause "
"undefined behavior by evaluating data not in the input");
__unicode::__code_point_view<_CharT> __view{__begin, __end};
__unicode::__consume_result __consumed = __view.__consume();
if (__consumed.__status != __unicode::__consume_result::__ok)
std::__throw_format_error("The format specifier contains malformed Unicode characters");
if (__view.__position() < __end && __parse_alignment(*__view.__position())) {
ptrdiff_t __code_units = __view.__position() - __begin;
if (__code_units == 1)
__validate_fill_character(*__begin);
std::copy_n(__begin, __code_units, std::addressof(__fill_.__data[0]));
__begin += __code_units + 1;
return true;
}
if (!__parse_alignment(*__begin))
return false;
++__begin;
return true;
}
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <contiguous_iterator _Iterator>
requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4)
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__begin != __end,
"when called with an empty input the function will cause "
"undefined behavior by evaluating data not in the input");
if (__begin + 1 != __end && __parse_alignment(*(__begin + 1))) {
if (!__unicode::__is_scalar_value(*__begin))
std::__throw_format_error("The fill option contains an invalid value");
__validate_fill_character(*__begin);
__fill_.__data[0] = *__begin;
__begin += 2;
return true;
}
if (!__parse_alignment(*__begin))
return false;
++__begin;
return true;
}
# endif
# else
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__begin != __end,
"when called with an empty input the function will cause "
"undefined behavior by evaluating data not in the input");
if (__begin + 1 != __end) {
if (__parse_alignment(*(__begin + 1))) {
__validate_fill_character(*__begin);
__fill_.__data[0] = *__begin;
__begin += 2;
return true;
}
}
if (!__parse_alignment(*__begin))
return false;
++__begin;
return true;
}
# endif
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_sign(_Iterator& __begin) {
switch (*__begin) {
case _CharT('-'):
__sign_ = __sign::__minus;
break;
case _CharT('+'):
__sign_ = __sign::__plus;
break;
case _CharT(' '):
__sign_ = __sign::__space;
break;
default:
return false;
}
++__begin;
return true;
}
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_alternate_form(_Iterator& __begin) {
if (*__begin != _CharT('#'))
return false;
__alternate_form_ = true;
++__begin;
return true;
}
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_zero_padding(_Iterator& __begin) {
if (*__begin != _CharT('0'))
return false;
if (__alignment_ == __alignment::__default)
__alignment_ = __alignment::__zero_padding;
++__begin;
return true;
}
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_width(_Iterator& __begin, _Iterator __end, auto& __ctx) {
if (*__begin == _CharT('0'))
std::__throw_format_error("The width option should not have a leading zero");
if (*__begin == _CharT('{')) {
__format::__parse_number_result __r = __format_spec::__parse_arg_id(++__begin, __end, __ctx);
__width_as_arg_ = true;
__width_ = __r.__value;
__begin = __r.__last;
return true;
}
if (*__begin < _CharT('0') || *__begin > _CharT('9'))
return false;
__format::__parse_number_result __r = __format::__parse_number(__begin, __end);
__width_ = __r.__value;
_LIBCPP_ASSERT_INTERNAL(__width_ != 0,
"A zero value isn't allowed and should be impossible, "
"due to validations in this function");
__begin = __r.__last;
return true;
}
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_precision(_Iterator& __begin, _Iterator __end, auto& __ctx) {
if (*__begin != _CharT('.'))
return false;
++__begin;
if (__begin == __end)
std::__throw_format_error("End of input while parsing format specifier precision");
if (*__begin == _CharT('{')) {
__format::__parse_number_result __arg_id = __format_spec::__parse_arg_id(++__begin, __end, __ctx);
__precision_as_arg_ = true;
__precision_ = __arg_id.__value;
__begin = __arg_id.__last;
return true;
}
if (*__begin < _CharT('0') || *__begin > _CharT('9'))
std::__throw_format_error("The precision option does not contain a value or an argument index");
__format::__parse_number_result __r = __format::__parse_number(__begin, __end);
__precision_ = __r.__value;
__precision_as_arg_ = false;
__begin = __r.__last;
return true;
}
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_locale_specific_form(_Iterator& __begin) {
if (*__begin != _CharT('L'))
return false;
__locale_specific_form_ = true;
++__begin;
return true;
}
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_clear_brackets(_Iterator& __begin) {
if (*__begin != _CharT('n'))
return false;
__clear_brackets_ = true;
++__begin;
return true;
}
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(_Iterator& __begin) {
switch (*__begin) {
case 'A':
__type_ = __type::__hexfloat_upper_case;
break;
case 'B':
__type_ = __type::__binary_upper_case;
break;
case 'E':
__type_ = __type::__scientific_upper_case;
break;
case 'F':
__type_ = __type::__fixed_upper_case;
break;
case 'G':
__type_ = __type::__general_upper_case;
break;
case 'X':
__type_ = __type::__hexadecimal_upper_case;
break;
case 'a':
__type_ = __type::__hexfloat_lower_case;
break;
case 'b':
__type_ = __type::__binary_lower_case;
break;
case 'c':
__type_ = __type::__char;
break;
case 'd':
__type_ = __type::__decimal;
break;
case 'e':
__type_ = __type::__scientific_lower_case;
break;
case 'f':
__type_ = __type::__fixed_lower_case;
break;
case 'g':
__type_ = __type::__general_lower_case;
break;
case 'o':
__type_ = __type::__octal;
break;
case 'p':
__type_ = __type::__pointer_lower_case;
break;
case 'P':
__type_ = __type::__pointer_upper_case;
break;
case 's':
__type_ = __type::__string;
break;
case 'x':
__type_ = __type::__hexadecimal_lower_case;
break;
# if _LIBCPP_STD_VER >= 23
case '?':
__type_ = __type::__debug;
break;
# endif
default:
return;
}
++__begin;
}
_LIBCPP_HIDE_FROM_ABI int32_t __get_width(auto& __ctx) const {
if (!__width_as_arg_)
return __width_;
return __format_spec::__substitute_arg_id(__ctx.arg(__width_));
}
_LIBCPP_HIDE_FROM_ABI int32_t __get_precision(auto& __ctx) const {
if (!__precision_as_arg_)
return __precision_;
return __format_spec::__substitute_arg_id(__ctx.arg(__precision_));
}
};
static_assert(sizeof(__parser<char>) == 16);
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
static_assert(sizeof(__parser<wchar_t>) == 16);
# endif
_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_string(__format_spec::__type __type) {
switch (__type) {
case __format_spec::__type::__default:
case __format_spec::__type::__string:
case __format_spec::__type::__debug:
break;
default:
std::__throw_format_error("The type option contains an invalid value for a string formatting argument");
}
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_bool_string(__parser<_CharT>& __parser, const char* __id) {
__parser.__validate(__format_spec::__fields_bool, __id);
if (__parser.__alignment_ == __alignment::__default)
__parser.__alignment_ = __alignment::__left;
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_char(__parser<_CharT>& __parser, const char* __id) {
__format_spec::__process_display_type_bool_string(__parser, __id);
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_bool(__parser<_CharT>& __parser, const char* __id) {
switch (__parser.__type_) {
case __format_spec::__type::__default:
case __format_spec::__type::__string:
__format_spec::__process_display_type_bool_string(__parser, __id);
break;
case __format_spec::__type::__binary_lower_case:
case __format_spec::__type::__binary_upper_case:
case __format_spec::__type::__octal:
case __format_spec::__type::__decimal:
case __format_spec::__type::__hexadecimal_lower_case:
case __format_spec::__type::__hexadecimal_upper_case:
break;
default:
__format_spec::__throw_invalid_type_format_error(__id);
}
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_char(__parser<_CharT>& __parser, const char* __id) {
switch (__parser.__type_) {
case __format_spec::__type::__default:
case __format_spec::__type::__char:
case __format_spec::__type::__debug:
__format_spec::__process_display_type_char(__parser, __id);
break;
case __format_spec::__type::__binary_lower_case:
case __format_spec::__type::__binary_upper_case:
case __format_spec::__type::__octal:
case __format_spec::__type::__decimal:
case __format_spec::__type::__hexadecimal_lower_case:
case __format_spec::__type::__hexadecimal_upper_case:
break;
default:
__format_spec::__throw_invalid_type_format_error(__id);
}
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_integer(__parser<_CharT>& __parser, const char* __id) {
switch (__parser.__type_) {
case __format_spec::__type::__default:
case __format_spec::__type::__binary_lower_case:
case __format_spec::__type::__binary_upper_case:
case __format_spec::__type::__octal:
case __format_spec::__type::__decimal:
case __format_spec::__type::__hexadecimal_lower_case:
case __format_spec::__type::__hexadecimal_upper_case:
break;
case __format_spec::__type::__char:
__format_spec::__process_display_type_char(__parser, __id);
break;
default:
__format_spec::__throw_invalid_type_format_error(__id);
}
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_floating_point(__parser<_CharT>& __parser, const char* __id) {
switch (__parser.__type_) {
case __format_spec::__type::__default:
case __format_spec::__type::__hexfloat_lower_case:
case __format_spec::__type::__hexfloat_upper_case:
break;
case __format_spec::__type::__scientific_lower_case:
case __format_spec::__type::__scientific_upper_case:
case __format_spec::__type::__fixed_lower_case:
case __format_spec::__type::__fixed_upper_case:
case __format_spec::__type::__general_lower_case:
case __format_spec::__type::__general_upper_case:
if (!__parser.__precision_as_arg_ && __parser.__precision_ == -1)
__parser.__precision_ = 6;
break;
default:
__format_spec::__throw_invalid_type_format_error(__id);
}
}
_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_pointer(__format_spec::__type __type, const char* __id) {
switch (__type) {
case __format_spec::__type::__default:
case __format_spec::__type::__pointer_lower_case:
case __format_spec::__type::__pointer_upper_case:
break;
default:
__format_spec::__throw_invalid_type_format_error(__id);
}
}
template <contiguous_iterator _Iterator>
struct __column_width_result {
size_t __width_;
_Iterator __last_;
};
template <contiguous_iterator _Iterator>
__column_width_result(size_t, _Iterator) -> __column_width_result<_Iterator>;
enum class __column_width_rounding { __down, __up };
# ifndef _LIBCPP_HAS_NO_UNICODE
namespace __detail {
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_Iterator> __estimate_column_width_grapheme_clustering(
_Iterator __first, _Iterator __last, size_t __maximum, __column_width_rounding __rounding) noexcept {
using _CharT = iter_value_t<_Iterator>;
__unicode::__extended_grapheme_cluster_view<_CharT> __view{__first, __last};
__column_width_result<_Iterator> __result{0, __first};
while (__result.__last_ != __last && __result.__width_ <= __maximum) {
typename __unicode::__extended_grapheme_cluster_view<_CharT>::__cluster __cluster = __view.__consume();
int __width = __width_estimation_table::__estimated_width(__cluster.__code_point_);
if (__rounding == __column_width_rounding::__down && __result.__width_ + __width > __maximum)
return __result;
__result.__width_ += __width;
__result.__last_ = __cluster.__last_;
}
return __result;
}
}
_LIBCPP_HIDE_FROM_ABI constexpr bool __is_ascii(char32_t __c) { return __c < 0x80; }
template <class _CharT, class _Iterator = typename basic_string_view<_CharT>::const_iterator>
_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_Iterator> __estimate_column_width(
basic_string_view<_CharT> __str, size_t __maximum, __column_width_rounding __rounding) noexcept {
if (__str.empty() || __maximum == 0)
return {0, __str.begin()};
auto __it = __str.begin();
if (__format_spec::__is_ascii(*__it)) {
do {
--__maximum;
++__it;
if (__it == __str.end())
return {__str.size(), __str.end()};
if (__maximum == 0) {
if (__format_spec::__is_ascii(*__it))
return {static_cast<size_t>(__it - __str.begin()), __it};
break;
}
} while (__format_spec::__is_ascii(*__it));
--__it;
++__maximum;
}
ptrdiff_t __ascii_size = __it - __str.begin();
__column_width_result __result =
__detail::__estimate_column_width_grapheme_clustering(__it, __str.end(), __maximum, __rounding);
__result.__width_ += __ascii_size;
return __result;
}
# else
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<typename basic_string_view<_CharT>::const_iterator>
__estimate_column_width(basic_string_view<_CharT> __str, size_t __maximum, __column_width_rounding) noexcept {
size_t __width = std::min(__str.size(), __maximum);
return {__width, __str.begin() + __width};
}
# endif
}
#endif
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif