diff --git a/include/fmt/base.h b/include/fmt/base.h index 9336cd3f..57750ca7 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -2282,8 +2282,8 @@ template constexpr auto is_name_start(Char c) -> bool { } template -FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end, - Handler&& handler) -> const Char* { +FMT_CONSTEXPR auto parse_arg_id(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { Char c = *begin; if (c >= '0' && c <= '9') { int index = 0; @@ -2309,25 +2309,10 @@ FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end, return it; } -template -FMT_CONSTEXPR auto parse_arg_id(const Char* begin, const Char* end, - Handler&& handler) -> const Char* { - FMT_ASSERT(begin != end, ""); - Char c = *begin; - if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler); - handler.on_auto(); - return begin; -} - template struct dynamic_spec_id_handler { basic_format_parse_context& ctx; arg_ref& ref; - FMT_CONSTEXPR void on_auto() { - int id = ctx.next_arg_id(); - ref = arg_ref(id); - ctx.check_dynamic_spec(id); - } FMT_CONSTEXPR void on_index(int id) { ref = arg_ref(id); ctx.check_arg_id(id); @@ -2354,8 +2339,17 @@ FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end, report_error("number is too big"); } else if (*begin == '{') { ++begin; - auto handler = dynamic_spec_id_handler{ctx, ref}; - if (begin != end) begin = parse_arg_id(begin, end, handler); + if (begin != end) { + Char c = *begin; + if (c == '}' || c == ':') { + int id = ctx.next_arg_id(); + ref = arg_ref(id); + ctx.check_dynamic_spec(id); + } else { + begin = + parse_arg_id(begin, end, dynamic_spec_id_handler{ctx, ref}); + } + } if (begin != end && *begin == '}') return ++begin; report_error("invalid format string"); } @@ -2563,39 +2557,53 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end, } template -FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end, - Handler&& handler) -> const Char* { - struct id_adapter { - Handler& handler; - int arg_id; - - FMT_CONSTEXPR void on_auto() { arg_id = handler.on_arg_id(); } - FMT_CONSTEXPR void on_index(int id) { arg_id = handler.on_arg_id(id); } - FMT_CONSTEXPR void on_name(basic_string_view id) { - arg_id = handler.on_arg_id(id); - } - }; - +FMT_CONSTEXPR FMT_INLINE auto parse_replacement_field(const Char* begin, + const Char* end, + Handler&& handler) + -> const Char* { ++begin; - if (begin == end) return handler.on_error("invalid format string"), end; - if (*begin == '}') { + if (begin == end) { + handler.on_error("invalid format string"); + return end; + } + int arg_id = 0; + switch (*begin) { + case '}': handler.on_replacement_field(handler.on_arg_id(), begin); - } else if (*begin == '{') { + return begin + 1; + case '{': handler.on_text(begin, begin + 1); - } else { - auto adapter = id_adapter{handler, 0}; + return begin + 1; + case ':': + arg_id = handler.on_arg_id(); + break; + default: { + struct id_adapter { + Handler& handler; + int arg_id; + + FMT_CONSTEXPR void on_index(int id) { arg_id = handler.on_arg_id(id); } + FMT_CONSTEXPR void on_name(basic_string_view id) { + arg_id = handler.on_arg_id(id); + } + } adapter = {handler, 0}; begin = parse_arg_id(begin, end, adapter); + arg_id = adapter.arg_id; Char c = begin != end ? *begin : Char(); if (c == '}') { - handler.on_replacement_field(adapter.arg_id, begin); - } else if (c == ':') { - begin = handler.on_format_specs(adapter.arg_id, begin + 1, end); - if (begin == end || *begin != '}') - return handler.on_error("unknown format specifier"), end; - } else { - return handler.on_error("missing '}' in format string"), end; + handler.on_replacement_field(arg_id, begin); + return begin + 1; } + if (c != ':') { + handler.on_error("missing '}' in format string"); + return end; + } + break; } + } + begin = handler.on_format_specs(arg_id, begin + 1, end); + if (begin == end || *begin != '}') + return handler.on_error("unknown format specifier"), end; return begin + 1; } diff --git a/test/base-test.cc b/test/base-test.cc index 4e2164a4..e03c5d91 100644 --- a/test/base-test.cc +++ b/test/base-test.cc @@ -481,14 +481,12 @@ TEST(arg_test, visit_invalid_arg) { #if FMT_USE_CONSTEXPR -enum class arg_id_result { none, empty, index, name }; +enum class arg_id_result { none, index, name }; struct test_arg_id_handler { arg_id_result res = arg_id_result::none; int index = 0; string_view name; - constexpr void on_auto() { res = arg_id_result::empty; } - constexpr void on_index(int i) { res = arg_id_result::index; index = i; @@ -508,8 +506,6 @@ constexpr test_arg_id_handler parse_arg_id(const char (&s)[N]) { } TEST(base_test, constexpr_parse_arg_id) { - static_assert(parse_arg_id(":").res == arg_id_result::empty, ""); - static_assert(parse_arg_id("}").res == arg_id_result::empty, ""); static_assert(parse_arg_id("42:").res == arg_id_result::index, ""); static_assert(parse_arg_id("42:").index == 42, ""); static_assert(parse_arg_id("foo:").res == arg_id_result::name, "");