mirror of
https://github.com/nlohmann/json.git
synced 2026-10-24 06:48:55 +00:00
Remember where the DOM parser stores the next value
The DOM SAX parser looked up the innermost open container for every value: the end of its frame stack, then the object or array pointer in the frame. Compilers have to reload all of that after each value is stored, since a store of a value may alias the frame. The parser now keeps the innermost container's kind and, for an array that stores directly, the array itself in members, updated when a container opens or closes. Flat arrays of numbers are the case that mattered: parsing floats.json (1 000 000 doubles) into a DOM took 2 % more cycles than before the previous commit on macOS and now takes 0.4 % fewer than the code before it (signed_ints.json -0.8 %). Linux Ir is unchanged (canada -6.1 % GCC / -6.9 % Clang, citm -0.3 % / -0.8 %, twitter +0.2 % / 0.0 %). Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
2 files changed
+86
-26
No files matched your search
@@ -410,6 +410,8 @@ class json_sax_dom_parser
|
|||||||
BasicJsonType* const ref = store(BasicJsonType(BasicJsonType::value_t::object));
|
BasicJsonType* const ref = store(BasicJsonType(BasicJsonType::value_t::object));
|
||||||
reserve_frames();
|
reserve_frames();
|
||||||
frames.push_back(frame{ref->m_data.m_value.object, nullptr, ref, 0});
|
frames.push_back(frame{ref->m_data.m_value.object, nullptr, ref, 0});
|
||||||
|
in_object = true;
|
||||||
|
stored_array = nullptr;
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
// Ensure this is after the call to store to ensure correct start position.
|
// Ensure this is after the call to store to ensure correct start position.
|
||||||
@@ -447,6 +449,7 @@ class json_sax_dom_parser
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
frames.pop_back();
|
frames.pop_back();
|
||||||
|
enter_enclosing_container();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,6 +491,8 @@ class json_sax_dom_parser
|
|||||||
reserve_frames();
|
reserve_frames();
|
||||||
reserve_elements();
|
reserve_elements();
|
||||||
frames.push_back(frame{nullptr, nullptr, slot, elements.size()});
|
frames.push_back(frame{nullptr, nullptr, slot, elements.size()});
|
||||||
|
in_object = false;
|
||||||
|
stored_array = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
@@ -499,6 +504,7 @@ 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();
|
||||||
|
|
||||||
if (f.array == nullptr)
|
if (f.array == nullptr)
|
||||||
{
|
{
|
||||||
@@ -595,6 +601,8 @@ class json_sax_dom_parser
|
|||||||
BasicJsonType* const ref = store(BasicJsonType(BasicJsonType::value_t::array));
|
BasicJsonType* const ref = store(BasicJsonType(BasicJsonType::value_t::array));
|
||||||
reserve_frames();
|
reserve_frames();
|
||||||
frames.push_back(frame{nullptr, ref->m_data.m_value.array, ref, 0});
|
frames.push_back(frame{nullptr, ref->m_data.m_value.array, ref, 0});
|
||||||
|
in_object = false;
|
||||||
|
stored_array = ref->m_data.m_value.array;
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
// Ensure this is after the call to store to ensure correct start position.
|
// Ensure this is after the call to store to ensure correct start position.
|
||||||
@@ -616,6 +624,19 @@ class json_sax_dom_parser
|
|||||||
JSON_HEDLEY_RETURNS_NON_NULL
|
JSON_HEDLEY_RETURNS_NON_NULL
|
||||||
BasicJsonType* store(Value&& v)
|
BasicJsonType* store(Value&& v)
|
||||||
{
|
{
|
||||||
|
if (in_object)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(object_element);
|
||||||
|
*object_element = BasicJsonType(std::forward<Value>(v));
|
||||||
|
return object_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stored_array != nullptr)
|
||||||
|
{
|
||||||
|
stored_array->emplace_back(std::forward<Value>(v));
|
||||||
|
return &stored_array->back();
|
||||||
|
}
|
||||||
|
|
||||||
if (frames.empty())
|
if (frames.empty())
|
||||||
{
|
{
|
||||||
root = BasicJsonType(std::forward<Value>(v));
|
root = BasicJsonType(std::forward<Value>(v));
|
||||||
@@ -623,19 +644,6 @@ class json_sax_dom_parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
frame& f = frames.back();
|
frame& f = frames.back();
|
||||||
if (f.object != nullptr)
|
|
||||||
{
|
|
||||||
JSON_ASSERT(object_element);
|
|
||||||
*object_element = BasicJsonType(std::forward<Value>(v));
|
|
||||||
return object_element;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f.array != nullptr)
|
|
||||||
{
|
|
||||||
f.array->emplace_back(std::forward<Value>(v));
|
|
||||||
return &f.array->back();
|
|
||||||
}
|
|
||||||
|
|
||||||
elements.emplace_back(std::forward<Value>(v));
|
elements.emplace_back(std::forward<Value>(v));
|
||||||
if (JSON_HEDLEY_UNLIKELY(elements.size() - f.start > buffer_limit))
|
if (JSON_HEDLEY_UNLIKELY(elements.size() - f.start > buffer_limit))
|
||||||
{
|
{
|
||||||
@@ -660,6 +668,7 @@ class json_sax_dom_parser
|
|||||||
arr.insert(arr.end(), std::make_move_iterator(first), std::make_move_iterator(elements.end()));
|
arr.insert(arr.end(), std::make_move_iterator(first), std::make_move_iterator(elements.end()));
|
||||||
elements.erase(first, elements.end());
|
elements.erase(first, elements.end());
|
||||||
f.array = &arr;
|
f.array = &arr;
|
||||||
|
stored_array = &arr;
|
||||||
|
|
||||||
// the array takes the place its first element had on the stack
|
// the array takes the place its first element had on the stack
|
||||||
if (f.slot != nullptr)
|
if (f.slot != nullptr)
|
||||||
@@ -682,6 +691,22 @@ class json_sax_dom_parser
|
|||||||
return &arr.back();
|
return &arr.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// after a container was closed: the one it was in is the one that gets the next value
|
||||||
|
void enter_enclosing_container()
|
||||||
|
{
|
||||||
|
if (frames.empty())
|
||||||
|
{
|
||||||
|
in_object = false;
|
||||||
|
stored_array = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const frame& f = frames.back();
|
||||||
|
in_object = f.object != nullptr;
|
||||||
|
stored_array = f.array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
void handle_value(Value&& v)
|
void handle_value(Value&& v)
|
||||||
{
|
{
|
||||||
@@ -702,6 +727,11 @@ class json_sax_dom_parser
|
|||||||
std::vector<BasicJsonType> elements {};
|
std::vector<BasicJsonType> elements {};
|
||||||
/// helper to hold the reference for the next object element
|
/// helper to hold the reference for the next object element
|
||||||
BasicJsonType* object_element = nullptr;
|
BasicJsonType* object_element = nullptr;
|
||||||
|
/// whether the innermost container is an object (frames.back().object)
|
||||||
|
bool in_object = false;
|
||||||
|
/// the array that stores the elements of the innermost array as they
|
||||||
|
/// arrive (frames.back().array), or nullptr
|
||||||
|
array_t* stored_array = nullptr;
|
||||||
/// whether a syntax error occurred
|
/// whether a syntax error occurred
|
||||||
bool errored = false;
|
bool errored = false;
|
||||||
/// whether to throw exceptions in case of errors
|
/// whether to throw exceptions in case of errors
|
||||||
|
|||||||
Generated
+43
-13
@@ -15279,6 +15279,8 @@ class json_sax_dom_parser
|
|||||||
BasicJsonType* const ref = store(BasicJsonType(BasicJsonType::value_t::object));
|
BasicJsonType* const ref = store(BasicJsonType(BasicJsonType::value_t::object));
|
||||||
reserve_frames();
|
reserve_frames();
|
||||||
frames.push_back(frame{ref->m_data.m_value.object, nullptr, ref, 0});
|
frames.push_back(frame{ref->m_data.m_value.object, nullptr, ref, 0});
|
||||||
|
in_object = true;
|
||||||
|
stored_array = nullptr;
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
// Ensure this is after the call to store to ensure correct start position.
|
// Ensure this is after the call to store to ensure correct start position.
|
||||||
@@ -15316,6 +15318,7 @@ class json_sax_dom_parser
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
frames.pop_back();
|
frames.pop_back();
|
||||||
|
enter_enclosing_container();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15357,6 +15360,8 @@ class json_sax_dom_parser
|
|||||||
reserve_frames();
|
reserve_frames();
|
||||||
reserve_elements();
|
reserve_elements();
|
||||||
frames.push_back(frame{nullptr, nullptr, slot, elements.size()});
|
frames.push_back(frame{nullptr, nullptr, slot, elements.size()});
|
||||||
|
in_object = false;
|
||||||
|
stored_array = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
@@ -15368,6 +15373,7 @@ 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();
|
||||||
|
|
||||||
if (f.array == nullptr)
|
if (f.array == nullptr)
|
||||||
{
|
{
|
||||||
@@ -15464,6 +15470,8 @@ class json_sax_dom_parser
|
|||||||
BasicJsonType* const ref = store(BasicJsonType(BasicJsonType::value_t::array));
|
BasicJsonType* const ref = store(BasicJsonType(BasicJsonType::value_t::array));
|
||||||
reserve_frames();
|
reserve_frames();
|
||||||
frames.push_back(frame{nullptr, ref->m_data.m_value.array, ref, 0});
|
frames.push_back(frame{nullptr, ref->m_data.m_value.array, ref, 0});
|
||||||
|
in_object = false;
|
||||||
|
stored_array = ref->m_data.m_value.array;
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
// Ensure this is after the call to store to ensure correct start position.
|
// Ensure this is after the call to store to ensure correct start position.
|
||||||
@@ -15485,6 +15493,19 @@ class json_sax_dom_parser
|
|||||||
JSON_HEDLEY_RETURNS_NON_NULL
|
JSON_HEDLEY_RETURNS_NON_NULL
|
||||||
BasicJsonType* store(Value&& v)
|
BasicJsonType* store(Value&& v)
|
||||||
{
|
{
|
||||||
|
if (in_object)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(object_element);
|
||||||
|
*object_element = BasicJsonType(std::forward<Value>(v));
|
||||||
|
return object_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stored_array != nullptr)
|
||||||
|
{
|
||||||
|
stored_array->emplace_back(std::forward<Value>(v));
|
||||||
|
return &stored_array->back();
|
||||||
|
}
|
||||||
|
|
||||||
if (frames.empty())
|
if (frames.empty())
|
||||||
{
|
{
|
||||||
root = BasicJsonType(std::forward<Value>(v));
|
root = BasicJsonType(std::forward<Value>(v));
|
||||||
@@ -15492,19 +15513,6 @@ class json_sax_dom_parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
frame& f = frames.back();
|
frame& f = frames.back();
|
||||||
if (f.object != nullptr)
|
|
||||||
{
|
|
||||||
JSON_ASSERT(object_element);
|
|
||||||
*object_element = BasicJsonType(std::forward<Value>(v));
|
|
||||||
return object_element;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f.array != nullptr)
|
|
||||||
{
|
|
||||||
f.array->emplace_back(std::forward<Value>(v));
|
|
||||||
return &f.array->back();
|
|
||||||
}
|
|
||||||
|
|
||||||
elements.emplace_back(std::forward<Value>(v));
|
elements.emplace_back(std::forward<Value>(v));
|
||||||
if (JSON_HEDLEY_UNLIKELY(elements.size() - f.start > buffer_limit))
|
if (JSON_HEDLEY_UNLIKELY(elements.size() - f.start > buffer_limit))
|
||||||
{
|
{
|
||||||
@@ -15529,6 +15537,7 @@ class json_sax_dom_parser
|
|||||||
arr.insert(arr.end(), std::make_move_iterator(first), std::make_move_iterator(elements.end()));
|
arr.insert(arr.end(), std::make_move_iterator(first), std::make_move_iterator(elements.end()));
|
||||||
elements.erase(first, elements.end());
|
elements.erase(first, elements.end());
|
||||||
f.array = &arr;
|
f.array = &arr;
|
||||||
|
stored_array = &arr;
|
||||||
|
|
||||||
// the array takes the place its first element had on the stack
|
// the array takes the place its first element had on the stack
|
||||||
if (f.slot != nullptr)
|
if (f.slot != nullptr)
|
||||||
@@ -15551,6 +15560,22 @@ class json_sax_dom_parser
|
|||||||
return &arr.back();
|
return &arr.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// after a container was closed: the one it was in is the one that gets the next value
|
||||||
|
void enter_enclosing_container()
|
||||||
|
{
|
||||||
|
if (frames.empty())
|
||||||
|
{
|
||||||
|
in_object = false;
|
||||||
|
stored_array = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const frame& f = frames.back();
|
||||||
|
in_object = f.object != nullptr;
|
||||||
|
stored_array = f.array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
void handle_value(Value&& v)
|
void handle_value(Value&& v)
|
||||||
{
|
{
|
||||||
@@ -15571,6 +15596,11 @@ class json_sax_dom_parser
|
|||||||
std::vector<BasicJsonType> elements {};
|
std::vector<BasicJsonType> elements {};
|
||||||
/// helper to hold the reference for the next object element
|
/// helper to hold the reference for the next object element
|
||||||
BasicJsonType* object_element = nullptr;
|
BasicJsonType* object_element = nullptr;
|
||||||
|
/// whether the innermost container is an object (frames.back().object)
|
||||||
|
bool in_object = false;
|
||||||
|
/// the array that stores the elements of the innermost array as they
|
||||||
|
/// arrive (frames.back().array), or nullptr
|
||||||
|
array_t* stored_array = nullptr;
|
||||||
/// whether a syntax error occurred
|
/// whether a syntax error occurred
|
||||||
bool errored = false;
|
bool errored = false;
|
||||||
/// whether to throw exceptions in case of errors
|
/// whether to throw exceptions in case of errors
|
||||||
|
|||||||
Reference in new issue
Block a user