mirror of
https://github.com/nlohmann/json.git
synced 2026-11-02 10:55:35 +00:00
json_view: keep accept()'s string check out of run()
Clang 23 made run() slower on files without escapes (mesh.pretty +15 %) when the check-only string path was a separate call target. Dispatch inside slow_string() instead, so the call in run() is the same as before, and skip the SIMD run scan between escapes that follow each other (twitterescaped 1.11 -> 0.82 against the previous commit). Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
3 files changed
+36
-36
No files matched your search
@@ -16,7 +16,6 @@
|
|||||||
#include <cstring> // memcmp, memcpy
|
#include <cstring> // memcmp, memcpy
|
||||||
#include <limits> // numeric_limits
|
#include <limits> // numeric_limits
|
||||||
#include <string> // string
|
#include <string> // string
|
||||||
#include <type_traits> // false_type, integral_constant, true_type
|
|
||||||
#include <vector> // vector
|
#include <vector> // vector
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
@@ -309,31 +308,25 @@ class builder
|
|||||||
--p;
|
--p;
|
||||||
return failed(error_code::string_escape, p);
|
return failed(error_code::string_escape, p);
|
||||||
}
|
}
|
||||||
|
if (p != end && *p == '\\')
|
||||||
|
{
|
||||||
|
continue; // (escapes in a row: no run of text between them)
|
||||||
|
}
|
||||||
p = scan_string_run(p, end); // the text up to the next backslash, quote, control character, or ill-formed UTF-8
|
p = scan_string_run(p, end); // the text up to the next backslash, quote, control character, or ill-formed UTF-8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// the string from p, decoded into the arena, or only checked (Store == false)
|
|
||||||
decoded decode_string(const unsigned char* s, const unsigned char* p)
|
|
||||||
{
|
|
||||||
return decode_string(s, p, std::integral_constant<bool, Store>());
|
|
||||||
}
|
|
||||||
|
|
||||||
decoded decode_string(const unsigned char* s, const unsigned char* p, std::true_type /*unused*/)
|
|
||||||
{
|
|
||||||
return slow_string(s, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
decoded decode_string(const unsigned char* /*unused*/, const unsigned char* p, std::false_type /*unused*/)
|
|
||||||
{
|
|
||||||
return check_string(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// s points to the start of the string, p to a backslash, a control
|
/// s points to the start of the string, p to a backslash, a control
|
||||||
/// character, an ill-formed UTF-8 byte, or the end: decode the string into
|
/// character, an ill-formed UTF-8 byte, or the end: decode the string into
|
||||||
/// the arena
|
/// the arena
|
||||||
NLOHMANN_VIEW_NOINLINE decoded slow_string(const unsigned char* s, const unsigned char* p)
|
NLOHMANN_VIEW_NOINLINE decoded slow_string(const unsigned char* s, const unsigned char* p)
|
||||||
{
|
{
|
||||||
|
if (!enabled(Store))
|
||||||
|
{
|
||||||
|
// (accept(): the string is checked, not decoded)
|
||||||
|
static_cast<void>(s);
|
||||||
|
return check_string(p);
|
||||||
|
}
|
||||||
// single-character escapes; 0: invalid (and 'u', handled separately)
|
// single-character escapes; 0: invalid (and 'u', handled separately)
|
||||||
static const std::array<char, 128> simple_escape =
|
static const std::array<char, 128> simple_escape =
|
||||||
{
|
{
|
||||||
@@ -1271,7 +1264,7 @@ indent_done:
|
|||||||
++p;
|
++p;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const decoded r = cold.decode_string(s, p);
|
const decoded r = cold.slow_string(s, p);
|
||||||
if (r.p == nullptr)
|
if (r.p == nullptr)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Generated
+11
-18
@@ -88,7 +88,6 @@
|
|||||||
#include <cstring> // memcmp, memcpy
|
#include <cstring> // memcmp, memcpy
|
||||||
#include <limits> // numeric_limits
|
#include <limits> // numeric_limits
|
||||||
#include <string> // string
|
#include <string> // string
|
||||||
#include <type_traits> // false_type, integral_constant, true_type
|
|
||||||
#include <vector> // vector
|
#include <vector> // vector
|
||||||
|
|
||||||
// #include <nlohmann/json.hpp>
|
// #include <nlohmann/json.hpp>
|
||||||
@@ -1551,31 +1550,25 @@ class builder
|
|||||||
--p;
|
--p;
|
||||||
return failed(error_code::string_escape, p);
|
return failed(error_code::string_escape, p);
|
||||||
}
|
}
|
||||||
|
if (p != end && *p == '\\')
|
||||||
|
{
|
||||||
|
continue; // (escapes in a row: no run of text between them)
|
||||||
|
}
|
||||||
p = scan_string_run(p, end); // the text up to the next backslash, quote, control character, or ill-formed UTF-8
|
p = scan_string_run(p, end); // the text up to the next backslash, quote, control character, or ill-formed UTF-8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// the string from p, decoded into the arena, or only checked (Store == false)
|
|
||||||
decoded decode_string(const unsigned char* s, const unsigned char* p)
|
|
||||||
{
|
|
||||||
return decode_string(s, p, std::integral_constant<bool, Store>());
|
|
||||||
}
|
|
||||||
|
|
||||||
decoded decode_string(const unsigned char* s, const unsigned char* p, std::true_type /*unused*/)
|
|
||||||
{
|
|
||||||
return slow_string(s, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
decoded decode_string(const unsigned char* /*unused*/, const unsigned char* p, std::false_type /*unused*/)
|
|
||||||
{
|
|
||||||
return check_string(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// s points to the start of the string, p to a backslash, a control
|
/// s points to the start of the string, p to a backslash, a control
|
||||||
/// character, an ill-formed UTF-8 byte, or the end: decode the string into
|
/// character, an ill-formed UTF-8 byte, or the end: decode the string into
|
||||||
/// the arena
|
/// the arena
|
||||||
NLOHMANN_VIEW_NOINLINE decoded slow_string(const unsigned char* s, const unsigned char* p)
|
NLOHMANN_VIEW_NOINLINE decoded slow_string(const unsigned char* s, const unsigned char* p)
|
||||||
{
|
{
|
||||||
|
if (!enabled(Store))
|
||||||
|
{
|
||||||
|
// (accept(): the string is checked, not decoded)
|
||||||
|
static_cast<void>(s);
|
||||||
|
return check_string(p);
|
||||||
|
}
|
||||||
// single-character escapes; 0: invalid (and 'u', handled separately)
|
// single-character escapes; 0: invalid (and 'u', handled separately)
|
||||||
static const std::array<char, 128> simple_escape =
|
static const std::array<char, 128> simple_escape =
|
||||||
{
|
{
|
||||||
@@ -2513,7 +2506,7 @@ indent_done:
|
|||||||
++p;
|
++p;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const decoded r = cold.decode_string(s, p);
|
const decoded r = cold.slow_string(s, p);
|
||||||
if (r.p == nullptr)
|
if (r.p == nullptr)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -553,6 +553,20 @@ TEST_CASE("json_view builder")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("escapes in a row")
|
||||||
|
{
|
||||||
|
for (const char* content :
|
||||||
|
{
|
||||||
|
"\\n", "\\n\\t\\\\", "\\u00e9\\u00e9\\u4e2d", "\\u00e9\\u00e", "\\u00e9\\", "\\n\\q", "\\n\\ud83d\\ude00\\n",
|
||||||
|
"\\ud83d\\ude00\\ud83d", "\\n\\n\\n abc \\n\\n", "\\n\x01", "\\n\xC3\x28", "\\n\\"
|
||||||
|
})
|
||||||
|
{
|
||||||
|
check_accept(std::string("[\"") + content + "\"]");
|
||||||
|
check_accept(std::string("[\"") + content);
|
||||||
|
check_accept(std::string("{\"") + content + "\":1}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("test files")
|
SECTION("test files")
|
||||||
{
|
{
|
||||||
for (const char* name :
|
for (const char* name :
|
||||||
|
|||||||
Reference in new issue
Block a user