forked from fmtlib/fmt
Simplify handling of dynamic specs
This commit is contained in:
@ -2283,10 +2283,8 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
// is not specified.
|
// is not specified.
|
||||||
auto buf = basic_memory_buffer<Char>();
|
auto buf = basic_memory_buffer<Char>();
|
||||||
auto out = basic_appender<Char>(buf);
|
auto out = basic_appender<Char>(buf);
|
||||||
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
|
detail::handle_dynamic_spec(specs.width, width_ref_, ctx);
|
||||||
ctx);
|
detail::handle_dynamic_spec(precision, precision_ref_, ctx);
|
||||||
detail::handle_dynamic_spec<detail::precision_checker>(precision,
|
|
||||||
precision_ref_, ctx);
|
|
||||||
if (begin == end || *begin == '}') {
|
if (begin == end || *begin == '}') {
|
||||||
out = detail::format_duration_value<Char>(out, d.count(), precision);
|
out = detail::format_duration_value<Char>(out, d.count(), precision);
|
||||||
detail::format_duration_unit<Char, Period>(out);
|
detail::format_duration_unit<Char, Period>(out);
|
||||||
@ -2392,8 +2390,7 @@ template <typename Char> struct formatter<std::tm, Char> {
|
|||||||
auto specs = specs_;
|
auto specs = specs_;
|
||||||
auto buf = basic_memory_buffer<Char>();
|
auto buf = basic_memory_buffer<Char>();
|
||||||
auto out = basic_appender<Char>(buf);
|
auto out = basic_appender<Char>(buf);
|
||||||
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
|
detail::handle_dynamic_spec(specs.width, width_ref_, ctx);
|
||||||
ctx);
|
|
||||||
|
|
||||||
auto loc_ref = ctx.locale();
|
auto loc_ref = ctx.locale();
|
||||||
detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
|
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)>
|
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");
|
if (is_negative(value)) report_error("negative width/precision");
|
||||||
return 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)>
|
||||||
FMT_CONSTEXPR auto operator()(T) -> unsigned long long {
|
FMT_CONSTEXPR auto operator()(T) -> unsigned long long {
|
||||||
report_error("width is not integer");
|
report_error("width/precision is not integer");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct precision_checker {
|
template <typename Context>
|
||||||
template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
|
FMT_CONSTEXPR auto get_dynamic_spec(basic_format_arg<Context> arg) -> int {
|
||||||
FMT_CONSTEXPR auto operator()(T value) -> unsigned long long {
|
unsigned long long value = arg.visit(dynamic_spec_getter());
|
||||||
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());
|
|
||||||
if (value > to_unsigned(max_value<int>())) report_error("number is too big");
|
if (value > to_unsigned(max_value<int>())) report_error("number is too big");
|
||||||
return static_cast<int>(value);
|
return static_cast<int>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Context, typename ID>
|
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);
|
auto arg = ctx.arg(id);
|
||||||
if (!arg) report_error("argument not found");
|
if (!arg) report_error("argument not found");
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Handler, typename Context>
|
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) {
|
||||||
@ -3727,10 +3713,10 @@ FMT_CONSTEXPR void handle_dynamic_spec(int& value,
|
|||||||
case arg_id_kind::none:
|
case arg_id_kind::none:
|
||||||
break;
|
break;
|
||||||
case arg_id_kind::index:
|
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;
|
break;
|
||||||
case arg_id_kind::name:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3987,10 +3973,8 @@ template <> struct formatter<bytes> {
|
|||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(bytes b, FormatContext& ctx) const -> decltype(ctx.out()) {
|
auto format(bytes b, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
auto specs = specs_;
|
auto specs = specs_;
|
||||||
detail::handle_dynamic_spec<detail::width_checker>(specs.width,
|
detail::handle_dynamic_spec(specs.width, specs.width_ref, ctx);
|
||||||
specs.width_ref, ctx);
|
detail::handle_dynamic_spec(specs.precision, specs.precision_ref, ctx);
|
||||||
detail::handle_dynamic_spec<detail::precision_checker>(
|
|
||||||
specs.precision, specs.precision_ref, ctx);
|
|
||||||
return detail::write_bytes<char>(ctx.out(), b.data_, specs);
|
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
|
auto format(group_digits_view<T> t, FormatContext& ctx) const
|
||||||
-> decltype(ctx.out()) {
|
-> decltype(ctx.out()) {
|
||||||
auto specs = specs_;
|
auto specs = specs_;
|
||||||
detail::handle_dynamic_spec<detail::width_checker>(specs.width,
|
detail::handle_dynamic_spec(specs.width, specs.width_ref, ctx);
|
||||||
specs.width_ref, ctx);
|
detail::handle_dynamic_spec(specs.precision, specs.precision_ref, ctx);
|
||||||
detail::handle_dynamic_spec<detail::precision_checker>(
|
|
||||||
specs.precision, specs.precision_ref, ctx);
|
|
||||||
auto arg = detail::make_write_int_arg(t.value, specs.sign);
|
auto arg = detail::make_write_int_arg(t.value, specs.sign);
|
||||||
return detail::write_int(
|
return detail::write_int(
|
||||||
ctx.out(), static_cast<detail::uint64_or_128_t<T>>(arg.abs_value),
|
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();
|
return parse_context.begin();
|
||||||
auto specs = detail::dynamic_format_specs<Char>();
|
auto specs = detail::dynamic_format_specs<Char>();
|
||||||
begin = parse_format_specs(begin, end, specs, parse_context, arg.type());
|
begin = parse_format_specs(begin, end, specs, parse_context, arg.type());
|
||||||
detail::handle_dynamic_spec<detail::width_checker>(
|
detail::handle_dynamic_spec(specs.width, specs.width_ref, context);
|
||||||
specs.width, specs.width_ref, context);
|
detail::handle_dynamic_spec(specs.precision, specs.precision_ref,
|
||||||
detail::handle_dynamic_spec<detail::precision_checker>(
|
context);
|
||||||
specs.precision, specs.precision_ref, context);
|
|
||||||
if (begin == end || *begin != '}')
|
if (begin == end || *begin != '}')
|
||||||
report_error("missing '}' in format string");
|
report_error("missing '}' in format string");
|
||||||
context.advance_to(arg.visit(
|
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());
|
return write<Char>(ctx.out(), val, specs_, ctx.locale());
|
||||||
}
|
}
|
||||||
auto specs = specs_;
|
auto specs = specs_;
|
||||||
handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx);
|
handle_dynamic_spec(specs.width, specs.width_ref, ctx);
|
||||||
handle_dynamic_spec<precision_checker>(specs.precision, specs.precision_ref,
|
handle_dynamic_spec(specs.precision, specs.precision_ref, ctx);
|
||||||
ctx);
|
|
||||||
return write<Char>(ctx.out(), val, specs, ctx.locale());
|
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()
|
!path_type_ ? p.native()
|
||||||
: p.generic_string<std::filesystem::path::value_type>();
|
: p.generic_string<std::filesystem::path::value_type>();
|
||||||
|
|
||||||
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
|
detail::handle_dynamic_spec(specs.width, width_ref_, ctx);
|
||||||
ctx);
|
|
||||||
if (!debug_) {
|
if (!debug_) {
|
||||||
auto s = detail::get_path_string<Char>(p, path_string);
|
auto s = detail::get_path_string<Char>(p, path_string);
|
||||||
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
|
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_;
|
auto specs = specs_;
|
||||||
if (specs.width_ref.kind != detail::arg_id_kind::none ||
|
if (specs.width_ref.kind != detail::arg_id_kind::none ||
|
||||||
specs.precision_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,
|
detail::handle_dynamic_spec(specs.width, specs.width_ref, ctx);
|
||||||
specs.width_ref, ctx);
|
detail::handle_dynamic_spec(specs.precision, specs.precision_ref, ctx);
|
||||||
detail::handle_dynamic_spec<detail::precision_checker>(
|
|
||||||
specs.precision, specs.precision_ref, ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (specs.width == 0) return do_format(c, specs, ctx, ctx.out());
|
if (specs.width == 0) return do_format(c, specs, ctx, ctx.out());
|
||||||
|
@ -897,11 +897,11 @@ 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");
|
"negative width/precision");
|
||||||
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, "number is too big");
|
||||||
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");
|
"negative width/precision");
|
||||||
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)),
|
||||||
@ -911,9 +911,9 @@ TEST(format_test, runtime_width) {
|
|||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
|
|
||||||
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 is not integer");
|
"width/precision is not integer");
|
||||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, 0.0), format_error,
|
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}}", -42, 4), " -42");
|
||||||
EXPECT_EQ(fmt::format("{0:{1}}", 42u, 5), " 42");
|
EXPECT_EQ(fmt::format("{0:{1}}", 42u, 5), " 42");
|
||||||
@ -1118,11 +1118,11 @@ 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 precision");
|
format_error, "negative width/precision");
|
||||||
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, "number is too big");
|
||||||
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 precision");
|
format_error, "negative width/precision");
|
||||||
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)),
|
||||||
@ -1132,9 +1132,9 @@ TEST(format_test, runtime_precision) {
|
|||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
|
|
||||||
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, "precision is not integer");
|
format_error, "width/precision is not integer");
|
||||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0.0, 0.0),
|
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,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42, 2), format_error,
|
||||||
"invalid format specifier");
|
"invalid format specifier");
|
||||||
|
Reference in New Issue
Block a user