diff --git a/include/jsoncons/basic_json.hpp b/include/jsoncons/basic_json.hpp index dffe31ddd..5d78ac666 100644 --- a/include/jsoncons/basic_json.hpp +++ b/include/jsoncons/basic_json.hpp @@ -2161,7 +2161,7 @@ namespace jsoncons { static const basic_json& null() { - static const basic_json a_null = basic_json(null_type(), semantic_tag::none); + static const basic_json a_null = basic_json(null_arg, semantic_tag::none); return a_null; } @@ -2582,6 +2582,8 @@ namespace jsoncons { } break; } + case json_storage_kind::json_reference: + return cast().value()[key]; default: JSONCONS_THROW(not_an_object(key.data(),key.length())); break; @@ -2609,6 +2611,10 @@ namespace jsoncons { } break; } + case json_storage_kind::json_const_pointer: + return *(cast().value())[key]; + case json_storage_kind::json_reference: + return cast().value()[key]; default: JSONCONS_THROW(not_an_object(key.data(),key.length())); break; @@ -2873,21 +2879,15 @@ namespace jsoncons { switch (storage_kind()) { case json_storage_kind::long_str: - { return cast().get_allocator(); - } case json_storage_kind::byte_str: - { return cast().get_allocator(); - } case json_storage_kind::array: - { return cast().get_allocator(); - } case json_storage_kind::object: - { return cast().get_allocator(); - } + case json_storage_kind::json_reference: + return cast().value().get_allocator(); default: return get_default_allocator(typename std::allocator_traits::is_always_equal()); } @@ -3222,15 +3222,14 @@ namespace jsoncons { cast().value().reserve(n); break; case json_storage_kind::empty_object: - { create_object_implicitly(); cast().value().reserve(n); - } - break; + break; case json_storage_kind::object: - { cast().value().reserve(n); - } + break; + case json_storage_kind::json_reference: + cast().value().reserve(n); break; default: break; @@ -3245,6 +3244,9 @@ namespace jsoncons { case json_storage_kind::array: cast().value().resize(n); break; + case json_storage_kind::json_reference: + cast().value().resize(n); + break; default: break; } @@ -3258,6 +3260,9 @@ namespace jsoncons { case json_storage_kind::array: cast().value().resize(n, val); break; + case json_storage_kind::json_reference: + cast().value().resize(n, val); + break; default: break; } @@ -3653,17 +3658,19 @@ namespace jsoncons { } } - object_iterator find(const string_view_type& name) + object_iterator find(const string_view_type& key) { switch (storage_kind()) { case json_storage_kind::empty_object: return object_range().end(); case json_storage_kind::object: - return object_iterator(cast().value().find(name)); + return object_iterator(cast().value().find(key)); + case json_storage_kind::json_reference: + return cast().value().find(key); default: { - JSONCONS_THROW(not_an_object(name.data(),name.length())); + JSONCONS_THROW(not_an_object(key.data(),key.length())); } } } @@ -3935,7 +3942,7 @@ namespace jsoncons { cast().value().merge(source.cast().value()); break; case json_storage_kind::json_reference: - cast().value().merge(source.cast().value()); + merge(source.cast().value()); break; default: JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); @@ -3962,12 +3969,15 @@ namespace jsoncons { case json_storage_kind::object: cast().value().merge(std::move(source.cast().value())); break; + case json_storage_kind::json_reference: + merge(std::move(source.cast().value())); + break; default: JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); } break; - default: - JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); + default: + JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); } } @@ -3987,6 +3997,9 @@ namespace jsoncons { case json_storage_kind::object: cast().value().merge(hint, source.cast().value()); break; + case json_storage_kind::json_reference: + merge(hint, source.cast().value()); + break; default: JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); } @@ -4012,6 +4025,9 @@ namespace jsoncons { case json_storage_kind::object: cast().value().merge(hint, std::move(source.cast().value())); break; + case json_storage_kind::json_reference: + merge(hint, std::move(source.cast().value())); + break; default: JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); } @@ -4039,6 +4055,9 @@ namespace jsoncons { case json_storage_kind::object: cast().value().merge_or_update(source.cast().value()); break; + case json_storage_kind::json_reference: + merge_or_update(source.cast().value()); + break; default: JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); } @@ -4057,15 +4076,18 @@ namespace jsoncons { case json_storage_kind::object: switch (storage_kind()) { - case json_storage_kind::empty_object: - create_object_implicitly(); - cast().value().merge_or_update(std::move(source.cast().value())); - break; - case json_storage_kind::object: - cast().value().merge_or_update(std::move(source.cast().value())); - break; - default: - JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); + case json_storage_kind::empty_object: + create_object_implicitly(); + cast().value().merge_or_update(std::move(source.cast().value())); + break; + case json_storage_kind::object: + cast().value().merge_or_update(std::move(source.cast().value())); + break; + case json_storage_kind::json_reference: + merge_or_update(std::move(source.cast().value())); + break; + default: + JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); } break; default: @@ -4089,6 +4111,9 @@ namespace jsoncons { case json_storage_kind::object: cast().value().merge_or_update(hint, source.cast().value()); break; + case json_storage_kind::json_reference: + merge_or_update(hint, source.cast().value()); + break; default: JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); } @@ -4114,6 +4139,9 @@ namespace jsoncons { case json_storage_kind::object: cast().value().merge_or_update(hint, std::move(source.cast().value())); break; + case json_storage_kind::json_reference: + merge_or_update(hint, std::move(source.cast().value())); + break; default: JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); } @@ -4128,13 +4156,15 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::empty_object: - create_object_implicitly(); - return object_iterator(cast().value().insert_or_assign(hint, name, std::forward(val))); - case json_storage_kind::object: - return object_iterator(cast().value().insert_or_assign(hint, name, std::forward(val))); - default: - JSONCONS_THROW(not_an_object(name.data(),name.length())); + case json_storage_kind::empty_object: + create_object_implicitly(); + return object_iterator(cast().value().insert_or_assign(hint, name, std::forward(val))); + case json_storage_kind::object: + return object_iterator(cast().value().insert_or_assign(hint, name, std::forward(val))); + case json_storage_kind::json_reference: + return object_iterator(cast().value().insert_or_assign(hint, name, std::forward(val))); + default: + JSONCONS_THROW(not_an_object(name.data(),name.length())); } } @@ -4143,13 +4173,15 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::empty_object: - create_object_implicitly(); - return object_iterator(cast().value().try_emplace(hint, name, std::forward(args)...)); - case json_storage_kind::object: - return object_iterator(cast().value().try_emplace(hint, name, std::forward(args)...)); - default: - JSONCONS_THROW(not_an_object(name.data(),name.length())); + case json_storage_kind::empty_object: + create_object_implicitly(); + return object_iterator(cast().value().try_emplace(hint, name, std::forward(args)...)); + case json_storage_kind::object: + return object_iterator(cast().value().try_emplace(hint, name, std::forward(args)...)); + case json_storage_kind::json_reference: + return object_iterator(cast().value().try_emplace(hint, name, std::forward(args)...)); + default: + JSONCONS_THROW(not_an_object(name.data(),name.length())); } } @@ -4158,11 +4190,14 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::array: - return cast().value().insert(pos, std::forward(val)); - break; - default: - JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + case json_storage_kind::array: + return cast().value().insert(pos, std::forward(val)); + break; + case json_storage_kind::json_reference: + return cast().value().insert(pos, std::forward(val)); + break; + default: + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); } } @@ -4171,11 +4206,14 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::array: - return cast().value().insert(pos, first, last); - break; - default: - JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + case json_storage_kind::array: + return cast().value().insert(pos, first, last); + break; + case json_storage_kind::json_reference: + return cast().value().insert(pos, first, last); + break; + default: + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); } } @@ -4184,15 +4222,18 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::empty_object: - create_object_implicitly(); - cast().value().insert(first, last); - break; - case json_storage_kind::object: - cast().value().insert(first, last); - break; - default: - JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an object")); + case json_storage_kind::empty_object: + create_object_implicitly(); + cast().value().insert(first, last); + break; + case json_storage_kind::object: + cast().value().insert(first, last); + break; + case json_storage_kind::json_reference: + cast().value().insert(first, last); + break; + default: + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an object")); } } @@ -4201,15 +4242,18 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::empty_object: - create_object_implicitly(); - cast().value().insert(tag, first, last); - break; - case json_storage_kind::object: - cast().value().insert(tag, first, last); - break; - default: - JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an object")); + case json_storage_kind::empty_object: + create_object_implicitly(); + cast().value().insert(tag, first, last); + break; + case json_storage_kind::object: + cast().value().insert(tag, first, last); + break; + case json_storage_kind::json_reference: + cast().value().insert(tag, first, last); + break; + default: + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an object")); } } diff --git a/include/jsoncons/tag_type.hpp b/include/jsoncons/tag_type.hpp index 94b319416..863aaa251 100644 --- a/include/jsoncons/tag_type.hpp +++ b/include/jsoncons/tag_type.hpp @@ -17,6 +17,8 @@ struct null_type explicit null_type() = default; }; +constexpr null_type null_arg{}; + struct temp_allocator_arg_t { explicit temp_allocator_arg_t() = default; diff --git a/test/corelib/src/json_reference_arg_tests.cpp b/test/corelib/src/json_reference_arg_tests.cpp index b2904aa5d..5d3770f79 100644 --- a/test/corelib/src/json_reference_arg_tests.cpp +++ b/test/corelib/src/json_reference_arg_tests.cpp @@ -13,22 +13,86 @@ using namespace jsoncons; -TEST_CASE("json_pointer array tests") +TEST_CASE("json_reference array tests") { - json j = json::parse(R"( ["one", "two", "three"] )"); + json j = json::parse(R"( [1, "two", "three"] )"); SECTION("size()") { json v(json_reference_arg, j); REQUIRE(v.is_array()); - CHECK(v.size() == 3); + CHECK(v.get_allocator() == j.get_allocator()); + REQUIRE(j.size() == v.size()); + v.resize(4); + REQUIRE(4 == v.size()); + CHECK(json{} == v[3]); + + v.resize(5, json{jsoncons::null_arg}); + REQUIRE(5 == v.size()); + CHECK(json{} == v[3]); + CHECK(json::null() == v[4]); + CHECK(v[4].is_null()); + } + SECTION("capacity()") + { + json v(json_reference_arg, j); + REQUIRE(v.is_array()); + CHECK(j.capacity() == v.capacity()); + v.reserve(4); + REQUIRE(4 == v.capacity()); + } + + SECTION("empty()") + { + json v(json_reference_arg, j); + REQUIRE(v.is_array()); CHECK_FALSE(v.empty()); } + + SECTION("is_int64()") + { + json v(json_reference_arg, j); + REQUIRE(v.is_array()); + CHECK(v[0].is_int64()); + CHECK_FALSE(v[1].is_int64()); + } + SECTION("is_number()") + { + json v(json_reference_arg, j); + REQUIRE(v.is_array()); + CHECK(v[0].is_number()); + CHECK_FALSE(v[1].is_number()); + } + SECTION("operator[]") + { + json expected = json::parse(R"( [1, "two", "four"] )"); + + json v(json_reference_arg, j); + CHECK(v.storage_kind() == json_storage_kind::json_reference); + j[2] = "four"; + + CHECK(expected == v); + } + SECTION("const operator[]") + { + const json v(json_reference_arg, j); + CHECK(v.storage_kind() == json_storage_kind::json_reference); + + CHECK("three" == v[2]); + } SECTION("at()") { json v(json_reference_arg, j); REQUIRE(v.is_array()); REQUIRE_NOTHROW(v.at(1)); + CHECK("two" == v[1]); + } + SECTION("const at()") + { + const json v(json_reference_arg, j); + REQUIRE(v.is_array()); + REQUIRE_NOTHROW(v.at(1)); + CHECK("two" == v[1]); } SECTION("copy") { @@ -49,7 +113,7 @@ TEST_CASE("json_pointer array tests") } SECTION("push_back") { - json expected = json::parse(R"( ["one", "two", "three", "four"] )"); + json expected = json::parse(R"( [1, "two", "three", "four"] )"); json v(json_reference_arg, j); CHECK(v.storage_kind() == json_storage_kind::json_reference); @@ -59,7 +123,7 @@ TEST_CASE("json_pointer array tests") } SECTION("emplace_back") { - json expected = json::parse(R"( ["one", "two", "three", "four"] )"); + json expected = json::parse(R"( [1, "two", "three", "four"] )"); json v(json_reference_arg, j); CHECK(v.storage_kind() == json_storage_kind::json_reference); @@ -69,7 +133,7 @@ TEST_CASE("json_pointer array tests") } } -TEST_CASE("json_pointer object tests") +TEST_CASE("json_reference object tests") { json j = json::parse(R"( {"one" : 1, "two" : 2, "three" : 3} )"); @@ -90,10 +154,13 @@ TEST_CASE("json_pointer object tests") CHECK(v.get_value_or("three", 0) == 3); CHECK(v.get_value_or("four", 4) == 4); + + v.at("one") = "first"; + CHECK("first" == v.at("one")); } } -TEST_CASE("json_pointer string tests") +TEST_CASE("json_reference string tests") { json j = json("Hello World"); @@ -107,7 +174,7 @@ TEST_CASE("json_pointer string tests") } } -TEST_CASE("json_pointer byte_string tests") +TEST_CASE("json_reference byte_string tests") { std::string data = "abcdefghijk"; json j(byte_string_arg, data); @@ -120,7 +187,7 @@ TEST_CASE("json_pointer byte_string tests") } } -TEST_CASE("json_pointer bool tests") +TEST_CASE("json_reference bool tests") { json tru(true); json fal(false); @@ -139,7 +206,18 @@ TEST_CASE("json_pointer bool tests") } } -TEST_CASE("json_pointer int64 tests") +TEST_CASE("json_reference null tests") +{ + json null(jsoncons::null_arg); + + SECTION("null") + { + json v(json_reference_arg, null); + REQUIRE(v.is_null()); + } +} + +TEST_CASE("json_reference int64 tests") { json j(-100); @@ -151,7 +229,7 @@ TEST_CASE("json_pointer int64 tests") } } -TEST_CASE("json_pointer uint64 tests") +TEST_CASE("json_reference uint64 tests") { json j(100); @@ -163,7 +241,7 @@ TEST_CASE("json_pointer uint64 tests") } } -TEST_CASE("json_pointer half tests") +TEST_CASE("json_reference half tests") { json j(half_arg, 100); @@ -175,7 +253,7 @@ TEST_CASE("json_pointer half tests") } } -TEST_CASE("json_pointer double tests") +TEST_CASE("json_reference double tests") { json j(123.456);