From b9c0e4dd82874d784cd8bd70457c595658483d48 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 2 Aug 2024 11:57:02 -0700 Subject: [PATCH] Improve spec parsing --- include/fmt/base.h | 30 +++++++----------------------- include/fmt/format.h | 13 ++++++++----- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/include/fmt/base.h b/include/fmt/base.h index 141ffe08..b40b3bfb 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -2398,14 +2398,11 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end, constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; struct { const Char*& begin; - dynamic_format_specs& specs; + format_specs& specs; type arg_type; FMT_CONSTEXPR auto operator()(pres pres_type, int set) -> const Char* { - if (!in(arg_type, set)) { - if (arg_type == type::none_type) return begin; - report_error("invalid format specifier"); - } + if (!in(arg_type, set)) report_error("invalid format specifier"); specs.type = pres_type; return begin + 1; } @@ -2421,34 +2418,23 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end, ++begin; break; case '+': - case '-': + FMT_FALLTHROUGH; case ' ': - if (arg_type == type::none_type) return begin; + specs.sign = c == ' ' ? sign::space : sign::plus; + FMT_FALLTHROUGH; + case '-': enter_state(state::sign, in(arg_type, sint_set | float_set)); - switch (c) { - case '+': - specs.sign = sign::plus; - break; - case '-': - break; - case ' ': - specs.sign = sign::space; - break; - } ++begin; break; case '#': - if (arg_type == type::none_type) return begin; enter_state(state::hash, is_arithmetic_type(arg_type)); specs.alt = true; ++begin; break; case '0': enter_state(state::zero); - if (!is_arithmetic_type(arg_type)) { - if (arg_type == type::none_type) return begin; + if (!is_arithmetic_type(arg_type)) report_error("format specifier requires numeric argument"); - } if (specs.align == align::none) { // Ignore 0 if align is specified for compatibility with std::format. specs.align = align::numeric; @@ -2470,14 +2456,12 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end, begin = parse_dynamic_spec(begin, end, specs.width, specs.width_ref, ctx); break; case '.': - if (arg_type == type::none_type) return begin; enter_state(state::precision, in(arg_type, float_set | string_set | cstring_set)); begin = parse_precision(begin, end, specs.precision, specs.precision_ref, ctx); break; case 'L': - if (arg_type == type::none_type) return begin; enter_state(state::locale, is_arithmetic_type(arg_type)); specs.localized = true; ++begin; diff --git a/include/fmt/format.h b/include/fmt/format.h index b0976f47..33ed7034 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -2315,7 +2315,6 @@ FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { return format_decimal(out, abs_value, num_digits); } -// DEPRECATED! template FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end, format_specs& specs) -> const Char* { @@ -4068,12 +4067,16 @@ template struct nested_formatter { FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) -> decltype(ctx.begin()) { - auto specs = detail::dynamic_format_specs(); - auto it = parse_format_specs(ctx.begin(), ctx.end(), specs, ctx, - detail::type::none_type); - width_ = specs.width; + auto it = ctx.begin(), end = ctx.end(); + if (it == end) return it; + auto specs = format_specs(); + it = detail::parse_align(it, end, specs); fill_ = specs.fill; align_ = specs.align; + Char c = *it; + auto width_ref = detail::arg_ref(); + if ((c >= '0' && c <= '9') || c == '{') + it = detail::parse_dynamic_spec(it, end, width_, width_ref, ctx); ctx.advance_to(it); return formatter_.parse(ctx); }