Unverified Commit c9c5c016 authored by Niels Lohmann's avatar Niels Lohmann Committed by GitHub

Merge pull request #2866 from nlohmann/issue2838

parents 4e92a617 a711e1f5
...@@ -1304,12 +1304,25 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -1304,12 +1304,25 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return it; return it;
} }
reference set_parent(reference j) reference set_parent(reference j, std::size_t old_capacity = std::size_t(-1))
{ {
#if JSON_DIAGNOSTICS #if JSON_DIAGNOSTICS
if (old_capacity != std::size_t(-1))
{
// see https://github.com/nlohmann/json/issues/2838
JSON_ASSERT(type() == value_t::array);
if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity))
{
// capacity has changed: update all parents
set_parents();
return j;
}
}
j.m_parent = this; j.m_parent = this;
#else #else
static_cast<void>(j); static_cast<void>(j);
static_cast<void>(old_capacity);
#endif #endif
return j; return j;
} }
...@@ -5371,8 +5384,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -5371,8 +5384,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// add element to array (move semantics) // add element to array (move semantics)
const auto old_capacity = m_value.array->capacity();
m_value.array->push_back(std::move(val)); m_value.array->push_back(std::move(val));
set_parent(m_value.array->back()); set_parent(m_value.array->back(), old_capacity);
// if val is moved from, basic_json move constructor marks it null so we do not call the destructor // if val is moved from, basic_json move constructor marks it null so we do not call the destructor
} }
...@@ -5407,8 +5421,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -5407,8 +5421,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// add element to array // add element to array
const auto old_capacity = m_value.array->capacity();
m_value.array->push_back(val); m_value.array->push_back(val);
set_parent(m_value.array->back()); set_parent(m_value.array->back(), old_capacity);
} }
/*! /*!
...@@ -5562,12 +5577,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -5562,12 +5577,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// add element to array (perfect forwarding) // add element to array (perfect forwarding)
#ifdef JSON_HAS_CPP_17 const auto old_capacity = m_value.array->capacity();
return set_parent(m_value.array->emplace_back(std::forward<Args>(args)...));
#else
m_value.array->emplace_back(std::forward<Args>(args)...); m_value.array->emplace_back(std::forward<Args>(args)...);
return set_parent(m_value.array->back()); return set_parent(m_value.array->back(), old_capacity);
#endif
} }
/*! /*!
...@@ -5643,6 +5655,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -5643,6 +5655,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
// but the return value of insert is missing in GCC 4.8, so it is written this way instead. // but the return value of insert is missing in GCC 4.8, so it is written this way instead.
set_parents();
return result; return result;
} }
...@@ -5680,7 +5693,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -5680,7 +5693,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// insert to array and return iterator // insert to array and return iterator
return set_parents(insert_iterator(pos, val), static_cast<typename iterator::difference_type>(1)); return insert_iterator(pos, val);
} }
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this));
...@@ -5731,7 +5744,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -5731,7 +5744,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// insert to array and return iterator // insert to array and return iterator
return set_parents(insert_iterator(pos, cnt, val), static_cast<typename iterator::difference_type>(cnt)); return insert_iterator(pos, cnt, val);
} }
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this));
...@@ -5793,7 +5806,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -5793,7 +5806,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// insert to array and return iterator // insert to array and return iterator
return set_parents(insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator), std::distance(first, last)); return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);
} }
/*! /*!
...@@ -5835,7 +5848,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -5835,7 +5848,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// insert to array and return iterator // insert to array and return iterator
return set_parents(insert_iterator(pos, ilist.begin(), ilist.end()), static_cast<typename iterator::difference_type>(ilist.size())); return insert_iterator(pos, ilist.begin(), ilist.end());
} }
/*! /*!
......
...@@ -18339,12 +18339,25 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -18339,12 +18339,25 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
return it; return it;
} }
reference set_parent(reference j) reference set_parent(reference j, std::size_t old_capacity = std::size_t(-1))
{ {
#if JSON_DIAGNOSTICS #if JSON_DIAGNOSTICS
if (old_capacity != std::size_t(-1))
{
// see https://github.com/nlohmann/json/issues/2838
JSON_ASSERT(type() == value_t::array);
if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity))
{
// capacity has changed: update all parents
set_parents();
return j;
}
}
j.m_parent = this; j.m_parent = this;
#else #else
static_cast<void>(j); static_cast<void>(j);
static_cast<void>(old_capacity);
#endif #endif
return j; return j;
} }
...@@ -22406,8 +22419,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -22406,8 +22419,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// add element to array (move semantics) // add element to array (move semantics)
const auto old_capacity = m_value.array->capacity();
m_value.array->push_back(std::move(val)); m_value.array->push_back(std::move(val));
set_parent(m_value.array->back()); set_parent(m_value.array->back(), old_capacity);
// if val is moved from, basic_json move constructor marks it null so we do not call the destructor // if val is moved from, basic_json move constructor marks it null so we do not call the destructor
} }
...@@ -22442,8 +22456,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -22442,8 +22456,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// add element to array // add element to array
const auto old_capacity = m_value.array->capacity();
m_value.array->push_back(val); m_value.array->push_back(val);
set_parent(m_value.array->back()); set_parent(m_value.array->back(), old_capacity);
} }
/*! /*!
...@@ -22597,12 +22612,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -22597,12 +22612,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// add element to array (perfect forwarding) // add element to array (perfect forwarding)
#ifdef JSON_HAS_CPP_17 const auto old_capacity = m_value.array->capacity();
return set_parent(m_value.array->emplace_back(std::forward<Args>(args)...));
#else
m_value.array->emplace_back(std::forward<Args>(args)...); m_value.array->emplace_back(std::forward<Args>(args)...);
return set_parent(m_value.array->back()); return set_parent(m_value.array->back(), old_capacity);
#endif
} }
/*! /*!
...@@ -22678,6 +22690,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -22678,6 +22690,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
// but the return value of insert is missing in GCC 4.8, so it is written this way instead. // but the return value of insert is missing in GCC 4.8, so it is written this way instead.
set_parents();
return result; return result;
} }
...@@ -22715,7 +22728,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -22715,7 +22728,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// insert to array and return iterator // insert to array and return iterator
return set_parents(insert_iterator(pos, val), static_cast<typename iterator::difference_type>(1)); return insert_iterator(pos, val);
} }
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this));
...@@ -22766,7 +22779,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -22766,7 +22779,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// insert to array and return iterator // insert to array and return iterator
return set_parents(insert_iterator(pos, cnt, val), static_cast<typename iterator::difference_type>(cnt)); return insert_iterator(pos, cnt, val);
} }
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this));
...@@ -22828,7 +22841,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -22828,7 +22841,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// insert to array and return iterator // insert to array and return iterator
return set_parents(insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator), std::distance(first, last)); return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);
} }
/*! /*!
...@@ -22870,7 +22883,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -22870,7 +22883,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
// insert to array and return iterator // insert to array and return iterator
return set_parents(insert_iterator(pos, ilist.begin(), ilist.end()), static_cast<typename iterator::difference_type>(ilist.size())); return insert_iterator(pos, ilist.begin(), ilist.end());
} }
/*! /*!
......
...@@ -109,4 +109,69 @@ TEST_CASE("Better diagnostics") ...@@ -109,4 +109,69 @@ TEST_CASE("Better diagnostics")
j["/foo"] = {1, 2, 3}; j["/foo"] = {1, 2, 3};
CHECK_THROWS_WITH_AS(j.unflatten(), "[json.exception.type_error.315] (/~1foo) values in object must be primitive", json::type_error); CHECK_THROWS_WITH_AS(j.unflatten(), "[json.exception.type_error.315] (/~1foo) values in object must be primitive", json::type_error);
} }
SECTION("Regression test for https://github.com/nlohmann/json/issues/2838")
{
// void push_back(basic_json&& val)
{
json j_arr = json::array();
j_arr.push_back(json::object());
j_arr.push_back(json::object());
j_arr.push_back(json::object());
j_arr.push_back(json::object());
json j_obj = json::object();
j_obj["key"] = j_arr;
}
// void push_back(const basic_json& val)
{
json j_arr = json::array();
auto object = json::object();
j_arr.push_back(object);
j_arr.push_back(object);
j_arr.push_back(object);
j_arr.push_back(object);
json j_obj = json::object();
j_obj["key"] = j_arr;
}
// reference emplace_back(Args&& ... args)
{
json j_arr = json::array();
j_arr.emplace_back(json::object());
j_arr.emplace_back(json::object());
j_arr.emplace_back(json::object());
j_arr.emplace_back(json::object());
json j_obj = json::object();
j_obj["key"] = j_arr;
}
// iterator insert(const_iterator pos, const basic_json& val)
{
json j_arr = json::array();
j_arr.insert(j_arr.begin(), json::object());
j_arr.insert(j_arr.begin(), json::object());
j_arr.insert(j_arr.begin(), json::object());
j_arr.insert(j_arr.begin(), json::object());
json j_obj = json::object();
j_obj["key"] = j_arr;
}
// iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
{
json j_arr = json::array();
j_arr.insert(j_arr.begin(), 2, json::object());
json j_obj = json::object();
j_obj["key"] = j_arr;
}
// iterator insert(const_iterator pos, const_iterator first, const_iterator last)
{
json j_arr = json::array();
json j_objects = {json::object(), json::object()};
j_arr.insert(j_arr.begin(), j_objects.begin(), j_objects.end());
json j_obj = json::object();
j_obj["key"] = j_arr;
}
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment