aboutsummaryrefslogtreecommitdiff
path: root/libcxx/include/__format/parser_std_format_spec.h
diff options
context:
space:
mode:
Diffstat (limited to 'libcxx/include/__format/parser_std_format_spec.h')
-rw-r--r--libcxx/include/__format/parser_std_format_spec.h649
1 files changed, 611 insertions, 38 deletions
diff --git a/libcxx/include/__format/parser_std_format_spec.h b/libcxx/include/__format/parser_std_format_spec.h
index 9d893e9ced27..739bdf457e40 100644
--- a/libcxx/include/__format/parser_std_format_spec.h
+++ b/libcxx/include/__format/parser_std_format_spec.h
@@ -10,12 +10,20 @@
#ifndef _LIBCPP___FORMAT_PARSER_STD_FORMAT_SPEC_H
#define _LIBCPP___FORMAT_PARSER_STD_FORMAT_SPEC_H
+/// \file Contains the std-format-spec parser.
+///
+/// Most of the code can be reused in the chrono-format-spec.
+/// This header has some support for the chrono-format-spec since it doesn't
+/// affect the std-format-spec.
+
#include <__algorithm/find_if.h>
#include <__algorithm/min.h>
+#include <__assert>
#include <__config>
#include <__debug>
#include <__format/format_arg.h>
#include <__format/format_error.h>
+#include <__format/format_parse_context.h>
#include <__format/format_string.h>
#include <__variant/monostate.h>
#include <bit>
@@ -24,7 +32,7 @@
#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-# pragma GCC system_header
+# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
@@ -34,24 +42,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER > 17
-// TODO FMT Remove this once we require compilers with proper C++20 support.
-// If the compiler has no concepts support, the format header will be disabled.
-// Without concepts support enable_if needs to be used and that too much effort
-// to support compilers with partial C++20 support.
-# if !defined(_LIBCPP_HAS_NO_CONCEPTS)
-
namespace __format_spec {
/**
* Contains the flags for the std-format-spec.
*
- * Some format-options can only be used for specific C++types and may depend on
+ * Some format-options can only be used for specific C++ types and may depend on
* the selected format-type.
* * The C++type filtering can be done using the proper policies for
* @ref __parser_std.
* * The format-type filtering needs to be done post parsing in the parser
* derived from @ref __parser_std.
*/
+_LIBCPP_PACKED_BYTE_FOR_AIX
class _LIBCPP_TYPE_VIS _Flags {
public:
enum class _LIBCPP_ENUM_VIS _Alignment : uint8_t {
@@ -109,6 +112,7 @@ public:
_Type __type{_Type::__default};
};
+_LIBCPP_PACKED_BYTE_FOR_AIX_END
namespace __detail {
template <class _CharT>
@@ -222,7 +226,7 @@ __parse_arg_id(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) {
template <class _Context>
_LIBCPP_HIDE_FROM_ABI constexpr uint32_t
-__substitute_arg_id(basic_format_arg<_Context> __arg) {
+__substitute_arg_id(basic_format_arg<_Context> _Arg) {
return visit_format_arg(
[](auto __arg) -> uint32_t {
using _Type = decltype(__arg);
@@ -246,7 +250,7 @@ __substitute_arg_id(basic_format_arg<_Context> __arg) {
__throw_format_error("A format-spec arg-id replacement argument "
"isn't an integral type");
},
- __arg);
+ _Arg);
}
class _LIBCPP_TYPE_VIS __parser_width {
@@ -256,25 +260,21 @@ public:
/** Determines whether the value stored is a width or an arg-id. */
uint32_t __width_as_arg : 1 {0};
-protected:
/**
- * Does the supplied std-format-spec contain a width field?
+ * Does the supplied width field contain an arg-id?
*
- * When the field isn't present there's no padding required. This can be used
- * to optimize the formatting.
+ * If @c true the formatter needs to call @ref __substitute_width_arg_id.
*/
- constexpr bool __has_width_field() const noexcept {
- return __width_as_arg || __width;
- }
+ constexpr bool __width_needs_substitution() const noexcept { return __width_as_arg; }
+protected:
/**
- * Does the supplied width field contain an arg-id?
+ * Does the supplied std-format-spec contain a width field?
*
- * If @c true the formatter needs to call @ref __substitute_width_arg_id.
+ * When the field isn't present there's no padding required. This can be used
+ * to optimize the formatting.
*/
- constexpr bool __width_needs_substitution() const noexcept {
- return __width_as_arg;
- }
+ constexpr bool __has_width_field() const noexcept { return __width_as_arg || __width; }
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr const _CharT*
@@ -331,6 +331,15 @@ public:
*/
uint32_t __precision_as_arg : 1 {1};
+ /**
+ * Does the supplied precision field contain an arg-id?
+ *
+ * If @c true the formatter needs to call @ref __substitute_precision_arg_id.
+ */
+ constexpr bool __precision_needs_substitution() const noexcept {
+ return __precision_as_arg && __precision != __format::__number_max;
+ }
+
protected:
/**
* Does the supplied std-format-spec contain a precision field?
@@ -344,15 +353,6 @@ protected:
__precision != __format::__number_max; // The arg-id is valid?
}
- /**
- * Does the supplied precision field contain an arg-id?
- *
- * If @c true the formatter needs to call @ref __substitute_precision_arg_id.
- */
- constexpr bool __precision_needs_substitution() const noexcept {
- return __precision_as_arg && __precision != __format::__number_max;
- }
-
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr const _CharT*
__parse(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) {
@@ -1041,7 +1041,7 @@ concept __utf16_or_32_character = __utf16_character<_CharT> || __utf32_character
* character.
*/
_LIBCPP_HIDE_FROM_ABI inline constexpr int __column_width_3(uint32_t __c) noexcept {
- _LIBCPP_ASSERT(__c < 0x1'0000,
+ _LIBCPP_ASSERT(__c < 0x10000,
"Use __column_width_4 or __column_width for larger values");
// clang-format off
@@ -1066,7 +1066,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr int __column_width_3(uint32_t __c) noexce
* 4-byte UTF-8 character.
*/
_LIBCPP_HIDE_FROM_ABI inline constexpr int __column_width_4(uint32_t __c) noexcept {
- _LIBCPP_ASSERT(__c >= 0x1'0000,
+ _LIBCPP_ASSERT(__c >= 0x10000,
"Use __column_width_3 or __column_width for smaller values");
// clang-format off
@@ -1084,7 +1084,7 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr int __column_width_4(uint32_t __c) noexce
* The general case, accepting all values.
*/
_LIBCPP_HIDE_FROM_ABI inline constexpr int __column_width(uint32_t __c) noexcept {
- if (__c < 0x1'0000)
+ if (__c < 0x10000)
return __column_width_3(__c);
return __column_width_4(__c);
@@ -1244,7 +1244,7 @@ __estimate_column_width(const _CharT* __first, const _CharT* __last,
__c -= 0xd800;
__c <<= 10;
__c += (*(__first + 1) - 0xdc00);
- __c += 0x10'000;
+ __c += 0x10000;
__result += __column_width_4(__c);
if (__result > __maximum)
@@ -1271,7 +1271,7 @@ __estimate_column_width(const _CharT* __first, const _CharT* __last,
size_t __result = 0;
while (__first != __last) {
- wchar_t __c = *__first;
+ uint32_t __c = *__first;
__result += __column_width(__c);
if (__result > __maximum)
@@ -1385,9 +1385,582 @@ __get_string_alignment(const _CharT* __first, const _CharT* __last,
}
#endif // _LIBCPP_HAS_NO_UNICODE
-} // namespace __format_spec
+/// These fields are a filter for which elements to parse.
+///
+/// They default to false so when a new field is added it needs to be opted in
+/// explicitly.
+struct __fields {
+ uint8_t __sign_ : 1 {false};
+ uint8_t __alternate_form_ : 1 {false};
+ uint8_t __zero_padding_ : 1 {false};
+ uint8_t __precision_ : 1 {false};
+ uint8_t __locale_specific_form_ : 1 {false};
+ uint8_t __type_ : 1 {false};
+};
+
+// By not placing this constant in the formatter class it's not duplicated for
+// char and wchar_t.
+inline constexpr __fields __fields_integral{
+ .__sign_ = true,
+ .__alternate_form_ = true,
+ .__zero_padding_ = true,
+ .__locale_specific_form_ = true,
+ .__type_ = true};
+inline constexpr __fields __fields_string{.__precision_ = true, .__type_ = true};
+inline constexpr __fields __fields_pointer{.__type_ = true};
+
+enum class _LIBCPP_ENUM_VIS __alignment : uint8_t {
+ /// No alignment is set in the format string.
+ __default,
+ __left,
+ __center,
+ __right,
+ __zero_padding
+};
+
+enum class _LIBCPP_ENUM_VIS __sign : uint8_t {
+ /// No sign is set in the format string.
+ ///
+ /// The sign isn't allowed for certain format-types. By using this value
+ /// it's possible to detect whether or not the user explicitly set the sign
+ /// flag. For formatting purposes it behaves the same as \ref __minus.
+ __default,
+ __minus,
+ __plus,
+ __space
+};
+
+enum class _LIBCPP_ENUM_VIS __type : uint8_t {
+ __default,
+ __string,
+ __binary_lower_case,
+ __binary_upper_case,
+ __octal,
+ __decimal,
+ __hexadecimal_lower_case,
+ __hexadecimal_upper_case,
+ __pointer,
+ __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
+};
+
+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 __weekday_name_ : 1;
+ bool __month_name_ : 1;
+};
+
+/// Contains the parsed formatting specifications.
+///
+/// This contains information for both the std-format-spec and the
+/// chrono-format-spec. This results in some unused members for both
+/// specifications. However these unused members don't increase the size
+/// of the structure.
+///
+/// This struct doesn't cross ABI boundaries so its layout doesn't need to be
+/// kept stable.
+template <class _CharT>
+struct __parsed_specifications {
+ union {
+ // The field __alignment_ is the first element in __std_ and __chrono_.
+ // This allows the code to always inspect this value regards which member
+ // of the union is the active member [class.union.general]/2.
+ //
+ // This is needed since the generic output routines handle the alignment of
+ // the output.
+ __alignment __alignment_ : 3;
+ __std __std_;
+ __chrono __chrono_;
+ };
+
+ /// The requested width.
+ ///
+ /// When the format-spec used an arg-id for this field it has already been
+ /// replaced with the value of that arg-id.
+ int32_t __width_;
+
+ /// The requested precision.
+ ///
+ /// When the format-spec used an arg-id for this field it has already been
+ /// replaced with the value of that arg-id.
+ int32_t __precision_;
+
+ _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; }
+};
+
+// Validate the struct is small and cheap to copy since the struct is passed by
+// value in formatting functions.
+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
+
+/// The parser for the std-format-spec.
+///
+/// Note this class is a member of std::formatter specializations. It's
+/// expected developers will create their own formatter specializations that
+/// inherit from the std::formatter specializations. This means this class
+/// must be ABI stable. To aid the stability the unused bits in the class are
+/// set to zero. That way they can be repurposed if a future revision of the
+/// Standards adds new fields to std-format-spec.
+template <class _CharT>
+class _LIBCPP_TEMPLATE_VIS __parser {
+public:
+ _LIBCPP_HIDE_FROM_ABI constexpr auto __parse(basic_format_parse_context<_CharT>& __parse_ctx, __fields __fields)
+ -> decltype(__parse_ctx.begin()) {
+
+ const _CharT* __begin = __parse_ctx.begin();
+ const _CharT* __end = __parse_ctx.end();
+ if (__begin == __end)
+ return __begin;
+
+ if (__parse_fill_align(__begin, __end) && __begin == __end)
+ return __begin;
+
+ if (__fields.__sign_ && __parse_sign(__begin) && __begin == __end)
+ return __begin;
+
+ if (__fields.__alternate_form_ && __parse_alternate_form(__begin) && __begin == __end)
+ return __begin;
+
+ if (__fields.__zero_padding_ && __parse_zero_padding(__begin) && __begin == __end)
+ return __begin;
+
+ if (__parse_width(__begin, __end, __parse_ctx) && __begin == __end)
+ return __begin;
+
+ if (__fields.__precision_ && __parse_precision(__begin, __end, __parse_ctx) && __begin == __end)
+ return __begin;
+
+ if (__fields.__locale_specific_form_ && __parse_locale_specific_form(__begin) && __begin == __end)
+ return __begin;
+
+ if (__fields.__type_) {
+ __parse_type(__begin);
+
+ // When __type_ is false the calling parser is expected to do additional
+ // parsing. In that case that parser should do the end of format string
+ // validation.
+ if (__begin != __end && *__begin != _CharT('}'))
+ __throw_format_error("The format-spec should consume the input or end with a '}'");
+ }
+
+ return __begin;
+ }
+
+ /// \returns the `__parsed_specifications` with the resolved dynamic sizes..
+ _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_}};
+ }
+
+ __alignment __alignment_ : 3 {__alignment::__default};
+ __sign __sign_ : 2 {__sign::__default};
+ bool __alternate_form_ : 1 {false};
+ bool __locale_specific_form_ : 1 {false};
+ bool __reserved_0_ : 1 {false};
+ __type __type_{__type::__default};
+
+ // These two flags are used for formatting chrono. Since the struct has
+ // padding space left it's added to this structure.
+ bool __weekday_name_ : 1 {false};
+ bool __month_name_ : 1 {false};
+
+ uint8_t __reserved_1_ : 6 {0};
+ uint8_t __reserved_2_ : 6 {0};
+ // These two flags are only used internally and not part of the
+ // __parsed_specifications. Therefore put them at the end.
+ bool __width_as_arg_ : 1 {false};
+ bool __precision_as_arg_ : 1 {false};
+
+ /// The requested width, either the value or the arg-id.
+ int32_t __width_{0};
+
+ /// The requested precision, either the value or the arg-id.
+ int32_t __precision_{-1};
+
+ // LWG 3576 will probably change this to always accept a Unicode code point
+ // To avoid changing the size with that change align the field so when it
+ // becomes 32-bit its alignment will remain the same. That also means the
+ // size will remain the same. (D2572 addresses the solution for LWG 3576.)
+ _CharT __fill_{_CharT(' ')};
+
+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 bool __parse_fill_align(const _CharT*& __begin, const _CharT* __end) {
+ _LIBCPP_ASSERT(__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))) {
+ if (*__begin == _CharT('{') || *__begin == _CharT('}'))
+ __throw_format_error("The format-spec fill field contains an invalid character");
+
+ __fill_ = *__begin;
+ __begin += 2;
+ return true;
+ }
+ }
+
+ if (!__parse_alignment(*__begin))
+ return false;
+
+ ++__begin;
+ return true;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_sign(const _CharT*& __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;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_alternate_form(const _CharT*& __begin) {
+ if (*__begin != _CharT('#'))
+ return false;
-# endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
+ __alternate_form_ = true;
+ ++__begin;
+ return true;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_zero_padding(const _CharT*& __begin) {
+ if (*__begin != _CharT('0'))
+ return false;
+
+ if (__alignment_ == __alignment::__default)
+ __alignment_ = __alignment::__zero_padding;
+ ++__begin;
+ return true;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_width(const _CharT*& __begin, const _CharT* __end, auto& __parse_ctx) {
+ if (*__begin == _CharT('0'))
+ __throw_format_error("A format-spec width field shouldn't have a leading zero");
+
+ if (*__begin == _CharT('{')) {
+ __format::__parse_number_result __r = __format_spec::__parse_arg_id(++__begin, __end, __parse_ctx);
+ __width_as_arg_ = true;
+ __width_ = __r.__value;
+ __begin = __r.__ptr;
+ 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(__width_ != 0, "A zero value isn't allowed and should be impossible, "
+ "due to validations in this function");
+ __begin = __r.__ptr;
+ return true;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_precision(const _CharT*& __begin, const _CharT* __end,
+ auto& __parse_ctx) {
+ if (*__begin != _CharT('.'))
+ return false;
+
+ ++__begin;
+ if (__begin == __end)
+ __throw_format_error("End of input while parsing format-spec precision");
+
+ if (*__begin == _CharT('{')) {
+ __format::__parse_number_result __arg_id = __format_spec::__parse_arg_id(++__begin, __end, __parse_ctx);
+ __precision_as_arg_ = true;
+ __precision_ = __arg_id.__value;
+ __begin = __arg_id.__ptr;
+ return true;
+ }
+
+ if (*__begin < _CharT('0') || *__begin > _CharT('9'))
+ __throw_format_error("The format-spec precision field doesn't contain a value or arg-id");
+
+ __format::__parse_number_result __r = __format::__parse_number(__begin, __end);
+ __precision_ = __r.__value;
+ __precision_as_arg_ = false;
+ __begin = __r.__ptr;
+ return true;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_locale_specific_form(const _CharT*& __begin) {
+ if (*__begin != _CharT('L'))
+ return false;
+
+ __locale_specific_form_ = true;
+ ++__begin;
+ return true;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(const _CharT*& __begin) {
+ // Determines the type. It does not validate whether the selected type is
+ // valid. Most formatters have optional fields that are only allowed for
+ // certain types. These parsers need to do validation after the type has
+ // been parsed. So its easier to implement the validation for all types in
+ // the specific parse function.
+ 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;
+ break;
+ case 's':
+ __type_ = __type::__string;
+ break;
+ case 'x':
+ __type_ = __type::__hexadecimal_lower_case;
+ break;
+ default:
+ return;
+ }
+ ++__begin;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI
+ int32_t __get_width(auto& __ctx) const {
+ if (!__width_as_arg_)
+ return __width_;
+
+ int32_t __result = __format_spec::__substitute_arg_id(__ctx.arg(__width_));
+ if (__result == 0)
+ __throw_format_error("A format-spec width field replacement should have a positive value");
+ return __result;
+ }
+
+ _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_));
+ }
+};
+
+// Validates whether the reserved bitfields don't change the size.
+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:
+ break;
+
+ default:
+ std::__throw_format_error("The format-spec type has a type not supported for a string argument");
+ }
+}
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_bool_string(__parser<_CharT>& __parser) {
+ if (__parser.__sign_ != __sign::__default)
+ std::__throw_format_error("A sign field isn't allowed in this format-spec");
+
+ if (__parser.__alternate_form_)
+ std::__throw_format_error("An alternate form field isn't allowed in this format-spec");
+
+ if (__parser.__alignment_ == __alignment::__zero_padding)
+ std::__throw_format_error("A zero-padding field isn't allowed in this format-spec");
+
+ 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) {
+ __format_spec::__process_display_type_bool_string(__parser);
+}
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_integer(__parser<_CharT>& __parser) {
+ if (__parser.__alignment_ == __alignment::__default)
+ __parser.__alignment_ = __alignment::__right;
+}
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_bool(__parser<_CharT>& __parser) {
+ switch (__parser.__type_) {
+ case __format_spec::__type::__default:
+ __parser.__type_ = __format_spec::__type::__string;
+ [[fallthrough]];
+ case __format_spec::__type::__string:
+ __format_spec::__process_display_type_bool_string(__parser);
+ 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:
+ __process_display_type_integer(__parser);
+ break;
+
+ default:
+ std::__throw_format_error("The format-spec type has a type not supported for a bool argument");
+ }
+}
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_char(__parser<_CharT>& __parser) {
+ switch (__parser.__type_) {
+ case __format_spec::__type::__default:
+ __parser.__type_ = __format_spec::__type::__char;
+ [[fallthrough]];
+ case __format_spec::__type::__char:
+ __format_spec::__process_display_type_char(__parser);
+ 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:
+ __format_spec::__process_display_type_integer(__parser);
+ break;
+
+ default:
+ std::__throw_format_error("The format-spec type has a type not supported for a char argument");
+ }
+}
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_integer(__parser<_CharT>& __parser) {
+ switch (__parser.__type_) {
+ case __format_spec::__type::__default:
+ __parser.__type_ = __format_spec::__type::__decimal;
+ [[fallthrough]];
+ 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:
+ __format_spec::__process_display_type_integer(__parser);
+ break;
+
+ case __format_spec::__type::__char:
+ __format_spec::__process_display_type_char(__parser);
+ break;
+
+ default:
+ std::__throw_format_error("The format-spec type has a type not supported for an integer argument");
+ }
+}
+
+_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_pointer(__format_spec::__type __type) {
+ switch (__type) {
+ case __format_spec::__type::__default:
+ case __format_spec::__type::__pointer:
+ break;
+
+ default:
+ std::__throw_format_error("The format-spec type has a type not supported for a pointer argument");
+ }
+}
+
+} // namespace __format_spec
#endif //_LIBCPP_STD_VER > 17