auto __begin = __parser_.__parse(__ctx, __format_spec::__fields_tuple);
auto __end = __ctx.end();
- if (__begin != __end) {
- if (*__begin == _CharT('m')) {
- if constexpr (sizeof...(_Args) == 2) {
- set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": "));
- set_brackets({}, {});
- ++__begin;
- } else
- std::__throw_format_error("The format specifier m requires a pair or a two-element tuple");
- } else if (*__begin == _CharT('n')) {
+ // Note 'n' is part of the type here
+ if (__parser_.__clear_brackets_)
+ set_brackets({}, {});
+ else if (__begin != __end && *__begin == _CharT('m')) {
+ if constexpr (sizeof...(_Args) == 2) {
+ set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": "));
set_brackets({}, {});
++__begin;
- }
+ } else
+ std::__throw_format_error("The format specifier m requires a pair or a two-element tuple");
}
if (__begin != __end && *__begin != _CharT('}'))
/// explicitly.
// TODO FMT Use an ABI tag for this struct.
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};
+ 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};
// Determines the valid values for fill.
//
// Originally the fill could be any character except { and }. Range-based
// formatters use the colon to mark the beginning of the
// underlying-format-spec. To avoid parsing ambiguities these formatter
// specializations prohibit the use of the colon as a fill character.
- uint8_t __use_range_fill_ : 1 {false};
+ uint16_t __use_range_fill_ : 1 {false};
+ uint16_t __clear_brackets_ : 1 {false};
+ uint16_t __consume_all_ : 1 {false};
};
// By not placing this constant in the formatter class it's not duplicated for
// char and wchar_t.
+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};
+ .__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};
-inline constexpr __fields __fields_string{.__precision_ = true, .__type_ = true};
-inline constexpr __fields __fields_pointer{.__zero_padding_ = true, .__type_ = 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};
-inline constexpr __fields __fields_range{.__use_range_fill_ = true};
+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
if (__fields.__locale_specific_form_ && __parse_locale_specific_form(__begin) && __begin == __end)
return __begin;
- if (__fields.__type_) {
+ if (__fields.__clear_brackets_ && __parse_clear_brackets(__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('}'))
- std::__throw_format_error("The format-spec should consume the input or end with a '}'");
- }
+ if (!__fields.__consume_all_)
+ return __begin;
+
+ if (__begin != __end && *__begin != _CharT('}'))
+ std::__throw_format_error("The format-spec should consume the input or end with a '}'");
return __begin;
}
__sign __sign_ : 2 {__sign::__default};
bool __alternate_form_ : 1 {false};
bool __locale_specific_form_ : 1 {false};
- bool __reserved_0_ : 1 {false};
+ bool __clear_brackets_ : 1 {false};
__type __type_{__type::__default};
// These flags are only used for formatting chrono. Since the struct has
bool __month_name_ : 1 {false};
- uint8_t __reserved_1_ : 2 {0};
- uint8_t __reserved_2_ : 6 {0};
+ uint8_t __reserved_0_ : 2 {0};
+ uint8_t __reserved_1_ : 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};
}
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) {
// Determines the type. It does not validate whether the selected type is
// valid. Most formatters have optional fields that are only allowed for
// The n field overrides a possible m type, therefore delay applying the
// effect of n until the type has been procesed.
- bool __clear_brackets = (*__begin == _CharT('n'));
- if (__clear_brackets) {
- ++__begin;
- if (__begin == __end) [[unlikely]] {
- // Since there is no more data, clear the brackets before returning.
- set_brackets({}, {});
- return __parse_empty_range_underlying_spec(__ctx, __begin);
- }
- }
-
__parse_type(__begin, __end);
- if (__clear_brackets)
+ if (__parser_.__clear_brackets_)
set_brackets({}, {});
if (__begin == __end) [[unlikely]]
return __parse_empty_range_underlying_spec(__ctx, __begin);
// [format.range.formatter]/6
// If the range-type is s or ?s, then there shall be no n option and no
// range-underlying-spec.
- if (__clear_brackets) {
+ if (__parser_.__clear_brackets_) {
if (__parser_.__type_ == __format_spec::__type::__string)
std::__throw_format_error("The n option and type s can't be used together");
std::__throw_format_error("The n option and type ?s can't be used together");