From 88de90a10e6cd320d69fc400d280fb296bfab46b Mon Sep 17 00:00:00 2001 From: Daniel Parker Date: Mon, 18 Nov 2024 14:02:20 -0500 Subject: [PATCH] json_pointer_arg --- include/jsoncons/basic_json.hpp | 508 ++++++++++++------ include/jsoncons/json_type.hpp | 9 +- include/jsoncons/tag_type.hpp | 7 + test/CMakeLists.txt | 3 +- ...s.cpp => json_const_pointer_arg_tests.cpp} | 28 +- test/corelib/src/json_pointer_arg_tests.cpp | 190 +++++++ test/corelib/src/json_storage_tests.cpp | 6 +- 7 files changed, 576 insertions(+), 175 deletions(-) rename test/corelib/src/{json_const_pointer_tests.cpp => json_const_pointer_arg_tests.cpp} (90%) create mode 100644 test/corelib/src/json_pointer_arg_tests.cpp diff --git a/include/jsoncons/basic_json.hpp b/include/jsoncons/basic_json.hpp index c045977fe..8df3b1040 100644 --- a/include/jsoncons/basic_json.hpp +++ b/include/jsoncons/basic_json.hpp @@ -816,7 +816,7 @@ namespace jsoncons { const basic_json* p_; json_const_pointer_storage(const basic_json* p) - : storage_kind_(static_cast(json_storage_kind::const_json_pointer)), short_str_length_(0), tag_(p->tag()), + : storage_kind_(static_cast(json_storage_kind::json_const_pointer)), short_str_length_(0), tag_(p->tag()), p_(p) { } @@ -827,6 +827,30 @@ namespace jsoncons { } }; + struct json_pointer_storage + { + uint8_t storage_kind_:4; + uint8_t short_str_length_:4; + semantic_tag tag_; + basic_json* p_; + + json_pointer_storage(basic_json* p) + : storage_kind_(static_cast(json_storage_kind::json_pointer)), short_str_length_(0), tag_(p->tag()), + p_(p) + { + } + + basic_json* value() + { + return p_; + } + + const basic_json* value() const + { + return p_; + } + }; + union { common_storage common_; @@ -843,6 +867,7 @@ namespace jsoncons { object_storage object_; empty_object_storage empty_object_; json_const_pointer_storage json_const_pointer_; + json_pointer_storage json_pointer_; }; void destroy() @@ -1087,11 +1112,21 @@ namespace jsoncons { return json_const_pointer_; } + json_pointer_storage& cast(identity) + { + return json_pointer_; + } + const json_const_pointer_storage& cast(identity) const { return json_const_pointer_; } + const json_pointer_storage& cast(identity) const + { + return json_pointer_; + } + template void swap_l_r(basic_json& other) noexcept { @@ -1123,7 +1158,8 @@ namespace jsoncons { case json_storage_kind::byte_str : swap_l_r(other); break; case json_storage_kind::array : swap_l_r(other); break; case json_storage_kind::object : swap_l_r(other); break; - case json_storage_kind::const_json_pointer : swap_l_r(other); break; + case json_storage_kind::json_const_pointer : swap_l_r(other); break; + case json_storage_kind::json_pointer : swap_l_r(other); break; default: JSONCONS_UNREACHABLE(); break; @@ -1415,8 +1451,10 @@ namespace jsoncons { case json_storage_kind::empty_object: case json_storage_kind::object: return json_type::object_value; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->type(); + case json_storage_kind::json_pointer: + return cast().value()->type(); default: JSONCONS_UNREACHABLE(); break; @@ -1431,8 +1469,10 @@ namespace jsoncons { // as defined in 11.4-25 of the Standard. switch(storage_kind()) { - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->tag(); + case json_storage_kind::json_pointer: + return cast().value()->tag(); default: return common_.tag_; } @@ -1448,8 +1488,10 @@ namespace jsoncons { return 0; case json_storage_kind::object: return cast().value().size(); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->size(); + case json_storage_kind::json_pointer: + return cast().value()->size(); default: return 0; } @@ -1463,8 +1505,10 @@ namespace jsoncons { return string_view_type(cast().data(),cast().length()); case json_storage_kind::long_str: return string_view_type(cast().data(),cast().length()); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->as_string_view(); + case json_storage_kind::json_pointer: + return cast().value()->as_string_view(); default: JSONCONS_THROW(json_runtime_error("Not a string")); } @@ -1491,8 +1535,10 @@ namespace jsoncons { } case json_storage_kind::byte_str: return basic_byte_string(cast().data(),cast().length()); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->as_byte_string(); + case json_storage_kind::json_pointer: + return cast().value()->as_byte_string(); default: JSONCONS_THROW(json_runtime_error("Not a byte string")); } @@ -1504,8 +1550,10 @@ namespace jsoncons { { case json_storage_kind::byte_str: return byte_string_view(cast().data(),cast().length()); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->as_byte_string_view(); + case json_storage_kind::json_pointer: + return cast().value()->as_byte_string_view(); default: JSONCONS_THROW(json_runtime_error("Not a byte string")); } @@ -1519,15 +1567,24 @@ namespace jsoncons { } switch (storage_kind()) { - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: switch (rhs.storage_kind()) { - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return (cast().value())->compare(*(rhs.cast().value())); default: return (cast().value())->compare(rhs); } break; + case json_storage_kind::json_pointer: + switch (rhs.storage_kind()) + { + case json_storage_kind::json_pointer: + return (cast().value())->compare(*(rhs.cast().value())); + default: + return (cast().value())->compare(rhs); + } + break; case json_storage_kind::null: return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); case json_storage_kind::empty_object: @@ -1537,8 +1594,10 @@ namespace jsoncons { return 0; case json_storage_kind::object: return rhs.empty() ? 0 : -1; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return compare(*(rhs.cast().value())); + case json_storage_kind::json_pointer: + return compare(*(rhs.cast().value())); default: return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); } @@ -1548,8 +1607,10 @@ namespace jsoncons { { case json_storage_kind::boolean: return static_cast(cast().value()) - static_cast(rhs.cast().value()); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return compare(*(rhs.cast().value())); + case json_storage_kind::json_pointer: + return compare(*(rhs.cast().value())); default: return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); } @@ -1575,8 +1636,10 @@ namespace jsoncons { double r = static_cast(cast().value()) - rhs.cast().value(); return r == 0.0 ? 0 : (r < 0.0 ? -1 : 1); } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return compare(*(rhs.cast().value())); + case json_storage_kind::json_pointer: + return compare(*(rhs.cast().value())); default: return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); } @@ -1601,8 +1664,10 @@ namespace jsoncons { auto r = static_cast(cast().value()) - rhs.cast().value(); return r == 0 ? 0 : (r < 0.0 ? -1 : 1); } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return compare(*(rhs.cast().value())); + case json_storage_kind::json_pointer: + return compare(*(rhs.cast().value())); default: return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); } @@ -1625,8 +1690,10 @@ namespace jsoncons { auto r = cast().value() - rhs.cast().value(); return r == 0 ? 0 : (r < 0.0 ? -1 : 1); } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return compare(*(rhs.cast().value())); + case json_storage_kind::json_pointer: + return compare(*(rhs.cast().value())); default: if (is_string_storage(rhs.storage_kind())) { @@ -1663,8 +1730,10 @@ namespace jsoncons { auto r = val1 - rhs.cast().value(); return r == 0 ? 0 : (r < 0.0 ? -1 : 1); } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return compare(*(rhs.cast().value())); + case json_storage_kind::json_pointer: + return compare(*(rhs.cast().value())); default: if (is_string_storage(rhs.storage_kind())) { @@ -1687,8 +1756,10 @@ namespace jsoncons { return as_string_view().compare(rhs.as_string_view()); case json_storage_kind::long_str: return as_string_view().compare(rhs.as_string_view()); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return compare(*(rhs.cast().value())); + case json_storage_kind::json_pointer: + return compare(*(rhs.cast().value())); default: return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); } @@ -1701,8 +1772,10 @@ namespace jsoncons { { return as_byte_string_view().compare(rhs.as_byte_string_view()); } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return compare(*(rhs.cast().value())); + case json_storage_kind::json_pointer: + return compare(*(rhs.cast().value())); default: return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); } @@ -1717,8 +1790,10 @@ namespace jsoncons { else return cast().value() < rhs.cast().value() ? -1 : 1; } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return compare(*(rhs.cast().value())); + case json_storage_kind::json_pointer: + return compare(*(rhs.cast().value())); default: return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); } @@ -1735,8 +1810,10 @@ namespace jsoncons { else return cast().value() < rhs.cast().value() ? -1 : 1; } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return compare(*(rhs.cast().value())); + case json_storage_kind::json_pointer: + return compare(*(rhs.cast().value())); default: return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); } @@ -1776,7 +1853,8 @@ namespace jsoncons { case json_storage_kind::byte_str: swap_l(other); break; case json_storage_kind::array: swap_l(other); break; case json_storage_kind::object: swap_l(other); break; - case json_storage_kind::const_json_pointer: swap_l(other); break; + case json_storage_kind::json_const_pointer: swap_l(other); break; + case json_storage_kind::json_pointer: swap_l(other); break; default: JSONCONS_UNREACHABLE(); break; @@ -2216,6 +2294,18 @@ namespace jsoncons { } } + basic_json(json_pointer_arg_t, basic_json* p) noexcept + { + if (p == nullptr) + { + construct(semantic_tag::none); + } + else + { + construct(p); + } + } + basic_json(const array& val, semantic_tag tag = semantic_tag::none) { auto ptr = create_array( @@ -2480,18 +2570,18 @@ namespace jsoncons { return at(i); } - basic_json& operator[](const string_view_type& name) + basic_json& operator[](const string_view_type& key) { switch (storage_kind()) { case json_storage_kind::empty_object: - return try_emplace(name, basic_json{}).first->value(); + return try_emplace(key, basic_json{}).first->value(); case json_storage_kind::object: { - auto it = cast().value().find(name); + auto it = cast().value().find(key); if (it == cast().value().end()) { - return try_emplace(name, basic_json{}).first->value(); + return try_emplace(key, basic_json{}).first->value(); } else { @@ -2500,12 +2590,12 @@ namespace jsoncons { break; } default: - JSONCONS_THROW(not_an_object(name.data(),name.length())); + JSONCONS_THROW(not_an_object(key.data(),key.length())); break; } } - const basic_json& operator[](const string_view_type& name) const + const basic_json& operator[](const string_view_type& key) const { static const basic_json an_empty_object = basic_json(); @@ -2515,7 +2605,7 @@ namespace jsoncons { return an_empty_object; case json_storage_kind::object: { - auto it = cast().value().find(name); + auto it = cast().value().find(key); if (it == cast().value().end()) { return an_empty_object; @@ -2527,12 +2617,11 @@ namespace jsoncons { break; } default: - JSONCONS_THROW(not_an_object(name.data(),name.length())); + JSONCONS_THROW(not_an_object(key.data(),key.length())); break; } } - template typename std::enable_if::value>::type dump(CharContainer& cont, @@ -2766,8 +2855,10 @@ namespace jsoncons { { case json_storage_kind::null: return true; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->is_null(); + case json_storage_kind::json_pointer: + return cast().value()->is_null(); default: return false; } @@ -2817,8 +2908,10 @@ namespace jsoncons { { return cast().ext_tag(); } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->ext_tag(); + case json_storage_kind::json_pointer: + return cast().value()->ext_tag(); default: return 0; } @@ -2833,8 +2926,10 @@ namespace jsoncons { auto it = cast().value().find(key); return it != cast().value().end(); } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->contains(key); + case json_storage_kind::json_pointer: + return cast().value()->contains(key); default: return false; } @@ -2859,8 +2954,10 @@ namespace jsoncons { } return count; } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->count(key); + case json_storage_kind::json_pointer: + return cast().value()->count(key); default: return 0; } @@ -2879,8 +2976,10 @@ namespace jsoncons { case json_storage_kind::short_str: case json_storage_kind::long_str: return true; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->is_string(); + case json_storage_kind::json_pointer: + return cast().value()->is_string(); default: return false; } @@ -2897,8 +2996,10 @@ namespace jsoncons { { case json_storage_kind::byte_str: return true; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->is_byte_string(); + case json_storage_kind::json_pointer: + return cast().value()->is_byte_string(); default: return false; } @@ -2919,8 +3020,8 @@ namespace jsoncons { case json_storage_kind::int64: case json_storage_kind::uint64: return true; - case json_storage_kind::const_json_pointer: - return cast().value()->is_bignum(); + case json_storage_kind::json_pointer: + return cast().value()->is_bignum(); default: return false; } @@ -2932,8 +3033,10 @@ namespace jsoncons { { case json_storage_kind::boolean: return true; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->is_bool(); + case json_storage_kind::json_pointer: + return cast().value()->is_bool(); default: return false; } @@ -2946,8 +3049,10 @@ namespace jsoncons { case json_storage_kind::empty_object: case json_storage_kind::object: return true; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->is_object(); + case json_storage_kind::json_pointer: + return cast().value()->is_object(); default: return false; } @@ -2959,8 +3064,10 @@ namespace jsoncons { { case json_storage_kind::array: return true; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->is_array(); + case json_storage_kind::json_pointer: + return cast().value()->is_array(); default: return false; } @@ -2974,8 +3081,10 @@ namespace jsoncons { return true; case json_storage_kind::uint64: return as_integer() <= static_cast((std::numeric_limits::max)()); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->is_int64(); + case json_storage_kind::json_pointer: + return cast().value()->is_int64(); default: return false; } @@ -2989,8 +3098,10 @@ namespace jsoncons { return true; case json_storage_kind::int64: return as_integer() >= 0; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->is_uint64(); + case json_storage_kind::json_pointer: + return cast().value()->is_uint64(); default: return false; } @@ -3002,8 +3113,10 @@ namespace jsoncons { { case json_storage_kind::half_float: return true; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->is_half(); + case json_storage_kind::json_pointer: + return cast().value()->is_half(); default: return false; } @@ -3015,8 +3128,10 @@ namespace jsoncons { { case json_storage_kind::float64: return true; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->is_double(); + case json_storage_kind::json_pointer: + return cast().value()->is_double(); default: return false; } @@ -3036,8 +3151,10 @@ namespace jsoncons { return tag() == semantic_tag::bigint || tag() == semantic_tag::bigdec || tag() == semantic_tag::bigfloat; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->is_number(); + case json_storage_kind::json_pointer: + return cast().value()->is_number(); default: return false; } @@ -3060,8 +3177,10 @@ namespace jsoncons { return true; case json_storage_kind::object: return cast().value().empty(); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->empty(); + case json_storage_kind::json_pointer: + return cast().value()->empty(); default: return false; } @@ -3075,8 +3194,10 @@ namespace jsoncons { return cast().value().capacity(); case json_storage_kind::object: return cast().value().capacity(); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->capacity(); + case json_storage_kind::json_pointer: + return cast().value()->capacity(); default: return 0; } @@ -3199,8 +3320,10 @@ namespace jsoncons { } case json_storage_kind::byte_str: return T(as_byte_string_view().begin(), as_byte_string_view().end()); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->template as(byte_string_arg, hint); + case json_storage_kind::json_pointer: + return cast().value()->template as(byte_string_arg, hint); default: JSONCONS_THROW(json_runtime_error("Not a byte string")); } @@ -3216,8 +3339,10 @@ namespace jsoncons { return cast().value() != 0; case json_storage_kind::uint64: return cast().value() != 0; - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->as_bool(); + case json_storage_kind::json_pointer: + return cast().value()->as_bool(); default: JSONCONS_THROW(json_runtime_error("Not a bool")); } @@ -3249,8 +3374,10 @@ namespace jsoncons { return static_cast(cast().value()); case json_storage_kind::boolean: return static_cast(cast().value() ? 1 : 0); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->template as_integer(); + case json_storage_kind::json_pointer: + return cast().value()->template as_integer(); default: JSONCONS_THROW(json_runtime_error("Not an integer")); } @@ -3266,8 +3393,10 @@ namespace jsoncons { return (as_integer() >= (extension_traits::integer_limits::lowest)()) && (as_integer() <= (extension_traits::integer_limits::max)()); case json_storage_kind::uint64: return as_integer() <= static_cast((extension_traits::integer_limits::max)()); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->template is_integer(); + case json_storage_kind::json_pointer: + return cast().value()->template is_integer(); default: return false; } @@ -3290,8 +3419,10 @@ namespace jsoncons { return (as_integer() >= (extension_traits::integer_limits::lowest)()) && (as_integer() <= (extension_traits::integer_limits::max)()); case json_storage_kind::uint64: return as_integer() <= static_cast((extension_traits::integer_limits::max)()); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->template is_integer(); + case json_storage_kind::json_pointer: + return cast().value()->template is_integer(); default: return false; } @@ -3307,8 +3438,10 @@ namespace jsoncons { return as_integer() >= 0 && static_cast(as_integer()) <= (extension_traits::integer_limits::max)(); case json_storage_kind::uint64: return as_integer() <= (extension_traits::integer_limits::max)(); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->template is_integer(); + case json_storage_kind::json_pointer: + return cast().value()->template is_integer(); default: return false; } @@ -3331,8 +3464,10 @@ namespace jsoncons { return as_integer() >= 0 && static_cast(as_integer()) <= (extension_traits::integer_limits::max)(); case json_storage_kind::uint64: return as_integer() <= (extension_traits::integer_limits::max)(); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->template is_integer(); + case json_storage_kind::json_pointer: + return cast().value()->template is_integer(); default: return false; } @@ -3357,8 +3492,10 @@ namespace jsoncons { return static_cast(cast().value()); case json_storage_kind::uint64: return static_cast(cast().value()); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->as_double(); + case json_storage_kind::json_pointer: + return cast().value()->as_double(); default: JSONCONS_THROW(json_runtime_error("Not a double")); } @@ -3402,8 +3539,10 @@ namespace jsoncons { } return s; } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->as_string(alloc); + case json_storage_kind::json_pointer: + return cast().value()->as_string(alloc); default: { string_type2 s(alloc); @@ -3422,31 +3561,35 @@ namespace jsoncons { return cast().c_str(); case json_storage_kind::long_str: return cast().c_str(); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->as_cstring(); + case json_storage_kind::json_pointer: + return cast().value()->as_cstring(); default: JSONCONS_THROW(json_runtime_error("Not a cstring")); } } - basic_json& at(const string_view_type& name) + basic_json& at(const string_view_type& key) { switch (storage_kind()) { case json_storage_kind::empty_object: - JSONCONS_THROW(key_not_found(name.data(),name.length())); + JSONCONS_THROW(key_not_found(key.data(),key.length())); case json_storage_kind::object: { - auto it = cast().value().find(name); + auto it = cast().value().find(key); if (it == cast().value().end()) { - JSONCONS_THROW(key_not_found(name.data(),name.length())); + JSONCONS_THROW(key_not_found(key.data(),key.length())); } return it->value(); } + case json_storage_kind::json_pointer: + return cast().value()->at(key); default: { - JSONCONS_THROW(not_an_object(name.data(),name.length())); + JSONCONS_THROW(not_an_object(key.data(),key.length())); } } } @@ -3466,8 +3609,10 @@ namespace jsoncons { } return it->value(); } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->at(key); + case json_storage_kind::json_pointer: + return cast().value()->at(key); default: { JSONCONS_THROW(not_an_object(key.data(),key.length())); @@ -3487,6 +3632,8 @@ namespace jsoncons { return cast().value().operator[](i); case json_storage_kind::object: return cast().value().at(i); + case json_storage_kind::json_pointer: + return cast().value()->at(i); default: JSONCONS_THROW(json_runtime_error("Index on non-array value not supported")); } @@ -3504,8 +3651,10 @@ namespace jsoncons { return cast().value().operator[](i); case json_storage_kind::object: return cast().value().at(i); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->at(i); + case json_storage_kind::json_pointer: + return cast().value()->at(i); default: JSONCONS_THROW(json_runtime_error("Index on non-array value not supported")); } @@ -3534,8 +3683,10 @@ namespace jsoncons { return object_range().end(); case json_storage_kind::object: return const_object_iterator(cast().value().find(key)); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->find(key); + case json_storage_kind::json_pointer: + return cast().value()->find(key); default: { JSONCONS_THROW(not_an_object(key.data(),key.length())); @@ -3564,8 +3715,10 @@ namespace jsoncons { return null(); } } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->at_or_null(key); + case json_storage_kind::json_pointer: + return cast().value()->at_or_null(key); default: { JSONCONS_THROW(not_an_object(key.data(),key.length())); @@ -3597,8 +3750,10 @@ namespace jsoncons { return static_cast(std::forward(default_value)); } } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->template get_value_or(key,std::forward(default_value)); + case json_storage_kind::json_pointer: + return cast().value()->template get_value_or(key,std::forward(default_value)); default: { JSONCONS_THROW(not_an_object(key.data(),key.length())); @@ -3612,14 +3767,17 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::array: - cast().value().shrink_to_fit(); - break; - case json_storage_kind::object: - cast().value().shrink_to_fit(); - break; - default: - break; + case json_storage_kind::array: + cast().value().shrink_to_fit(); + break; + case json_storage_kind::object: + cast().value().shrink_to_fit(); + break; + case json_storage_kind::json_pointer: + cast().value()->shrink_to_fit(); + break; + default: + break; } } @@ -3627,14 +3785,17 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::array: - cast().value().clear(); - break; - case json_storage_kind::object: - cast().value().clear(); - break; - default: - break; + case json_storage_kind::array: + cast().value().clear(); + break; + case json_storage_kind::object: + cast().value().clear(); + break; + case json_storage_kind::json_pointer: + cast().value()->clear(); + break; + default: + break; } } @@ -3642,10 +3803,12 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::empty_object: - return object_range().end(); - case json_storage_kind::object: - return object_iterator(cast().value().erase(pos)); + case json_storage_kind::empty_object: + return object_range().end(); + case json_storage_kind::object: + return object_iterator(cast().value().erase(pos)); + case json_storage_kind::json_pointer: + return cast().value()->erase(pos); default: JSONCONS_THROW(json_runtime_error("Not an object")); break; @@ -3656,13 +3819,15 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::empty_object: - return object_range().end(); - case json_storage_kind::object: - return object_iterator(cast().value().erase(first, last)); - default: - JSONCONS_THROW(json_runtime_error("Not an object")); - break; + case json_storage_kind::empty_object: + return object_range().end(); + case json_storage_kind::object: + return object_iterator(cast().value().erase(first, last)); + case json_storage_kind::json_pointer: + return cast().value()->erase(first, last); + default: + JSONCONS_THROW(json_runtime_error("Not an object")); + break; } } @@ -3670,10 +3835,12 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::array: - return cast().value().erase(pos); - default: - JSONCONS_THROW(json_runtime_error("Not an array")); + case json_storage_kind::array: + return cast().value().erase(pos); + case json_storage_kind::json_pointer: + return cast().value()->erase(pos); + default: + JSONCONS_THROW(json_runtime_error("Not an array")); } } @@ -3681,71 +3848,79 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::array: - return cast().value().erase(first, last); - default: - JSONCONS_THROW(json_runtime_error("Not an array")); - break; + case json_storage_kind::array: + return cast().value().erase(first, last); + case json_storage_kind::json_pointer: + return cast().value()->erase(first, last); + default: + JSONCONS_THROW(json_runtime_error("Not an array")); + break; } } // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. - void erase(const string_view_type& name) + void erase(const string_view_type& key) { switch (storage_kind()) { - case json_storage_kind::empty_object: - break; - case json_storage_kind::object: - cast().value().erase(name); - break; - default: - JSONCONS_THROW(not_an_object(name.data(),name.length())); - break; + case json_storage_kind::empty_object: + break; + case json_storage_kind::object: + cast().value().erase(key); + break; + case json_storage_kind::json_pointer: + return cast().value()->erase(key); + default: + JSONCONS_THROW(not_an_object(key.data(),key.length())); + break; } } template - std::pair insert_or_assign(const string_view_type& name, T&& val) + std::pair insert_or_assign(const string_view_type& key, T&& val) { switch (storage_kind()) { case json_storage_kind::empty_object: { create_object_implicitly(); - auto result = cast().value().insert_or_assign(name, std::forward(val)); + auto result = cast().value().insert_or_assign(key, std::forward(val)); return std::make_pair(object_iterator(result.first), result.second); } case json_storage_kind::object: { - auto result = cast().value().insert_or_assign(name, std::forward(val)); + auto result = cast().value().insert_or_assign(key, std::forward(val)); return std::make_pair(object_iterator(result.first), result.second); } + case json_storage_kind::json_pointer: + return cast().value()->insert_or_assign(key, std::forward(val)); default: - JSONCONS_THROW(not_an_object(name.data(),name.length())); - } + JSONCONS_THROW(not_an_object(key.data(),key.length())); + } } template - std::pair try_emplace(const string_view_type& name, Args&&... args) + std::pair try_emplace(const string_view_type& key, Args&&... args) { switch (storage_kind()) { case json_storage_kind::empty_object: { create_object_implicitly(); - auto result = cast().value().try_emplace(name, std::forward(args)...); + auto result = cast().value().try_emplace(key, std::forward(args)...); return std::make_pair(object_iterator(result.first),result.second); } case json_storage_kind::object: { - auto result = cast().value().try_emplace(name, std::forward(args)...); + auto result = cast().value().try_emplace(key, std::forward(args)...); return std::make_pair(object_iterator(result.first),result.second); } + case json_storage_kind::json_pointer: + return cast().value()->try_emplace(key, std::forward(args)...); default: - JSONCONS_THROW(not_an_object(name.data(),name.length())); - } + JSONCONS_THROW(not_an_object(key.data(),key.length())); + } } // merge @@ -3766,9 +3941,12 @@ namespace jsoncons { case json_storage_kind::object: cast().value().merge(source.cast().value()); break; + case json_storage_kind::json_pointer: + cast().value()->merge(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")); @@ -4047,11 +4225,13 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::array: - return cast().value().emplace(pos, std::forward(args)...); - 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().emplace(pos, std::forward(args)...); + break; + case json_storage_kind::json_pointer: + return cast().value()->emplace(pos, std::forward(args)...); + default: + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); } } @@ -4060,10 +4240,12 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::array: - return cast().value().emplace_back(std::forward(args)...); - 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().emplace_back(std::forward(args)...); + case json_storage_kind::json_pointer: + return cast().value()->emplace_back(std::forward(args)...); + default: + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); } } @@ -4077,11 +4259,14 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::array: - cast().value().push_back(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: + cast().value().push_back(std::forward(val)); + break; + case json_storage_kind::json_pointer: + cast().value()->push_back(std::forward(val)); + break; + default: + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); } } @@ -4089,11 +4274,14 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::array: - cast().value().push_back(std::move(val)); - break; - default: - JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + case json_storage_kind::array: + cast().value().push_back(std::move(val)); + break; + case json_storage_kind::json_pointer: + cast().value()->push_back(std::move(val)); + break; + default: + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); } } @@ -4116,13 +4304,15 @@ namespace jsoncons { { switch (storage_kind()) { - case json_storage_kind::empty_object: - return object_range_type(object_iterator(), object_iterator()); - case json_storage_kind::object: - return object_range_type(object_iterator(cast().value().begin()), - object_iterator(cast().value().end())); - default: - JSONCONS_THROW(json_runtime_error("Not an object")); + case json_storage_kind::empty_object: + return object_range_type(object_iterator(), object_iterator()); + case json_storage_kind::object: + return object_range_type(object_iterator(cast().value().begin()), + object_iterator(cast().value().end())); + case json_storage_kind::json_pointer: + return cast().value()->object_range(); + default: + JSONCONS_THROW(json_runtime_error("Not an object")); } } @@ -4135,8 +4325,10 @@ namespace jsoncons { case json_storage_kind::object: return const_object_range_type(const_object_iterator(cast().value().begin()), const_object_iterator(cast().value().end())); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->object_range(); + case json_storage_kind::json_pointer: + return cast().value()->object_range(); default: JSONCONS_THROW(json_runtime_error("Not an object")); } @@ -4149,6 +4341,8 @@ namespace jsoncons { case json_storage_kind::array: return array_range_type(cast().value().begin(), cast().value().end()); + case json_storage_kind::json_pointer: + return cast().value()->array_range(); default: JSONCONS_THROW(json_runtime_error("Not an array")); } @@ -4161,8 +4355,10 @@ namespace jsoncons { case json_storage_kind::array: return const_array_range_type(cast().value().begin(), cast().value().end()); - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->array_range(); + case json_storage_kind::json_pointer: + return cast().value()->array_range(); default: JSONCONS_THROW(json_runtime_error("Not an array")); } @@ -4241,8 +4437,10 @@ namespace jsoncons { } break; } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return cast().value()->dump_noflush(visitor, ec); + case json_storage_kind::json_pointer: + return cast().value()->dump_noflush(visitor, ec); default: break; } @@ -4294,8 +4492,10 @@ namespace jsoncons { } return j; } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: return deep_copy(*(other.cast().value())); + case json_storage_kind::json_pointer: + return deep_copy(*(other.cast().value())); default: return other; } diff --git a/include/jsoncons/json_type.hpp b/include/jsoncons/json_type.hpp index 01f9898ad..237553201 100644 --- a/include/jsoncons/json_type.hpp +++ b/include/jsoncons/json_type.hpp @@ -106,7 +106,8 @@ namespace jsoncons { float64 = 5, // 0101 half_float = 6, // 0110 short_str = 7, // 0111 - const_json_pointer = 8, // 1000 + json_const_pointer = 8, // 1000 + json_pointer = 9, // 1001 byte_str = 12, // 1100 object = 13, // 1101 array = 14, // 1110 @@ -141,7 +142,7 @@ namespace jsoncons { static constexpr const CharT* array_value = JSONCONS_CSTRING_CONSTANT(CharT, "array"); static constexpr const CharT* empty_object_value = JSONCONS_CSTRING_CONSTANT(CharT, "empty_object"); static constexpr const CharT* object_value = JSONCONS_CSTRING_CONSTANT(CharT, "object"); - static constexpr const CharT* const_json_pointer = JSONCONS_CSTRING_CONSTANT(CharT, "const_json_pointer"); + static constexpr const CharT* json_const_pointer = JSONCONS_CSTRING_CONSTANT(CharT, "json_const_pointer"); switch (storage) { @@ -205,9 +206,9 @@ namespace jsoncons { os << object_value; break; } - case json_storage_kind::const_json_pointer: + case json_storage_kind::json_const_pointer: { - os << const_json_pointer; + os << json_const_pointer; break; } } diff --git a/include/jsoncons/tag_type.hpp b/include/jsoncons/tag_type.hpp index 24111469c..0e4233e08 100644 --- a/include/jsoncons/tag_type.hpp +++ b/include/jsoncons/tag_type.hpp @@ -58,6 +58,13 @@ struct json_const_pointer_arg_t }; constexpr json_const_pointer_arg_t json_const_pointer_arg{}; + +struct json_pointer_arg_t +{ + explicit json_pointer_arg_t() = default; +}; + +constexpr json_pointer_arg_t json_pointer_arg{}; enum class semantic_tag : uint8_t { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index de2760485..7ac22d442 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -139,7 +139,8 @@ add_executable(unit_tests corelib/src/json_bitset_traits_tests.cpp corelib/src/json_checker_tests.cpp corelib/src/json_comparator_tests.cpp - corelib/src/json_const_pointer_tests.cpp + corelib/src/json_const_pointer_arg_tests.cpp + corelib/src/json_pointer_arg_tests.cpp corelib/src/json_assignment_tests.cpp corelib/src/json_constructor_tests.cpp corelib/src/json_cursor_tests.cpp diff --git a/test/corelib/src/json_const_pointer_tests.cpp b/test/corelib/src/json_const_pointer_arg_tests.cpp similarity index 90% rename from test/corelib/src/json_const_pointer_tests.cpp rename to test/corelib/src/json_const_pointer_arg_tests.cpp index dc6ffe8db..4a86f51af 100644 --- a/test/corelib/src/json_const_pointer_tests.cpp +++ b/test/corelib/src/json_const_pointer_arg_tests.cpp @@ -13,7 +13,7 @@ using namespace jsoncons; -TEST_CASE("const_json_pointer array tests") +TEST_CASE("json_const_pointer array tests") { json j = json::parse(R"( ["one", "two", "three"] )"); @@ -39,23 +39,23 @@ TEST_CASE("const_json_pointer array tests") SECTION("copy") { json v(json_const_pointer_arg, &j); - CHECK(v.storage_kind() == json_storage_kind::const_json_pointer); + CHECK(v.storage_kind() == json_storage_kind::json_const_pointer); json j2(v); - CHECK(j2.storage_kind() == json_storage_kind::const_json_pointer); + CHECK(j2.storage_kind() == json_storage_kind::json_const_pointer); } SECTION("assignment") { json v(json_const_pointer_arg, &j); - CHECK(v.storage_kind() == json_storage_kind::const_json_pointer); + CHECK(v.storage_kind() == json_storage_kind::json_const_pointer); json j2; j2 = v; - CHECK(j2.storage_kind() == json_storage_kind::const_json_pointer); + CHECK(j2.storage_kind() == json_storage_kind::json_const_pointer); } } -TEST_CASE("const_json_pointer object tests") +TEST_CASE("json_const_pointer object tests") { json j = json::parse(R"( {"one" : 1, "two" : 2, "three" : 3} )"); @@ -90,7 +90,7 @@ TEST_CASE("const_json_pointer object tests") } } -TEST_CASE("const_json_pointer string tests") +TEST_CASE("json_const_pointer string tests") { json j = json("Hello World"); @@ -104,7 +104,7 @@ TEST_CASE("const_json_pointer string tests") } } -TEST_CASE("const_json_pointer byte_string tests") +TEST_CASE("json_const_pointer byte_string tests") { std::string data = "abcdefghijk"; json j(byte_string_arg, data); @@ -117,7 +117,7 @@ TEST_CASE("const_json_pointer byte_string tests") } } -TEST_CASE("const_json_pointer bool tests") +TEST_CASE("json_const_pointer bool tests") { json tru(true); json fal(false); @@ -136,7 +136,7 @@ TEST_CASE("const_json_pointer bool tests") } } -TEST_CASE("const_json_pointer int64 tests") +TEST_CASE("json_const_pointer int64 tests") { json j(-100); @@ -148,7 +148,7 @@ TEST_CASE("const_json_pointer int64 tests") } } -TEST_CASE("const_json_pointer uint64 tests") +TEST_CASE("json_const_pointer uint64 tests") { json j(100); @@ -160,7 +160,7 @@ TEST_CASE("const_json_pointer uint64 tests") } } -TEST_CASE("const_json_pointer half tests") +TEST_CASE("json_const_pointer half tests") { json j(half_arg, 100); @@ -172,7 +172,7 @@ TEST_CASE("const_json_pointer half tests") } } -TEST_CASE("const_json_pointer double tests") +TEST_CASE("json_const_pointer double tests") { json j(123.456); @@ -220,7 +220,7 @@ namespace { } } -TEST_CASE("const_json_pointer identifier tests") +TEST_CASE("json_const_pointer identifier tests") { json source = json::parse(R"( {"reservations": [{ diff --git a/test/corelib/src/json_pointer_arg_tests.cpp b/test/corelib/src/json_pointer_arg_tests.cpp new file mode 100644 index 000000000..81335d56e --- /dev/null +++ b/test/corelib/src/json_pointer_arg_tests.cpp @@ -0,0 +1,190 @@ +// Copyright 2013-2024 Daniel Parker +// Distributed under Boost license + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace jsoncons; + +TEST_CASE("json_pointer array tests") +{ + json j = json::parse(R"( ["one", "two", "three"] )"); + + SECTION("size()") + { + json v(json_pointer_arg, &j); + REQUIRE(v.is_array()); + CHECK(v.size() == 3); + CHECK_FALSE(v.empty()); + } + SECTION("at()") + { + json v(json_pointer_arg, &j); + REQUIRE(v.is_array()); + REQUIRE_NOTHROW(v.at(1)); + } + SECTION("copy") + { + json v(json_pointer_arg, &j); + CHECK(v.storage_kind() == json_storage_kind::json_pointer); + + json j2(v); + CHECK(j2.storage_kind() == json_storage_kind::json_pointer); + } + SECTION("assignment") + { + json v(json_pointer_arg, &j); + CHECK(v.storage_kind() == json_storage_kind::json_pointer); + + json j2; + j2 = v; + CHECK(j2.storage_kind() == json_storage_kind::json_pointer); + } + SECTION("push_back") + { + json expected = json::parse(R"( ["one", "two", "three", "four"] )"); + + json v(json_pointer_arg, &j); + CHECK(v.storage_kind() == json_storage_kind::json_pointer); + j.push_back("four"); + + CHECK(expected == v); + } + SECTION("emplace_back") + { + json expected = json::parse(R"( ["one", "two", "three", "four"] )"); + + json v(json_pointer_arg, &j); + CHECK(v.storage_kind() == json_storage_kind::json_pointer); + j.emplace_back("four"); + + CHECK(expected == v); + } +} + +TEST_CASE("json_pointer object tests") +{ + json j = json::parse(R"( {"one" : 1, "two" : 2, "three" : 3} )"); + + SECTION("size()") + { + json v(json_pointer_arg, &j); + REQUIRE(v.is_object()); + CHECK(v.size() == 3); + CHECK_FALSE(v.empty()); + } + SECTION("at()") + { + json v(json_pointer_arg, &j); + REQUIRE(v.is_object()); + REQUIRE_NOTHROW(v.at("two")); + CHECK(v.contains("two")); + CHECK(v.count("two") == 1); + + CHECK(v.get_value_or("three", 0) == 3); + CHECK(v.get_value_or("four", 4) == 4); + } +} + +TEST_CASE("json_pointer string tests") +{ + json j = json("Hello World"); + + SECTION("is_string()") + { + json v(json_pointer_arg, &j); + REQUIRE(v.is_string()); + REQUIRE(v.is_string_view()); + + CHECK(v.as() == j.as()); + } +} + +TEST_CASE("json_pointer byte_string tests") +{ + std::string data = "abcdefghijk"; + json j(byte_string_arg, data); + + SECTION("is_byte_string()") + { + json v(json_pointer_arg, &j); + REQUIRE(v.is_byte_string()); + REQUIRE(v.is_byte_string_view()); + } +} + +TEST_CASE("json_pointer bool tests") +{ + json tru(true); + json fal(false); + + SECTION("true") + { + json v(json_pointer_arg, &tru); + REQUIRE(v.is_bool()); + CHECK(v.as_bool()); + } + SECTION("false") + { + json v(json_pointer_arg, &fal); + REQUIRE(v.is_bool()); + CHECK_FALSE(v.as_bool()); + } +} + +TEST_CASE("json_pointer int64 tests") +{ + json j(-100); + + SECTION("is_int64()") + { + json v(json_pointer_arg, &j); + REQUIRE(v.is_int64()); + CHECK(v.as() == -100); + } +} + +TEST_CASE("json_pointer uint64 tests") +{ + json j(100); + + SECTION("is_uint64()") + { + json v(json_pointer_arg, &j); + REQUIRE(v.is_uint64()); + CHECK(v.as() == 100); + } +} + +TEST_CASE("json_pointer half tests") +{ + json j(half_arg, 100); + + SECTION("is_half()") + { + json v(json_pointer_arg, &j); + REQUIRE(v.is_half()); + CHECK(v.as() == 100); + } +} + +TEST_CASE("json_pointer double tests") +{ + json j(123.456); + + SECTION("is_double()") + { + json v(json_pointer_arg, &j); + REQUIRE(v.is_double()); + + CHECK(v.as_double() == 123.456); + } +} + diff --git a/test/corelib/src/json_storage_tests.cpp b/test/corelib/src/json_storage_tests.cpp index c44cbe451..9c6a4b37f 100644 --- a/test/corelib/src/json_storage_tests.cpp +++ b/test/corelib/src/json_storage_tests.cpp @@ -20,7 +20,8 @@ TEST_CASE("test json_storage_kind") CHECK(is_trivial_storage(json_storage_kind::half_float)); CHECK(is_trivial_storage(json_storage_kind::short_str)); CHECK(is_trivial_storage(json_storage_kind::empty_object)); - CHECK(is_trivial_storage(json_storage_kind::const_json_pointer)); + CHECK(is_trivial_storage(json_storage_kind::json_const_pointer)); + CHECK(is_trivial_storage(json_storage_kind::json_pointer)); CHECK_FALSE(is_trivial_storage(json_storage_kind::long_str)); CHECK_FALSE(is_trivial_storage(json_storage_kind::byte_str)); CHECK_FALSE(is_trivial_storage(json_storage_kind::array)); @@ -35,7 +36,8 @@ TEST_CASE("test json_storage_kind") CHECK_FALSE(is_string_storage(json_storage_kind::half_float)); CHECK(is_string_storage(json_storage_kind::short_str)); CHECK_FALSE(is_string_storage(json_storage_kind::empty_object)); - CHECK_FALSE(is_string_storage(json_storage_kind::const_json_pointer)); + CHECK_FALSE(is_string_storage(json_storage_kind::json_const_pointer)); + CHECK_FALSE(is_string_storage(json_storage_kind::json_pointer)); CHECK(is_string_storage(json_storage_kind::long_str)); CHECK_FALSE(is_string_storage(json_storage_kind::byte_str)); CHECK_FALSE(is_string_storage(json_storage_kind::array));