A failed allocation while the new elements were copied left the value
changed, and with JSON_DIAGNOSTICS stale parent pointers behind. The
extra work now happens almost only on the failure path:
- Array insert(pos, cnt, val) and insert(pos, first, last) append the
copies at the end and rotate them into place. If a copy throws, the
appended elements are erased again (noexcept) and the parents are set.
Moving a basic_json cannot throw, so reallocation is safe. This is no
slower than vector::insert (faster for numbers), needs no temporary
array, and keeps the elements that libstdc++ lost on reallocation.
- Array insert(pos, val) copies a non-scalar value first and inserts it
by move, except at the end, where vector::insert is strong. Scalars
keep the direct path.
- The object range insert(first, last) into an empty object uses the
container's own range insertion and clears the object on an exception.
Into a non-empty object it inserts member by member and logs one bit
per source member (a new member is detected by the size change; no
allocation for the first 256 members); on an exception the members
added are erased by walking the source range. No assumption that
key_type is string_t.
- The parents are set when a failed insertion is undone.
The regression test fails every allocation of every insert() overload in
turn, for json and ordered_json, and checks the value and its parents.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>