mirror of
https://github.com/fmtlib/fmt.git
synced 2025-03-14 13:20:51 +00:00
Simplify handling of dynamic specs
This commit is contained in:
parent
58aba5a3de
commit
7891699737
@ -2283,10 +2283,8 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||
// is not specified.
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
auto out = basic_appender<Char>(buf);
|
||||
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
|
||||
ctx);
|
||||
detail::handle_dynamic_spec<detail::precision_checker>(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<Char>(out, d.count(), precision);
|
||||
detail::format_duration_unit<Char, Period>(out);
|
||||
@ -2392,8 +2390,7 @@ template <typename Char> struct formatter<std::tm, Char> {
|
||||
auto specs = specs_;
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
auto out = basic_appender<Char>(buf);
|
||||
detail::handle_dynamic_spec<detail::width_checker>(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<bool>(loc_ref), loc_ref);
|
||||
|
@ -3677,49 +3677,35 @@ template <typename Char> struct arg_formatter {
|
||||
}
|
||||
};
|
||||
|
||||
struct width_checker {
|
||||
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");
|
||||
if (is_negative(value)) report_error("negative width/precision");
|
||||
return static_cast<unsigned long long>(value);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!is_integer<T>::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 <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 precision");
|
||||
return static_cast<unsigned long long>(value);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
|
||||
FMT_CONSTEXPR auto operator()(T) -> unsigned long long {
|
||||
report_error("precision is not integer");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Handler, typename FormatArg>
|
||||
FMT_CONSTEXPR auto get_dynamic_spec(FormatArg arg) -> int {
|
||||
unsigned long long value = arg.visit(Handler());
|
||||
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) -> decltype(ctx.arg(id)) {
|
||||
FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> basic_format_arg<Context> {
|
||||
auto arg = ctx.arg(id);
|
||||
if (!arg) report_error("argument not found");
|
||||
return arg;
|
||||
}
|
||||
|
||||
template <typename Handler, typename Context>
|
||||
template <typename Context>
|
||||
FMT_CONSTEXPR void handle_dynamic_spec(int& value,
|
||||
arg_ref<typename Context::char_type> 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<Handler>(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<Handler>(get_arg(ctx, ref.val.name));
|
||||
value = get_dynamic_spec(get_arg(ctx, ref.val.name));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3987,10 +3973,8 @@ template <> struct formatter<bytes> {
|
||||
template <typename FormatContext>
|
||||
auto format(bytes b, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
auto specs = specs_;
|
||||
detail::handle_dynamic_spec<detail::width_checker>(specs.width,
|
||||
specs.width_ref, ctx);
|
||||
detail::handle_dynamic_spec<detail::precision_checker>(
|
||||
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<char>(ctx.out(), b.data_, specs);
|
||||
}
|
||||
};
|
||||
@ -4028,10 +4012,8 @@ template <typename T> struct formatter<group_digits_view<T>> : formatter<T> {
|
||||
auto format(group_digits_view<T> t, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto specs = specs_;
|
||||
detail::handle_dynamic_spec<detail::width_checker>(specs.width,
|
||||
specs.width_ref, ctx);
|
||||
detail::handle_dynamic_spec<detail::precision_checker>(
|
||||
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<detail::uint64_or_128_t<T>>(arg.abs_value),
|
||||
@ -4196,10 +4178,9 @@ void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt,
|
||||
return parse_context.begin();
|
||||
auto specs = detail::dynamic_format_specs<Char>();
|
||||
begin = parse_format_specs(begin, end, specs, parse_context, arg.type());
|
||||
detail::handle_dynamic_spec<detail::width_checker>(
|
||||
specs.width, specs.width_ref, context);
|
||||
detail::handle_dynamic_spec<detail::precision_checker>(
|
||||
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<T, Char, TYPE>::format(
|
||||
return write<Char>(ctx.out(), val, specs_, ctx.locale());
|
||||
}
|
||||
auto specs = specs_;
|
||||
handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx);
|
||||
handle_dynamic_spec<precision_checker>(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<Char>(ctx.out(), val, specs, ctx.locale());
|
||||
}
|
||||
|
||||
|
@ -147,8 +147,7 @@ template <typename Char> struct formatter<std::filesystem::path, Char> {
|
||||
!path_type_ ? p.native()
|
||||
: p.generic_string<std::filesystem::path::value_type>();
|
||||
|
||||
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
|
||||
ctx);
|
||||
detail::handle_dynamic_spec(specs.width, width_ref_, ctx);
|
||||
if (!debug_) {
|
||||
auto s = detail::get_path_string<Char>(p, path_string);
|
||||
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
|
||||
@ -672,10 +671,8 @@ template <typename T, typename Char> struct formatter<std::complex<T>, 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<detail::width_checker>(specs.width,
|
||||
specs.width_ref, ctx);
|
||||
detail::handle_dynamic_spec<detail::precision_checker>(
|
||||
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());
|
||||
|
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user