Simplify fill and alignment parsing

This commit is contained in:
Victor Zverovich 2022-12-23 10:12:05 -08:00
parent 040dc2a5d4
commit bde1a6070d
4 changed files with 31 additions and 23 deletions

View File

@ -2020,10 +2020,6 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
}
void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) {
f.specs.fill = fill;
}
FMT_CONSTEXPR void on_align(align_t align) { f.specs.align = align; }
FMT_CONSTEXPR void on_width(int width) { f.specs.width = width; }
FMT_CONSTEXPR void on_precision(int _precision) {
f.precision = _precision;
@ -2048,8 +2044,11 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
FMT_CONSTEXPR parse_range do_parse(basic_format_parse_context<Char>& ctx) {
auto begin = ctx.begin(), end = ctx.end();
if (begin == end || *begin == '}') return {begin, begin};
spec_handler handler{*this, ctx, format_str};
begin = detail::parse_align(begin, end, handler);
auto handler = spec_handler{*this, ctx, format_str};
auto result = detail::parse_align(begin, end);
begin = result.end;
specs.align = result.align;
if (result.fill.size() != 0) specs.fill = result.fill;
if (begin == end) return {begin, begin};
begin = detail::parse_width(begin, end, handler);
if (begin == end) return {begin, begin};

View File

@ -2362,11 +2362,18 @@ FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end,
: error_value;
}
// Parses fill and alignment.
template <typename Char, typename Handler>
FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
Handler&& handler) -> const Char* {
template <typename Char> struct parse_align_result {
const Char* end;
basic_string_view<Char> fill;
align_t align;
};
// Parses [[fill]align].
template <typename Char>
FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end)
-> parse_align_result<Char> {
FMT_ASSERT(begin != end, "");
auto fill = basic_string_view<Char>();
auto align = align::none;
auto p = begin + code_point_length(begin);
if (end - p <= 0) p = begin;
@ -2381,27 +2388,27 @@ FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
case '^':
align = align::center;
break;
default:
break;
}
if (align != align::none) {
if (p != begin) {
auto c = *begin;
if (c == '{')
return handler.on_error("invalid fill character '{'"), begin;
if (c == '}') return begin;
handler.on_fill(basic_string_view<Char>(begin, to_unsigned(p - begin)));
if (c == '}') return {begin, {}, align::none};
if (c == '{') {
throw_format_error("invalid fill character '{'");
return {begin, {}, align::none};
}
fill = {begin, to_unsigned(p - begin)};
begin = p + 1;
} else
} else {
++begin;
handler.on_align(align);
}
break;
} else if (p == begin) {
break;
}
p = begin;
}
return begin;
return {begin, fill, align};
}
template <typename Char> FMT_CONSTEXPR bool is_name_start(Char c) {
@ -2581,7 +2588,12 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin,
if (begin == end) return begin;
begin = parse_align(begin, end, handler);
auto result = parse_align(begin, end);
begin = result.end;
if (result.align != align::none) {
if (result.fill.size() != 0) handler.on_fill(result.fill);
handler.on_align(result.align);
}
if (begin == end) return begin;
// Parse sign.

View File

@ -586,7 +586,6 @@ TEST(core_test, constexpr_parse_format_specs) {
static_assert(parse_test_specs(".42").precision == 42, "");
static_assert(parse_test_specs(".{42}").precision_ref.val.index == 42, "");
static_assert(parse_test_specs("d").type == fmt::presentation_type::dec, "");
static_assert(parse_test_specs("{<").res == handler::error, "");
}
struct test_parse_context {
@ -652,7 +651,6 @@ TEST(format_test, constexpr_specs_checker) {
static_assert(check_specs(".42").precision == 42, "");
static_assert(check_specs(".{42}").precision_ref.val.index == 42, "");
static_assert(check_specs("d").type == fmt::presentation_type::dec, "");
static_assert(check_specs("{<").res == handler::error, "");
}
struct test_format_string_handler {

View File

@ -2214,7 +2214,6 @@ TEST(format_test, format_string_errors) {
EXPECT_ERROR("{0:s", "unknown format specifier", date);
# if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1916
// This causes an detail compiler error in MSVC2017.
EXPECT_ERROR("{:{<}", "invalid fill character '{'", int);
EXPECT_ERROR("{:10000000000}", "number is too big", int);
EXPECT_ERROR("{:.10000000000}", "number is too big", int);
EXPECT_ERROR_NOARGS("{:x}", "argument not found");