diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 1fc3f1f5..06b20933 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -2283,10 +2283,8 @@ struct formatter, Char> { // is not specified. auto buf = basic_memory_buffer(); auto out = basic_appender(buf); - detail::handle_dynamic_spec(specs.width, width_ref_, - ctx); - detail::handle_dynamic_spec(precision, - precision_ref_, ctx); + detail::handle_dynamic_spec(specs.width, width_ref_, ctx); + detail::handle_dynamic_spec(precision, precision_ref_, ctx); if (begin == end || *begin == '}') { out = detail::format_duration_value(out, d.count(), precision); detail::format_duration_unit(out); @@ -2392,8 +2390,7 @@ template struct formatter { auto specs = specs_; auto buf = basic_memory_buffer(); auto out = basic_appender(buf); - detail::handle_dynamic_spec(specs.width, width_ref_, - ctx); + detail::handle_dynamic_spec(specs.width, width_ref_, ctx); auto loc_ref = ctx.locale(); detail::get_locale loc(static_cast(loc_ref), loc_ref); diff --git a/include/fmt/format.h b/include/fmt/format.h index 76e3b880..cb35ab2d 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3677,49 +3677,35 @@ template struct arg_formatter { } }; -struct width_checker { +struct dynamic_spec_getter { template ::value)> FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { - if (is_negative(value)) report_error("negative width"); + if (is_negative(value)) report_error("negative width/precision"); return static_cast(value); } template ::value)> FMT_CONSTEXPR auto operator()(T) -> unsigned long long { - report_error("width is not integer"); + report_error("width/precision is not integer"); return 0; } }; -struct precision_checker { - template ::value)> - FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { - if (is_negative(value)) report_error("negative precision"); - return static_cast(value); - } - - template ::value)> - FMT_CONSTEXPR auto operator()(T) -> unsigned long long { - report_error("precision is not integer"); - return 0; - } -}; - -template -FMT_CONSTEXPR auto get_dynamic_spec(FormatArg arg) -> int { - unsigned long long value = arg.visit(Handler()); +template +FMT_CONSTEXPR auto get_dynamic_spec(basic_format_arg arg) -> int { + unsigned long long value = arg.visit(dynamic_spec_getter()); if (value > to_unsigned(max_value())) report_error("number is too big"); return static_cast(value); } template -FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> decltype(ctx.arg(id)) { +FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> basic_format_arg { auto arg = ctx.arg(id); if (!arg) report_error("argument not found"); return arg; } -template +template FMT_CONSTEXPR void handle_dynamic_spec(int& value, arg_ref ref, Context& ctx) { @@ -3727,10 +3713,10 @@ FMT_CONSTEXPR void handle_dynamic_spec(int& value, case arg_id_kind::none: break; case arg_id_kind::index: - value = detail::get_dynamic_spec(get_arg(ctx, ref.val.index)); + value = get_dynamic_spec(get_arg(ctx, ref.val.index)); break; case arg_id_kind::name: - value = detail::get_dynamic_spec(get_arg(ctx, ref.val.name)); + value = get_dynamic_spec(get_arg(ctx, ref.val.name)); break; } } @@ -3987,10 +3973,8 @@ template <> struct formatter { template auto format(bytes b, FormatContext& ctx) const -> decltype(ctx.out()) { auto specs = specs_; - detail::handle_dynamic_spec(specs.width, - specs.width_ref, ctx); - detail::handle_dynamic_spec( - specs.precision, specs.precision_ref, ctx); + detail::handle_dynamic_spec(specs.width, specs.width_ref, ctx); + detail::handle_dynamic_spec(specs.precision, specs.precision_ref, ctx); return detail::write_bytes(ctx.out(), b.data_, specs); } }; @@ -4028,10 +4012,8 @@ template struct formatter> : formatter { auto format(group_digits_view t, FormatContext& ctx) const -> decltype(ctx.out()) { auto specs = specs_; - detail::handle_dynamic_spec(specs.width, - specs.width_ref, ctx); - detail::handle_dynamic_spec( - specs.precision, specs.precision_ref, ctx); + detail::handle_dynamic_spec(specs.width, specs.width_ref, ctx); + detail::handle_dynamic_spec(specs.precision, specs.precision_ref, ctx); auto arg = detail::make_write_int_arg(t.value, specs.sign); return detail::write_int( ctx.out(), static_cast>(arg.abs_value), @@ -4196,10 +4178,9 @@ void vformat_to(buffer& buf, basic_string_view fmt, return parse_context.begin(); auto specs = detail::dynamic_format_specs(); begin = parse_format_specs(begin, end, specs, parse_context, arg.type()); - detail::handle_dynamic_spec( - specs.width, specs.width_ref, context); - detail::handle_dynamic_spec( - specs.precision, specs.precision_ref, context); + detail::handle_dynamic_spec(specs.width, specs.width_ref, context); + detail::handle_dynamic_spec(specs.precision, specs.precision_ref, + context); if (begin == end || *begin != '}') report_error("missing '}' in format string"); context.advance_to(arg.visit( @@ -4237,9 +4218,8 @@ FMT_CONSTEXPR FMT_INLINE auto native_formatter::format( return write(ctx.out(), val, specs_, ctx.locale()); } auto specs = specs_; - handle_dynamic_spec(specs.width, specs.width_ref, ctx); - handle_dynamic_spec(specs.precision, specs.precision_ref, - ctx); + handle_dynamic_spec(specs.width, specs.width_ref, ctx); + handle_dynamic_spec(specs.precision, specs.precision_ref, ctx); return write(ctx.out(), val, specs, ctx.locale()); } diff --git a/include/fmt/std.h b/include/fmt/std.h index 0695460c..8629ee14 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -147,8 +147,7 @@ template struct formatter { !path_type_ ? p.native() : p.generic_string(); - detail::handle_dynamic_spec(specs.width, width_ref_, - ctx); + detail::handle_dynamic_spec(specs.width, width_ref_, ctx); if (!debug_) { auto s = detail::get_path_string(p, path_string); return detail::write(ctx.out(), basic_string_view(s), specs); @@ -672,10 +671,8 @@ template struct formatter, Char> { auto specs = specs_; if (specs.width_ref.kind != detail::arg_id_kind::none || specs.precision_ref.kind != detail::arg_id_kind::none) { - detail::handle_dynamic_spec(specs.width, - specs.width_ref, ctx); - detail::handle_dynamic_spec( - specs.precision, specs.precision_ref, ctx); + detail::handle_dynamic_spec(specs.width, specs.width_ref, ctx); + detail::handle_dynamic_spec(specs.precision, specs.precision_ref, ctx); } if (specs.width == 0) return do_format(c, specs, ctx, ctx.out()); diff --git a/test/format-test.cc b/test/format-test.cc index 62d082a7..32f03ec5 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -897,11 +897,11 @@ TEST(format_test, runtime_width) { "invalid format string"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, -1), format_error, - "negative width"); + "negative width/precision"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1u)), format_error, "number is too big"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, -1l), format_error, - "negative width"); + "negative width/precision"); if (fmt::detail::const_check(sizeof(long) > sizeof(int))) { long value = INT_MAX; EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (value + 1)), @@ -911,9 +911,9 @@ TEST(format_test, runtime_width) { format_error, "number is too big"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, '0'), format_error, - "width is not integer"); + "width/precision is not integer"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, 0.0), format_error, - "width is not integer"); + "width/precision is not integer"); EXPECT_EQ(fmt::format("{0:{1}}", -42, 4), " -42"); EXPECT_EQ(fmt::format("{0:{1}}", 42u, 5), " 42"); @@ -1118,11 +1118,11 @@ TEST(format_test, runtime_precision) { "invalid format string"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, -1), - format_error, "negative precision"); + format_error, "negative width/precision"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, (INT_MAX + 1u)), format_error, "number is too big"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, -1l), - format_error, "negative precision"); + format_error, "negative width/precision"); if (fmt::detail::const_check(sizeof(long) > sizeof(int))) { long value = INT_MAX; EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, (value + 1)), @@ -1132,9 +1132,9 @@ TEST(format_test, runtime_precision) { format_error, "number is too big"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, '0'), - format_error, "precision is not integer"); + format_error, "width/precision is not integer"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, 0.0), - format_error, "precision is not integer"); + format_error, "width/precision is not integer"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42, 2), format_error, "invalid format specifier");