diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index 20a65d76e..80ee84c8c 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -844,8 +844,15 @@ class serializer if (state == UTF8_ACCEPT) { const auto* const data = reinterpret_cast(s.data()); + // A run can only be non-empty when the very first byte is one + // the scanner may copy, so test that single byte before paying + // for the scan. Without it, text whose characters all have to be + // escaped - CJK under ensure_ascii, where every byte is >= 0x80 - + // runs the scanner once per character only to be told zero. const std::size_t run = EnsureAscii - ? find_ascii_copyable_run(data + i, s.size() - i) + ? (is_ascii_copyable(data[i]) + ? find_ascii_copyable_run(data + i, s.size() - i) + : 0) : string_bulk_run(data + i, s.size() - i); if (run != 0) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 04438d1f7..26d0943da 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -21904,8 +21904,15 @@ class serializer if (state == UTF8_ACCEPT) { const auto* const data = reinterpret_cast(s.data()); + // A run can only be non-empty when the very first byte is one + // the scanner may copy, so test that single byte before paying + // for the scan. Without it, text whose characters all have to be + // escaped - CJK under ensure_ascii, where every byte is >= 0x80 - + // runs the scanner once per character only to be told zero. const std::size_t run = EnsureAscii - ? find_ascii_copyable_run(data + i, s.size() - i) + ? (is_ascii_copyable(data[i]) + ? find_ascii_copyable_run(data + i, s.size() - i) + : 0) : string_bulk_run(data + i, s.size() - i); if (run != 0) {