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

View File

@ -897,18 +897,18 @@ TEST(format_test, runtime_width) {
"invalid format string");
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)),
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,
"negative width/precision");
"width/precision is out of range");
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)),
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)),
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,
"width/precision is not integer");
@ -1118,18 +1118,18 @@ TEST(format_test, runtime_precision) {
"invalid format string");
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)),
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),
format_error, "negative width/precision");
format_error, "width/precision is out of range");
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)),
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)),
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'),
format_error, "width/precision is not integer");