diff --git a/include/fmt/core.h b/include/fmt/core.h index 34e60da8..d15916d5 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -2190,7 +2190,8 @@ template struct arg_ref { // Format specifiers with width and precision resolved at formatting rather // than parsing time to allow reusing the same parsed specifiers with // different sets of arguments (precompilation of format strings). -template struct dynamic_format_specs : format_specs { +template +struct dynamic_format_specs : format_specs { arg_ref width_ref; arg_ref precision_ref; }; @@ -2461,25 +2462,19 @@ FMT_CONSTEXPR inline void require_numeric_argument(type arg_type) { throw_format_error("format specifier requires numeric argument"); } -template struct parse_format_specs_result { - const Char* end; - dynamic_format_specs specs; -}; - // Parses standard format specifiers. template FMT_CONSTEXPR FMT_INLINE auto parse_format_specs( - const Char* begin, const Char* end, basic_format_parse_context& ctx, - type arg_type) -> parse_format_specs_result { - auto specs = dynamic_format_specs(); + const Char* begin, const Char* end, dynamic_format_specs& specs, + basic_format_parse_context& ctx, type arg_type) -> const Char* { if (1 < end - begin && begin[1] == '}' && is_ascii_letter(*begin) && *begin != 'L') { specs.type = parse_presentation_type(*begin++); if (specs.type == presentation_type::none) throw_format_error("invalid type specifier"); - return {begin, specs}; + return begin; } - if (begin == end) return {begin, specs}; + if (begin == end) return begin; auto align = parse_align(begin, end); if (align.align != align::none) { @@ -2488,7 +2483,7 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs( if (fill_size > 0) specs.fill = {begin, to_unsigned(fill_size)}; } begin = align.end; - if (begin == end) return {begin, specs}; + if (begin == end) return begin; // Parse sign. switch (to_ascii(*begin)) { @@ -2515,12 +2510,12 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs( throw_format_error("format specifier requires signed argument"); } } - if (begin == end) return {begin, specs}; + if (begin == end) return begin; if (*begin == '#') { require_numeric_argument(arg_type); specs.alt = true; - if (++begin == end) return {begin, specs}; + if (++begin == end) return begin; } // Parse zero flag. @@ -2531,11 +2526,11 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs( specs.align = align::numeric; specs.fill[0] = Char('0'); } - if (++begin == end) return {begin, specs}; + if (++begin == end) return begin; } begin = parse_dynamic_spec(begin, end, specs.width, specs.width_ref, ctx); - if (begin == end) return {begin, specs}; + if (begin == end) return begin; // Parse precision. if (*begin == '.') { @@ -2543,7 +2538,7 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs( parse_precision(begin, end, specs.precision, specs.precision_ref, ctx); if (is_integral_type(arg_type) || arg_type == type::pointer_type) throw_format_error("precision not allowed for this argument type"); - if (begin == end) return {begin, specs}; + if (begin == end) return begin; } if (*begin == 'L') { @@ -2558,7 +2553,7 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs( if (specs.type == presentation_type::none) throw_format_error("invalid type specifier"); } - return {begin, specs}; + return begin; } template @@ -2911,8 +2906,7 @@ struct formatter::value; - auto result = detail::parse_format_specs(begin, end, ctx, type); - specs_ = result.specs; + begin = detail::parse_format_specs(begin, end, specs_, ctx, type); auto eh = detail::error_handler(); switch (type) { case detail::type::none_type: @@ -2937,19 +2931,19 @@ struct formatter::value, diff --git a/include/fmt/format.h b/include/fmt/format.h index 8dbe3253..214273fa 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3871,16 +3871,15 @@ class bytes { template <> struct formatter { private: - detail::dynamic_format_specs specs_; + detail::dynamic_format_specs<> specs_; public: template FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - auto result = parse_format_specs(ctx.begin(), ctx.end(), ctx, - detail::type::string_type); - specs_ = result.specs; + auto end = parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, + detail::type::string_type); detail::check_string_type_spec(specs_.type, detail::error_handler()); - return result.end; + return end; } template @@ -3913,16 +3912,15 @@ template auto group_digits(T value) -> group_digits_view { template struct formatter> : formatter { private: - detail::dynamic_format_specs specs_; + detail::dynamic_format_specs<> specs_; public: template FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - auto result = - parse_format_specs(ctx.begin(), ctx.end(), ctx, detail::type::int_type); - specs_ = result.specs; + auto end = parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, + detail::type::int_type); detail::check_string_type_spec(specs_.type, detail::error_handler()); - return result.end; + return end; } template @@ -4139,16 +4137,15 @@ void vformat_to(buffer& buf, basic_string_view fmt, visit_format_arg(custom_formatter{parse_context, context}, arg); return parse_context.begin(); } - auto result = parse_format_specs(begin, end, parse_context, arg.type()); + auto specs = detail::dynamic_format_specs(); + begin = parse_format_specs(begin, end, specs, parse_context, arg.type()); detail::handle_dynamic_spec( - result.specs.width, result.specs.width_ref, context); + specs.width, specs.width_ref, context); detail::handle_dynamic_spec( - result.specs.precision, result.specs.precision_ref, context); - begin = result.end; + specs.precision, specs.precision_ref, context); if (begin == end || *begin != '}') on_error("missing '}' in format string"); - auto f = - arg_formatter{context.out(), result.specs, context.locale()}; + auto f = arg_formatter{context.out(), specs, context.locale()}; context.advance_to(visit_format_arg(f, arg)); return begin; } diff --git a/test/core-test.cc b/test/core-test.cc index 84dda8f4..f66cc8ae 100644 --- a/test/core-test.cc +++ b/test/core-test.cc @@ -523,9 +523,10 @@ TEST(format_test, constexpr_parse_arg_id) { template constexpr auto parse_test_specs(const char (&s)[N]) { auto ctx = fmt::detail::compile_parse_context(fmt::string_view(s, N), 43, nullptr); - auto result = fmt::detail::parse_format_specs(s, s + N - 1, ctx, - fmt::detail::type::float_type); - return result.specs; + auto specs = fmt::detail::dynamic_format_specs<>(); + fmt::detail::parse_format_specs(s, s + N - 1, specs, ctx, + fmt::detail::type::float_type); + return specs; } TEST(core_test, constexpr_parse_format_specs) { diff --git a/test/xchar-test.cc b/test/xchar-test.cc index af26653f..c118a482 100644 --- a/test/xchar-test.cc +++ b/test/xchar-test.cc @@ -518,11 +518,10 @@ template struct formatter, charT> { public: FMT_CONSTEXPR typename basic_format_parse_context::iterator parse( basic_format_parse_context& ctx) { - auto result = parse_format_specs(ctx.begin(), ctx.end(), ctx, - detail::type::string_type); - specs_ = result.specs; + auto end = parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, + detail::type::string_type); detail::parse_float_type_spec(specs_, detail::error_handler()); - return result.end; + return end; } template