This commit is contained in:
js324 2024-03-03 06:46:38 -08:00 committed by GitHub
commit 8ff5ea29ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 63 additions and 6 deletions

View File

@ -13,7 +13,7 @@
#include <tuple>
#include <type_traits>
#include "base.h"
#include "format.h"
FMT_BEGIN_NAMESPACE
@ -388,6 +388,8 @@ struct range_formatter<
detail::string_literal<Char, '['>{};
basic_string_view<Char> closing_bracket_ =
detail::string_literal<Char, ']'>{};
bool is_string_format = false;
bool is_debug = false;
public:
FMT_CONSTEXPR range_formatter() {}
@ -414,29 +416,79 @@ struct range_formatter<
if (it != end && *it == 'n') {
set_brackets({}, {});
++it;
} else {
bool check_for_s = false;
if (it != end && *it == '?') {
++it;
detail::maybe_set_debug_format(underlying_, true);
set_brackets({}, {});
check_for_s = true;
is_debug = true;
}
if (it != end && *it == 's') {
if (!std::is_same<T, Char>::value) {
report_error("invalid format specifier");
}
if (!is_debug) {
set_brackets(detail::string_literal<Char, '"'>{},
detail::string_literal<Char, '"'>{});
}
check_for_s = false;
is_string_format = true;
++it;
}
if (check_for_s) {
report_error("invalid format specifier");
}
}
if (it != end && *it != '}') {
if (*it != ':') report_error("invalid format specifier");
if (is_string_format || *it != ':')
report_error("invalid format specifier");
++it;
} else {
detail::maybe_set_debug_format(underlying_, true);
if (!is_string_format) detail::maybe_set_debug_format(underlying_, true);
}
ctx.advance_to(it);
return underlying_.parse(ctx);
}
template <typename Output, typename Iter, typename IterEnd, typename U = T,
enable_if_t<std::is_same<U, Char>::value, bool> = true>
auto write_debug_string(Output& out, Iter& it, IterEnd& end) const -> Output {
auto buf = basic_memory_buffer<Char>();
for (; it != end; ++it) {
auto&& item = *it;
buf.push_back(item);
}
format_specs spec_str{};
spec_str.type = presentation_type::debug;
return detail::write<Char>(
out, basic_string_view<Char>(buf.data(), buf.size()), spec_str);
}
template <typename Output, typename Iter, typename IterEnd, typename U = T,
enable_if_t<!(std::is_same<U, Char>::value), bool> = true>
auto write_debug_string(Output& out, Iter& it, IterEnd& end) const -> Output {
detail::ignore_unused(it);
detail::ignore_unused(end);
return out;
}
template <typename R, typename FormatContext>
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
detail::range_mapper<buffered_context<Char>> mapper;
auto out = ctx.out();
out = detail::copy<Char>(opening_bracket_, out);
int i = 0;
auto it = detail::range_begin(range);
auto end = detail::range_end(range);
if (is_string_format && is_debug) {
return write_debug_string(out, it, end);
}
out = detail::copy<Char>(opening_bracket_, out);
int i = 0;
for (; it != end; ++it) {
if (i > 0) out = detail::copy<Char>(separator_, out);
if (i > 0 && !is_string_format) out = detail::copy<Char>(separator_, out);
ctx.advance_to(out);
auto&& item = *it;
out = underlying_.format(mapper.map(item), ctx);

View File

@ -58,8 +58,13 @@ TEST(ranges_test, format_vector) {
EXPECT_EQ(fmt::format("{:n:#x}", v), "0x1, 0x2, 0x3, 0x5, 0x7, 0xb");
auto vc = std::vector<char>{'a', 'b', 'c'};
auto vec = std::vector<char>{'a', '\n', '\t'};
auto vvc = std::vector<std::vector<char>>{vc, vc};
EXPECT_EQ(fmt::format("{}", vc), "['a', 'b', 'c']");
EXPECT_EQ(fmt::format("{:s}", vc), "\"abc\"");
EXPECT_EQ(fmt::format("{:?s}", vec), "\"a\\n\\t\"");
EXPECT_EQ(fmt::format("{:s}", vec), "\"a\n\t\"");
EXPECT_EQ(fmt::format("{::s}", vvc), "[\"abc\", \"abc\"]");
EXPECT_EQ(fmt::format("{}", vvc), "[['a', 'b', 'c'], ['a', 'b', 'c']]");
EXPECT_EQ(fmt::format("{:n}", vvc), "['a', 'b', 'c'], ['a', 'b', 'c']");
EXPECT_EQ(fmt::format("{:n:n}", vvc), "'a', 'b', 'c', 'a', 'b', 'c'");