mirror of
https://github.com/fmtlib/fmt.git
synced 2025-04-03 16:20:22 +00:00
Improve parsing
This commit is contained in:
parent
bdc45eef76
commit
524ca1c715
@ -2282,7 +2282,7 @@ template <typename Char> constexpr auto is_name_start(Char c) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename Handler>
|
template <typename Char, typename Handler>
|
||||||
FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end,
|
FMT_CONSTEXPR auto parse_arg_id(const Char* begin, const Char* end,
|
||||||
Handler&& handler) -> const Char* {
|
Handler&& handler) -> const Char* {
|
||||||
Char c = *begin;
|
Char c = *begin;
|
||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
@ -2309,25 +2309,10 @@ FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end,
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename Handler>
|
|
||||||
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 <typename Char> struct dynamic_spec_id_handler {
|
template <typename Char> struct dynamic_spec_id_handler {
|
||||||
basic_format_parse_context<Char>& ctx;
|
basic_format_parse_context<Char>& ctx;
|
||||||
arg_ref<Char>& ref;
|
arg_ref<Char>& ref;
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_auto() {
|
|
||||||
int id = ctx.next_arg_id();
|
|
||||||
ref = arg_ref<Char>(id);
|
|
||||||
ctx.check_dynamic_spec(id);
|
|
||||||
}
|
|
||||||
FMT_CONSTEXPR void on_index(int id) {
|
FMT_CONSTEXPR void on_index(int id) {
|
||||||
ref = arg_ref<Char>(id);
|
ref = arg_ref<Char>(id);
|
||||||
ctx.check_arg_id(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");
|
report_error("number is too big");
|
||||||
} else if (*begin == '{') {
|
} else if (*begin == '{') {
|
||||||
++begin;
|
++begin;
|
||||||
auto handler = dynamic_spec_id_handler<Char>{ctx, ref};
|
if (begin != end) {
|
||||||
if (begin != end) begin = parse_arg_id(begin, end, handler);
|
Char c = *begin;
|
||||||
|
if (c == '}' || c == ':') {
|
||||||
|
int id = ctx.next_arg_id();
|
||||||
|
ref = arg_ref<Char>(id);
|
||||||
|
ctx.check_dynamic_spec(id);
|
||||||
|
} else {
|
||||||
|
begin =
|
||||||
|
parse_arg_id(begin, end, dynamic_spec_id_handler<Char>{ctx, ref});
|
||||||
|
}
|
||||||
|
}
|
||||||
if (begin != end && *begin == '}') return ++begin;
|
if (begin != end && *begin == '}') return ++begin;
|
||||||
report_error("invalid format string");
|
report_error("invalid format string");
|
||||||
}
|
}
|
||||||
@ -2563,39 +2557,53 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename Handler>
|
template <typename Char, typename Handler>
|
||||||
FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end,
|
FMT_CONSTEXPR FMT_INLINE auto parse_replacement_field(const Char* begin,
|
||||||
Handler&& handler) -> const Char* {
|
const Char* end,
|
||||||
|
Handler&& handler)
|
||||||
|
-> const Char* {
|
||||||
|
++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);
|
||||||
|
return begin + 1;
|
||||||
|
case '{':
|
||||||
|
handler.on_text(begin, begin + 1);
|
||||||
|
return begin + 1;
|
||||||
|
case ':':
|
||||||
|
arg_id = handler.on_arg_id();
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
struct id_adapter {
|
struct id_adapter {
|
||||||
Handler& handler;
|
Handler& handler;
|
||||||
int arg_id;
|
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_index(int id) { arg_id = handler.on_arg_id(id); }
|
||||||
FMT_CONSTEXPR void on_name(basic_string_view<Char> id) {
|
FMT_CONSTEXPR void on_name(basic_string_view<Char> id) {
|
||||||
arg_id = handler.on_arg_id(id);
|
arg_id = handler.on_arg_id(id);
|
||||||
}
|
}
|
||||||
};
|
} adapter = {handler, 0};
|
||||||
|
|
||||||
++begin;
|
|
||||||
if (begin == end) return handler.on_error("invalid format string"), end;
|
|
||||||
if (*begin == '}') {
|
|
||||||
handler.on_replacement_field(handler.on_arg_id(), begin);
|
|
||||||
} else if (*begin == '{') {
|
|
||||||
handler.on_text(begin, begin + 1);
|
|
||||||
} else {
|
|
||||||
auto adapter = id_adapter{handler, 0};
|
|
||||||
begin = parse_arg_id(begin, end, adapter);
|
begin = parse_arg_id(begin, end, adapter);
|
||||||
|
arg_id = adapter.arg_id;
|
||||||
Char c = begin != end ? *begin : Char();
|
Char c = begin != end ? *begin : Char();
|
||||||
if (c == '}') {
|
if (c == '}') {
|
||||||
handler.on_replacement_field(adapter.arg_id, begin);
|
handler.on_replacement_field(arg_id, begin);
|
||||||
} else if (c == ':') {
|
return begin + 1;
|
||||||
begin = handler.on_format_specs(adapter.arg_id, begin + 1, end);
|
}
|
||||||
|
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 != '}')
|
if (begin == end || *begin != '}')
|
||||||
return handler.on_error("unknown format specifier"), end;
|
return handler.on_error("unknown format specifier"), end;
|
||||||
} else {
|
|
||||||
return handler.on_error("missing '}' in format string"), end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return begin + 1;
|
return begin + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,14 +481,12 @@ TEST(arg_test, visit_invalid_arg) {
|
|||||||
|
|
||||||
#if FMT_USE_CONSTEXPR
|
#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 {
|
struct test_arg_id_handler {
|
||||||
arg_id_result res = arg_id_result::none;
|
arg_id_result res = arg_id_result::none;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
string_view name;
|
string_view name;
|
||||||
|
|
||||||
constexpr void on_auto() { res = arg_id_result::empty; }
|
|
||||||
|
|
||||||
constexpr void on_index(int i) {
|
constexpr void on_index(int i) {
|
||||||
res = arg_id_result::index;
|
res = arg_id_result::index;
|
||||||
index = i;
|
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) {
|
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:").res == arg_id_result::index, "");
|
||||||
static_assert(parse_arg_id("42:").index == 42, "");
|
static_assert(parse_arg_id("42:").index == 42, "");
|
||||||
static_assert(parse_arg_id("foo:").res == arg_id_result::name, "");
|
static_assert(parse_arg_id("foo:").res == arg_id_result::name, "");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user