Clarify the DOM parser's collection stacks and rename reenter_enclosing_container()

Address review comments: explain why a closed container erases only the top
of the shared stack, set the payload before the type, rename the helper that
makes the enclosing container current again, and declare the parser's state
stack right before reserving it.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-23 06:45:13 +02:00
1 parent 14e9150b97
commit 1fc4d2afb3
3 files changed
+30 -22

No files matched your search

+12 -8
View File
@@ -569,16 +569,18 @@ class json_sax_dom_parser
JSON_ASSERT(frames.back().object == nullptr); JSON_ASSERT(frames.back().object == nullptr);
const frame f = frames.back(); const frame f = frames.back();
frames.pop_back(); frames.pop_back();
enter_enclosing_container(); reenter_enclosing_container();
if (f.array == nullptr) if (f.array == nullptr)
{ {
// the elements are on the stack: make them the array // the elements are the top of the shared elements stack, from
// f.start on (the elements below belong to enclosing arrays that
// are still open): move them into the array and pop them
const auto first = elements.begin() + static_cast<std::ptrdiff_t>(f.start); const auto first = elements.begin() + static_cast<std::ptrdiff_t>(f.start);
auto* const arr = BasicJsonType::template create<array_t>(std::make_move_iterator(first), std::make_move_iterator(elements.end())); auto* const arr = BasicJsonType::template create<array_t>(std::make_move_iterator(first), std::make_move_iterator(elements.end()));
BasicJsonType value; BasicJsonType value;
value.m_data.m_type = BasicJsonType::value_t::array;
value.m_data.m_value.array = arr; value.m_data.m_value.array = arr;
value.m_data.m_type = BasicJsonType::value_t::array;
elements.erase(first, elements.end()); elements.erase(first, elements.end());
place_container(f, frames.empty() ? nullptr : &frames.back(), std::move(value), true); place_container(f, frames.empty() ? nullptr : &frames.back(), std::move(value), true);
@@ -1033,13 +1035,15 @@ class json_sax_dom_parser
return true; return true;
} }
/// the members of an object that is collected on the stack as an object /// the members of an object that is collected on the stack as an object;
/// they are the top of the shared member stack, from f.start on (the
/// members below belong to enclosing objects that are still open)
object_t* members_to_object(const frame& f, BasicJsonType& value) object_t* members_to_object(const frame& f, BasicJsonType& value)
{ {
const auto first = ordered_data.members.begin() + static_cast<std::ptrdiff_t>(f.start); const auto first = ordered_data.members.begin() + static_cast<std::ptrdiff_t>(f.start);
auto* const obj = BasicJsonType::template create<object_t>(std::make_move_iterator(first), std::make_move_iterator(ordered_data.members.end())); auto* const obj = BasicJsonType::template create<object_t>(std::make_move_iterator(first), std::make_move_iterator(ordered_data.members.end()));
value.m_data.m_type = BasicJsonType::value_t::object;
value.m_data.m_value.object = obj; value.m_data.m_value.object = obj;
value.m_data.m_type = BasicJsonType::value_t::object;
ordered_data.members.erase(first, ordered_data.members.end()); ordered_data.members.erase(first, ordered_data.members.end());
return obj; return obj;
} }
@@ -1073,7 +1077,7 @@ class json_sax_dom_parser
// the members are on the stack: make them the object // the members are on the stack: make them the object
const frame f = frames.back(); const frame f = frames.back();
frames.pop_back(); frames.pop_back();
enter_enclosing_container(); reenter_enclosing_container();
BasicJsonType value; BasicJsonType value;
members_to_object(f, value); members_to_object(f, value);
@@ -1098,7 +1102,7 @@ class json_sax_dom_parser
release_key_index(frames.back(), std::integral_constant<bool, indexed_keys> {}); release_key_index(frames.back(), std::integral_constant<bool, indexed_keys> {});
frames.pop_back(); frames.pop_back();
enter_enclosing_container(); reenter_enclosing_container();
return true; return true;
} }
@@ -1269,7 +1273,7 @@ class json_sax_dom_parser
} }
/// after a container was closed: the one it was in is the one that gets the next value /// after a container was closed: the one it was in is the one that gets the next value
void enter_enclosing_container() void reenter_enclosing_container()
{ {
if (frames.empty()) if (frames.empty())
{ {
+3 -3
View File
@@ -243,13 +243,13 @@ class parser
JSON_HEDLEY_NON_NULL(2) JSON_HEDLEY_NON_NULL(2)
bool sax_parse_internal(SAX* sax) bool sax_parse_internal(SAX* sax)
{ {
// value to avoid a goto (see comment where set to true)
bool skip_to_state_evaluation = false;
// stack to remember the hierarchy of structured values we are parsing // stack to remember the hierarchy of structured values we are parsing
// true = array; false = object (bytes, not std::vector<bool>, whose // true = array; false = object (bytes, not std::vector<bool>, whose
// push_back() is a call with GCC) // push_back() is a call with GCC)
std::vector<std::uint8_t> states; std::vector<std::uint8_t> states;
// value to avoid a goto (see comment where set to true)
bool skip_to_state_evaluation = false;
// a document that starts with a container pushes onto the stack at // a document that starts with a container pushes onto the stack at
// once: allocate it in one step instead of growing it from 1 byte // once: allocate it in one step instead of growing it from 1 byte
if (last_token == token_type::begin_object || last_token == token_type::begin_array) if (last_token == token_type::begin_object || last_token == token_type::begin_array)
+15 -11
View File
@@ -15502,16 +15502,18 @@ class json_sax_dom_parser
JSON_ASSERT(frames.back().object == nullptr); JSON_ASSERT(frames.back().object == nullptr);
const frame f = frames.back(); const frame f = frames.back();
frames.pop_back(); frames.pop_back();
enter_enclosing_container(); reenter_enclosing_container();
if (f.array == nullptr) if (f.array == nullptr)
{ {
// the elements are on the stack: make them the array // the elements are the top of the shared elements stack, from
// f.start on (the elements below belong to enclosing arrays that
// are still open): move them into the array and pop them
const auto first = elements.begin() + static_cast<std::ptrdiff_t>(f.start); const auto first = elements.begin() + static_cast<std::ptrdiff_t>(f.start);
auto* const arr = BasicJsonType::template create<array_t>(std::make_move_iterator(first), std::make_move_iterator(elements.end())); auto* const arr = BasicJsonType::template create<array_t>(std::make_move_iterator(first), std::make_move_iterator(elements.end()));
BasicJsonType value; BasicJsonType value;
value.m_data.m_type = BasicJsonType::value_t::array;
value.m_data.m_value.array = arr; value.m_data.m_value.array = arr;
value.m_data.m_type = BasicJsonType::value_t::array;
elements.erase(first, elements.end()); elements.erase(first, elements.end());
place_container(f, frames.empty() ? nullptr : &frames.back(), std::move(value), true); place_container(f, frames.empty() ? nullptr : &frames.back(), std::move(value), true);
@@ -15966,13 +15968,15 @@ class json_sax_dom_parser
return true; return true;
} }
/// the members of an object that is collected on the stack as an object /// the members of an object that is collected on the stack as an object;
/// they are the top of the shared member stack, from f.start on (the
/// members below belong to enclosing objects that are still open)
object_t* members_to_object(const frame& f, BasicJsonType& value) object_t* members_to_object(const frame& f, BasicJsonType& value)
{ {
const auto first = ordered_data.members.begin() + static_cast<std::ptrdiff_t>(f.start); const auto first = ordered_data.members.begin() + static_cast<std::ptrdiff_t>(f.start);
auto* const obj = BasicJsonType::template create<object_t>(std::make_move_iterator(first), std::make_move_iterator(ordered_data.members.end())); auto* const obj = BasicJsonType::template create<object_t>(std::make_move_iterator(first), std::make_move_iterator(ordered_data.members.end()));
value.m_data.m_type = BasicJsonType::value_t::object;
value.m_data.m_value.object = obj; value.m_data.m_value.object = obj;
value.m_data.m_type = BasicJsonType::value_t::object;
ordered_data.members.erase(first, ordered_data.members.end()); ordered_data.members.erase(first, ordered_data.members.end());
return obj; return obj;
} }
@@ -16006,7 +16010,7 @@ class json_sax_dom_parser
// the members are on the stack: make them the object // the members are on the stack: make them the object
const frame f = frames.back(); const frame f = frames.back();
frames.pop_back(); frames.pop_back();
enter_enclosing_container(); reenter_enclosing_container();
BasicJsonType value; BasicJsonType value;
members_to_object(f, value); members_to_object(f, value);
@@ -16031,7 +16035,7 @@ class json_sax_dom_parser
release_key_index(frames.back(), std::integral_constant<bool, indexed_keys> {}); release_key_index(frames.back(), std::integral_constant<bool, indexed_keys> {});
frames.pop_back(); frames.pop_back();
enter_enclosing_container(); reenter_enclosing_container();
return true; return true;
} }
@@ -16202,7 +16206,7 @@ class json_sax_dom_parser
} }
/// after a container was closed: the one it was in is the one that gets the next value /// after a container was closed: the one it was in is the one that gets the next value
void enter_enclosing_container() void reenter_enclosing_container()
{ {
if (frames.empty()) if (frames.empty())
{ {
@@ -22007,13 +22011,13 @@ class parser
JSON_HEDLEY_NON_NULL(2) JSON_HEDLEY_NON_NULL(2)
bool sax_parse_internal(SAX* sax) bool sax_parse_internal(SAX* sax)
{ {
// value to avoid a goto (see comment where set to true)
bool skip_to_state_evaluation = false;
// stack to remember the hierarchy of structured values we are parsing // stack to remember the hierarchy of structured values we are parsing
// true = array; false = object (bytes, not std::vector<bool>, whose // true = array; false = object (bytes, not std::vector<bool>, whose
// push_back() is a call with GCC) // push_back() is a call with GCC)
std::vector<std::uint8_t> states; std::vector<std::uint8_t> states;
// value to avoid a goto (see comment where set to true)
bool skip_to_state_evaluation = false;
// a document that starts with a container pushes onto the stack at // a document that starts with a container pushes onto the stack at
// once: allocate it in one step instead of growing it from 1 byte // once: allocate it in one step instead of growing it from 1 byte
if (last_token == token_type::begin_object || last_token == token_type::begin_array) if (last_token == token_type::begin_object || last_token == token_type::begin_array)