mirror of
https://github.com/nlohmann/json.git
synced 2026-10-23 14:28:54 +00:00
Escape runs of multi-byte characters straight into the write buffer
With ensure_ascii, every non-ASCII character went through the UTF-8 state machine one byte at a time and its \uXXXX escape was assembled in string_buffer and copied to the write buffer afterwards. A run of well-formed multi-byte characters is now decoded and escaped directly into the write buffer. The first byte that is ASCII or starts an ill-formed or truncated sequence ends the run and is left to the unchanged byte-at-a-time path, so error handling and its messages (positions, replacement, ignore, keep) are as before. Apple M1, Apple clang, retired instructions per dump(-1, ' ', true): cjk text 15.9M -> 6.94M (-56 %) twitter 9.10M -> 6.16M (-32 %) emoji text 8.89M -> 6.08M (-32 %) latin text 10.3M -> 9.23M (-10 %) Pure ASCII documents with escapes (logs, JSON in JSON) and all modes without ensure_ascii are unchanged. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
3 files changed
+219
No files matched your search
@@ -1631,3 +1631,42 @@ TEST_CASE("short strings are written like the reference, as values and as keys")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("runs of multi-byte characters are escaped like the reference under ensure_ascii")
|
||||
{
|
||||
// a run of well-formed multi-byte characters is escaped straight into the
|
||||
// write buffer; it has to flush that mid-run, stop at an ASCII character or
|
||||
// an ill-formed sequence and leave those to the general path, and pick up
|
||||
// behind what the general path has pending
|
||||
const std::vector<std::string> characters =
|
||||
{
|
||||
"\xc2\x80", "\xdf\xbf", "\xe0\xa0\x80", "\xe2\x82\xac", "\xed\x9f\xbf", "\xef\xbf\xbf",
|
||||
"\xf0\x90\x80\x80", "\xf0\x9f\x98\x80", "\xf4\x8f\xbf\xbf"
|
||||
};
|
||||
const std::vector<std::string> interruptions =
|
||||
{
|
||||
"", "a", "\n", "\"", "\x7f", "\xff", "\x80", "\xc3", "\xe2\x82", "\xf0\x9f\x98", "\xed\xa0\x80"
|
||||
};
|
||||
|
||||
for (std::size_t shift = 0; shift <= 13; ++shift)
|
||||
{
|
||||
for (const auto& interruption : interruptions)
|
||||
{
|
||||
for (const std::size_t count :
|
||||
{
|
||||
std::size_t{1}, std::size_t{2}, std::size_t{85}, std::size_t{200}
|
||||
})
|
||||
{
|
||||
std::string s(shift, 'x');
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
s += characters[(i + shift) % characters.size()];
|
||||
}
|
||||
s += interruption;
|
||||
s += characters[shift % characters.size()];
|
||||
s += characters[(shift + 3) % characters.size()];
|
||||
check_dump_against_reference(s, shift < 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user