Add xchar support for write_escaped_string.

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
This commit is contained in:
Vladislav Shchapov
2022-05-22 21:08:26 +05:00
committed by Victor Zverovich
parent 90b68783ff
commit 1f9eae7e31
3 changed files with 46 additions and 39 deletions

View File

@@ -1570,10 +1570,14 @@ inline auto find_escape(const char* begin, const char* end)
*/ */
#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string, ) #define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string, )
template <typename Char, typename OutputIt> template <size_t width, typename Char, typename OutputIt>
auto write_escaped_string(OutputIt out, basic_string_view<Char> str) auto write_codepoint(OutputIt out, char prefix, uint32_t cp) -> OutputIt {
-> OutputIt { *out++ = static_cast<Char>('\\');
return copy_str<Char>(str.data(), str.data() + str.size(), out); *out++ = static_cast<Char>(prefix);
Char buf[width];
fill_n(buf, width, static_cast<Char>('0'));
format_uint<4>(buf, cp, width);
return copy_str<Char>(buf, buf + width, out);
} }
template <typename OutputIt, typename Char> template <typename OutputIt, typename Char>
@@ -1582,40 +1586,40 @@ auto write_escaped_cp(OutputIt out, const find_escape_result<Char>& escape)
auto c = static_cast<Char>(escape.cp); auto c = static_cast<Char>(escape.cp);
switch (escape.cp) { switch (escape.cp) {
case '\n': case '\n':
*out++ = '\\'; *out++ = static_cast<Char>('\\');
c = 'n'; c = static_cast<Char>('n');
break; break;
case '\r': case '\r':
*out++ = '\\'; *out++ = static_cast<Char>('\\');
c = 'r'; c = static_cast<Char>('r');
break; break;
case '\t': case '\t':
*out++ = '\\'; *out++ = static_cast<Char>('\\');
c = 't'; c = static_cast<Char>('t');
break; break;
case '"': case '"':
FMT_FALLTHROUGH; FMT_FALLTHROUGH;
case '\'': case '\'':
FMT_FALLTHROUGH; FMT_FALLTHROUGH;
case '\\': case '\\':
*out++ = '\\'; *out++ = static_cast<Char>('\\');
break; break;
default: default:
if (is_utf8()) { if (is_utf8()) {
if (escape.cp < 0x100) { if (escape.cp < 0x100) {
return format_to(out, FMT_STRING("\\x{:02x}"), escape.cp); return write_codepoint<2, Char>(out, 'x', escape.cp);
} }
if (escape.cp < 0x10000) { if (escape.cp < 0x10000) {
return format_to(out, FMT_STRING("\\u{:04x}"), escape.cp); return write_codepoint<4, Char>(out, 'u', escape.cp);
} }
if (escape.cp < 0x110000) { if (escape.cp < 0x110000) {
return format_to(out, FMT_STRING("\\U{:08x}"), escape.cp); return write_codepoint<8, Char>(out, 'U', escape.cp);
} }
} }
for (char escape_char : basic_string_view<Char>( for (Char escape_char : basic_string_view<Char>(
escape.begin, to_unsigned(escape.end - escape.begin))) { escape.begin, to_unsigned(escape.end - escape.begin))) {
out = format_to(out, FMT_STRING("\\x{:02x}"), out = write_codepoint<2, Char>(out, 'x',
static_cast<make_unsigned_char<Char>>(escape_char)); static_cast<uint32_t>(escape_char) & 0xFF);
} }
return out; return out;
} }
@@ -1623,38 +1627,33 @@ auto write_escaped_cp(OutputIt out, const find_escape_result<Char>& escape)
return out; return out;
} }
template <typename OutputIt> template <typename Char, typename OutputIt>
auto write_escaped_string(OutputIt out, basic_string_view<char> str) auto write_escaped_string(OutputIt out, basic_string_view<Char> str)
-> OutputIt { -> OutputIt {
*out++ = '"'; *out++ = static_cast<Char>('"');
auto begin = str.begin(), end = str.end(); auto begin = str.begin(), end = str.end();
do { do {
auto escape = find_escape(begin, end); auto escape = find_escape(begin, end);
out = copy_str<char>(begin, escape.begin, out); out = copy_str<Char>(begin, escape.begin, out);
begin = escape.end; begin = escape.end;
if (!begin) break; if (!begin) break;
out = write_escaped_cp(out, escape); out = write_escaped_cp<OutputIt, Char>(out, escape);
} while (begin != end); } while (begin != end);
*out++ = '"'; *out++ = static_cast<Char>('"');
return out; return out;
} }
template <typename Char, typename OutputIt> template <typename Char, typename OutputIt>
auto write_escaped_char(OutputIt out, Char v) -> OutputIt { auto write_escaped_char(OutputIt out, Char v) -> OutputIt {
*out++ = v; *out++ = static_cast<Char>('\'');
return out; if ((needs_escape(static_cast<uint32_t>(v)) && v != static_cast<Char>('"')) ||
} v == static_cast<Char>('\'')) {
template <typename OutputIt>
auto write_escaped_char(OutputIt out, char v) -> OutputIt {
*out++ = '\'';
if ((needs_escape(static_cast<uint32_t>(v)) && v != '"') || v == '\'') {
out = write_escaped_cp( out = write_escaped_cp(
out, find_escape_result<char>{&v, &v + 1, static_cast<uint32_t>(v)}); out, find_escape_result<Char>{&v, &v + 1, static_cast<uint32_t>(v)});
} else { } else {
*out++ = v; *out++ = v;
} }
*out++ = '\''; *out++ = static_cast<Char>('\'');
return out; return out;
} }

View File

@@ -70,13 +70,9 @@ struct box {
int value; int value;
}; };
auto begin(const box& b) -> const int* { auto begin(const box& b) -> const int* { return &b.value; }
return &b.value;
}
auto end(const box& b) -> const int* { auto end(const box& b) -> const int* { return &b.value + 1; }
return &b.value + 1;
}
} // namespace adl } // namespace adl
TEST(ranges_test, format_adl_begin_end) { TEST(ranges_test, format_adl_begin_end) {
@@ -370,6 +366,7 @@ TEST(ranges_test, escape_string) {
EXPECT_EQ(fmt::format("{}", vec{"\xf0\xaa\x9b\x9e"}), "[\"\\U0002a6de\"]"); EXPECT_EQ(fmt::format("{}", vec{"\xf0\xaa\x9b\x9e"}), "[\"\\U0002a6de\"]");
EXPECT_EQ(fmt::format("{}", vec{"\xf4\x8f\xbf\xc0"}), EXPECT_EQ(fmt::format("{}", vec{"\xf4\x8f\xbf\xc0"}),
"[\"\\xf4\\x8f\\xbf\\xc0\"]"); "[\"\\xf4\\x8f\\xbf\\xc0\"]");
EXPECT_EQ(fmt::format("{}", vec{"понедельник"}), "[\"понедельник\"]");
} }
} }

View File

@@ -337,6 +337,17 @@ TEST(xchar_test, ostream) {
#endif #endif
} }
TEST(xchar_test, format_map) {
auto m = std::map<std::wstring, int>{{L"one", 1}, {L"t\"wo", 2}};
EXPECT_EQ(fmt::format(L"{}", m), L"{\"one\": 1, \"t\\\"wo\": 2}");
}
TEST(xchar_test, escape_string) {
using vec = std::vector<std::wstring>;
EXPECT_EQ(fmt::format(L"{}", vec{L"\n\r\t\"\\"}), L"[\"\\n\\r\\t\\\"\\\\\"]");
EXPECT_EQ(fmt::format(L"{}", vec{L"понедельник"}), L"[\"понедельник\"]");
}
TEST(xchar_test, to_wstring) { EXPECT_EQ(L"42", fmt::to_wstring(42)); } TEST(xchar_test, to_wstring) { EXPECT_EQ(L"42", fmt::to_wstring(42)); }
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR #ifndef FMT_STATIC_THOUSANDS_SEPARATOR