diff --git a/include/json/value.h b/include/json/value.h index e3c3d2b7e..5c10163e4 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -464,6 +464,8 @@ class JSON_API Value { /// Equivalent to jsonvalue[jsonvalue.size()] = value; Value& append(const Value& value); Value& append(Value&& value); + /// \brief Insert value in array at specific index + bool insert(ArrayIndex index, Value newValue); /// Access an object value by name, create a null member if it does not exist. /// \note Because of our implementation, keys are limited to 2^30 -1 chars. diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 9518ab828..00d28f774 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -1148,6 +1148,7 @@ Value const& Value::operator[](CppTL::ConstString const& key) const { #endif Value& Value::append(const Value& value) { return append(Value(value)); } + Value& Value::append(Value&& value) { JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, "in Json::Value::append: requires arrayValue"); @@ -1157,6 +1158,21 @@ Value& Value::append(Value&& value) { return this->value_.map_->emplace(size(), std::move(value)).first->second; } +bool Value::insert(ArrayIndex index, Value newValue) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, + "in Json::Value::insert: requires arrayValue"); + ArrayIndex length = size(); + if (index > length) { + return false; + } else { + for (ArrayIndex i = length; i > index; i--) { + (*this)[i] = std::move((*this)[i - 1]); + } + (*this)[index] = std::move(newValue); + return true; + } +} + Value Value::get(char const* begin, char const* end, Value const& defaultValue) const { Value const* found = find(begin, end); diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index c79ad1ea4..f32a11fbf 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -327,6 +327,63 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, arrayIssue252) { // JSONTEST_ASSERT_EQUAL(5, root["array"].size()); } +JSONTEST_FIXTURE_LOCAL(ValueTest, arrayInsertAtRandomIndex) { + Json::Value array; + const Json::Value str0("index2"); + const Json::Value str1("index3"); + array.append("index0"); // append rvalue + array.append("index1"); + array.append(str0); // append lvalue + + std::vector vec; // storage value address for checking + for (int i = 0; i < 3; i++) { + vec.push_back(&array[i]); + } + JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[0]); // check append + JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[1]); + JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[2]); + + // insert lvalue at the head + JSONTEST_ASSERT(array.insert(0, str1)); + JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array[0]); + JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[1]); + JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[2]); + JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[3]); + // checking address + for (int i = 0; i < 3; i++) { + JSONTEST_ASSERT_EQUAL(vec[i], &array[i]); + } + vec.push_back(&array[3]); + // insert rvalue at middle + JSONTEST_ASSERT(array.insert(2, "index4")); + JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array[0]); + JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[1]); + JSONTEST_ASSERT_EQUAL(Json::Value("index4"), array[2]); + JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[3]); + JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[4]); + // checking address + for (int i = 0; i < 4; i++) { + JSONTEST_ASSERT_EQUAL(vec[i], &array[i]); + } + vec.push_back(&array[4]); + // insert rvalue at the tail + Json::Value index5("index5"); + JSONTEST_ASSERT(array.insert(5, std::move(index5))); + JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array[0]); + JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[1]); + JSONTEST_ASSERT_EQUAL(Json::Value("index4"), array[2]); + JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[3]); + JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[4]); + JSONTEST_ASSERT_EQUAL(Json::Value("index5"), array[5]); + // checking address + for (int i = 0; i < 5; i++) { + JSONTEST_ASSERT_EQUAL(vec[i], &array[i]); + } + vec.push_back(&array[5]); + // beyond max array size, it should not be allowed to insert into its tail + JSONTEST_ASSERT(!array.insert(10, "index10")); +} + JSONTEST_FIXTURE_LOCAL(ValueTest, null) { JSONTEST_ASSERT_EQUAL(Json::nullValue, null_.type());