Match literals without a stack array and keep parser states in bytes

scan_after_whitespace() built the expected text of true, false, and null in
local std::array objects. With -fstack-protector-strong (the default of
Ubuntu's GCC, among others), a local array gives the function a stack canary
check, which then ran on every token. scan_literal() now takes the text
after the first character as a string literal, with its length as a template
parameter; for contiguous input it compares the rest at once and falls back
to the byte loop on a mismatch, so errors are reported at the same
character. It is out of line, which keeps the token dispatch small.

The parser kept the nesting of arrays and objects in a std::vector<bool>,
whose push_back() GCC calls out of line; it is a std::vector<std::uint8_t>
now.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-15 18:37:05 +02:00
1 parent c6742f9761
commit 57424ab0b5
5 files changed
+154 -53

No files matched your search

+6 -5
View File
@@ -244,8 +244,9 @@ class parser
bool sax_parse_internal(SAX* sax)
{
// stack to remember the hierarchy of structured values we are parsing
// true = array; false = object
std::vector<bool> states;
// true = array; false = object (bytes, not std::vector<bool>, whose
// push_back() is a call with GCC)
std::vector<std::uint8_t> states;
// value to avoid a goto (see comment where set to true)
bool skip_to_state_evaluation = false;
@@ -290,7 +291,7 @@ class parser
}
// remember we are now inside an object
states.push_back(false);
states.push_back(0);
// parse values
get_token();
@@ -315,7 +316,7 @@ class parser
}
// remember we are now inside an array
states.push_back(true);
states.push_back(1);
// parse values (no need to call get_token)
continue;
@@ -432,7 +433,7 @@ class parser
return true;
}
if (states.back()) // array
if (states.back() != 0) // array
{
// comma -> next value
// or end of array (ignore_trailing_commas = true)