Apply review feedback from Greg Marr on the json_value::destroy()
non-recursive, allocation-free destruction walk (#5135):
- last_child() now uses object->rbegin()->second instead of
std::prev(object->end())->second; pop_last_child() keeps
std::prev(end()) since erase() needs a forward iterator.
- is_empty_container() becomes has_no_children(), a switch that
returns true for every non-container type as well as empty
array/object, simplifying the "scalar or already-empty child"
check at the call site. The local variable `last` is renamed to
`cur_last_ref` for clarity.
- free_container() asserts the array/object is already empty before
freeing it, and the object branches assert the expected type.
- destroy(value_t t) is now a thin dispatcher to destroy_string(),
destroy_binary(), and destroy_container(t), each handling its own
"not initialized" check and sharing the simple cases first in the
switch.
- destroy_container() moves the top-level container into the local
stand-in via a plain swap of the json_value union, instead of a
manual copy plus clearing array/object by hand.
- The "cur has no children and there is no parent" case now frees
cur and returns immediately, so the main loop is a plain
while (true) with no trailing code after it.
Also adds edge-case tests for both json and ordered_json (mixes of
empty/non-empty arrays and objects, container children in first/last
position, single-element chains, top-level empty containers, and
destruction via erase()/assignment), plus a mixed-tree case in the
"destructor performs no allocation" test.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>