mirror of
https://github.com/fmtlib/fmt.git
synced 2025-08-01 03:34:45 +02:00
Add xchar support for write_escaped_string.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
This commit is contained in:
committed by
Victor Zverovich
parent
90b68783ff
commit
1f9eae7e31
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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{"понедельник"}), "[\"понедельник\"]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user