Simplify handling of dynamic specs

This commit is contained in:
Victor Zverovich
2024-08-04 09:09:01 -07:00
parent 7891699737
commit 928a07bb04
2 changed files with 19 additions and 29 deletions

View File

@ -3680,8 +3680,7 @@ template <typename Char> struct arg_formatter {
struct dynamic_spec_getter { struct dynamic_spec_getter {
template <typename T, FMT_ENABLE_IF(is_integer<T>::value)> template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { FMT_CONSTEXPR auto operator()(T value) -> unsigned long long {
if (is_negative(value)) report_error("negative width/precision"); return is_negative(value) ? ~0ull : static_cast<unsigned long long>(value);
return static_cast<unsigned long long>(value);
} }
template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)> template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
@ -3691,13 +3690,6 @@ struct dynamic_spec_getter {
} }
}; };
template <typename Context>
FMT_CONSTEXPR auto get_dynamic_spec(basic_format_arg<Context> arg) -> int {
unsigned long long value = arg.visit(dynamic_spec_getter());
if (value > to_unsigned(max_value<int>())) report_error("number is too big");
return static_cast<int>(value);
}
template <typename Context, typename ID> template <typename Context, typename ID>
FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> basic_format_arg<Context> { FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> basic_format_arg<Context> {
auto arg = ctx.arg(id); auto arg = ctx.arg(id);
@ -3709,16 +3701,14 @@ template <typename Context>
FMT_CONSTEXPR void handle_dynamic_spec(int& value, FMT_CONSTEXPR void handle_dynamic_spec(int& value,
arg_ref<typename Context::char_type> ref, arg_ref<typename Context::char_type> ref,
Context& ctx) { Context& ctx) {
switch (ref.kind) { if (ref.kind == arg_id_kind::none) return;
case arg_id_kind::none: auto arg = ref.kind == arg_id_kind::index ? ctx.arg(ref.val.index)
break; : ctx.arg(ref.val.name);
case arg_id_kind::index: if (!arg) report_error("argument not found");
value = get_dynamic_spec(get_arg(ctx, ref.val.index)); unsigned long long arg_value = arg.visit(dynamic_spec_getter());
break; if (arg_value > to_unsigned(max_value<int>()))
case arg_id_kind::name: report_error("width/precision is out of range");
value = get_dynamic_spec(get_arg(ctx, ref.val.name)); value = static_cast<int>(arg_value);
break;
}
} }
#if FMT_USE_USER_DEFINED_LITERALS #if FMT_USE_USER_DEFINED_LITERALS

View File

@ -897,18 +897,18 @@ TEST(format_test, runtime_width) {
"invalid format string"); "invalid format string");
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, -1), format_error, EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, -1), format_error,
"negative width/precision"); "width/precision is out of range");
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1u)), EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1u)),
format_error, "number is too big"); format_error, "width/precision is out of range");
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, -1l), format_error, EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, -1l), format_error,
"negative width/precision"); "width/precision is out of range");
if (fmt::detail::const_check(sizeof(long) > sizeof(int))) { if (fmt::detail::const_check(sizeof(long) > sizeof(int))) {
long value = INT_MAX; long value = INT_MAX;
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (value + 1)), EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (value + 1)),
format_error, "number is too big"); format_error, "width/precision is out of range");
} }
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1ul)), EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1ul)),
format_error, "number is too big"); format_error, "width/precision is out of range");
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, '0'), format_error, EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, '0'), format_error,
"width/precision is not integer"); "width/precision is not integer");
@ -1118,18 +1118,18 @@ TEST(format_test, runtime_precision) {
"invalid format string"); "invalid format string");
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, -1), EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, -1),
format_error, "negative width/precision"); format_error, "width/precision is out of range");
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, (INT_MAX + 1u)), EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, (INT_MAX + 1u)),
format_error, "number is too big"); format_error, "width/precision is out of range");
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, -1l), EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, -1l),
format_error, "negative width/precision"); format_error, "width/precision is out of range");
if (fmt::detail::const_check(sizeof(long) > sizeof(int))) { if (fmt::detail::const_check(sizeof(long) > sizeof(int))) {
long value = INT_MAX; long value = INT_MAX;
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, (value + 1)), EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, (value + 1)),
format_error, "number is too big"); format_error, "width/precision is out of range");
} }
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, (INT_MAX + 1ul)), EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, (INT_MAX + 1ul)),
format_error, "number is too big"); format_error, "width/precision is out of range");
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, '0'), EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, '0'),
format_error, "width/precision is not integer"); format_error, "width/precision is not integer");