diff --git a/include/nlohmann/detail/json_metadata.hpp b/include/nlohmann/detail/json_metadata.hpp new file mode 100644 index 000000000..314eb673e --- /dev/null +++ b/include/nlohmann/detail/json_metadata.hpp @@ -0,0 +1,30 @@ +#pragma once + +namespace nlohmann +{ +namespace detail +{ +template +class json_metadata +{ + public: + using metadata_t = MetaDataType; + metadata_t& metadata() + { + return m_metadata; + } + const metadata_t& metadata() const + { + return m_metadata; + } + private: + metadata_t m_metadata; +}; + +template<> +class json_metadata +{ + //no metadata +}; +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 76a0dc62c..2fc57fb55 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -131,12 +131,13 @@ class NumberUnsignedType, class NumberFloatType, \ template class AllocatorType, \ template class JSONSerializer, \ - class BinaryType> + class BinaryType, \ + class MetaDataType> #define NLOHMANN_BASIC_JSON_TPL \ basic_json + AllocatorType, JSONSerializer, BinaryType, MetaDataType> // Macros to simplify conversion from/to types diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 053be8f74..d892580f9 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -63,6 +63,7 @@ SOFTWARE. #include #include #include +#include #include #include #include @@ -174,6 +175,7 @@ Format](https://tools.ietf.org/html/rfc8259) */ NLOHMANN_BASIC_JSON_TPL_DECLARATION class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + : public ::nlohmann::detail::json_metadata { private: template friend struct detail::external_constructor; @@ -196,6 +198,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// workaround type for MSVC using basic_json_t = NLOHMANN_BASIC_JSON_TPL; + using json_metadata_t = ::nlohmann::detail::json_metadata; JSON_PRIVATE_UNLESS_TESTED: // convenience aliases for types residing in namespace detail; @@ -2188,7 +2191,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 1.0.0 */ basic_json(const basic_json& other) - : m_type(other.m_type) + : json_metadata_t(other), + m_type(other.m_type) { // check of passed value is valid other.assert_invariant(); @@ -2280,7 +2284,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 1.0.0 */ basic_json(basic_json&& other) noexcept - : m_type(std::move(other.m_type)), + : json_metadata_t(std::move(other)), + m_type(std::move(other.m_type)), m_value(std::move(other.m_value)) { // check that passed value is valid @@ -2321,12 +2326,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec std::is_nothrow_move_constructible::value&& std::is_nothrow_move_assignable::value&& std::is_nothrow_move_constructible::value&& - std::is_nothrow_move_assignable::value + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_assignable::value ) { // check that passed value is valid other.assert_invariant(); + json_metadata_t::operator=(std::move(other)); + using std::swap; swap(m_type, other.m_type); swap(m_value, other.m_value); diff --git a/include/nlohmann/json_fwd.hpp b/include/nlohmann/json_fwd.hpp index 332227c1b..d06c1c8d1 100644 --- a/include/nlohmann/json_fwd.hpp +++ b/include/nlohmann/json_fwd.hpp @@ -34,7 +34,8 @@ template class ObjectType = template class AllocatorType = std::allocator, template class JSONSerializer = adl_serializer, - class BinaryType = std::vector> + class BinaryType = std::vector, + class MetaDataType = void> class basic_json; /*! diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 9c27aabbe..a37dc2504 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2343,12 +2343,13 @@ JSON_HEDLEY_DIAGNOSTIC_POP class NumberUnsignedType, class NumberFloatType, \ template class AllocatorType, \ template class JSONSerializer, \ - class BinaryType> + class BinaryType, \ + class MetaDataType> #define NLOHMANN_BASIC_JSON_TPL \ basic_json + AllocatorType, JSONSerializer, BinaryType, MetaDataType> // Macros to simplify conversion from/to types @@ -3380,7 +3381,8 @@ template class ObjectType = template class AllocatorType = std::allocator, template class JSONSerializer = adl_serializer, - class BinaryType = std::vector> + class BinaryType = std::vector, + class MetaDataType = void> class basic_json; /*! @@ -12354,6 +12356,38 @@ class json_reverse_iterator : public std::reverse_iterator // #include +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +class json_metadata +{ + public: + using metadata_t = MetaDataType; + metadata_t& metadata() + { + return m_metadata; + } + const metadata_t& metadata() const + { + return m_metadata; + } + private: + metadata_t m_metadata; +}; + +template<> +class json_metadata +{ + //no metadata +}; +} // namespace detail +} // namespace nlohmann + // #include @@ -17580,6 +17614,7 @@ Format](https://tools.ietf.org/html/rfc8259) */ NLOHMANN_BASIC_JSON_TPL_DECLARATION class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + : public ::nlohmann::detail::json_metadata { private: template friend struct detail::external_constructor; @@ -17602,6 +17637,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// workaround type for MSVC using basic_json_t = NLOHMANN_BASIC_JSON_TPL; + using json_metadata_t = ::nlohmann::detail::json_metadata; JSON_PRIVATE_UNLESS_TESTED: // convenience aliases for types residing in namespace detail; @@ -19594,7 +19630,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 1.0.0 */ basic_json(const basic_json& other) - : m_type(other.m_type) + : json_metadata_t(other), + m_type(other.m_type) { // check of passed value is valid other.assert_invariant(); @@ -19686,7 +19723,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 1.0.0 */ basic_json(basic_json&& other) noexcept - : m_type(std::move(other.m_type)), + : json_metadata_t(std::move(other)), + m_type(std::move(other.m_type)), m_value(std::move(other.m_value)) { // check that passed value is valid @@ -19727,12 +19765,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec std::is_nothrow_move_constructible::value&& std::is_nothrow_move_assignable::value&& std::is_nothrow_move_constructible::value&& - std::is_nothrow_move_assignable::value + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_assignable::value ) { // check that passed value is valid other.assert_invariant(); + json_metadata_t::operator=(std::move(other)); + using std::swap; swap(m_type, other.m_type); swap(m_value, other.m_value); diff --git a/test/src/unit-metadata.cpp b/test/src/unit-metadata.cpp new file mode 100644 index 000000000..bdb2d7f88 --- /dev/null +++ b/test/src/unit-metadata.cpp @@ -0,0 +1,185 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 3.10.2 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "doctest_compatibility.h" + +#include + +template +using json_with_metadata = + nlohmann::basic_json < + std::map, + std::vector, + std::string, + bool, + std::int64_t, + std::uint64_t, + double, + std::allocator, + nlohmann::adl_serializer, + std::vector, + T + >; + +TEST_CASE("JSON Node Metadata") +{ + SECTION("type int") + { + using json = json_with_metadata; + json null; + auto obj = json::object(); + auto array = json::array(); + + null.metadata() = 1; + obj.metadata() = 2; + array.metadata() = 3; + auto copy = array; + + CHECK(null.metadata() == 1); + CHECK(obj.metadata() == 2); + CHECK(array.metadata() == 3); + CHECK(copy.metadata() == 3); + } + SECTION("type vector") + { + using json = json_with_metadata>; + json value; + value.metadata().emplace_back(1); + auto copy = value; + value.metadata().emplace_back(2); + + CHECK(copy.metadata().size() == 1); + CHECK(copy.metadata().at(0) == 1); + CHECK(value.metadata().size() == 2); + CHECK(value.metadata().at(0) == 1); + CHECK(value.metadata().at(1) == 2); + } + SECTION("copy ctor") + { + using json = json_with_metadata>; + json value; + value.metadata().emplace_back(1); + value.metadata().emplace_back(2); + + json copy = value; + + CHECK(copy.metadata().size() == 2); + CHECK(copy.metadata().at(0) == 1); + CHECK(copy.metadata().at(1) == 2); + CHECK(value.metadata().size() == 2); + CHECK(value.metadata().at(0) == 1); + CHECK(value.metadata().at(1) == 2); + + value.metadata().clear(); + CHECK(copy.metadata().size() == 2); + CHECK(value.metadata().size() == 0); + } + SECTION("move ctor") + { + using json = json_with_metadata>; + json value; + value.metadata().emplace_back(1); + value.metadata().emplace_back(2); + + const json moved = std::move(value); + + CHECK(moved.metadata().size() == 2); + CHECK(moved.metadata().at(0) == 1); + CHECK(moved.metadata().at(1) == 2); + CHECK(value.metadata().size() == 0); + } + SECTION("move assign") + { + using json = json_with_metadata>; + json value; + value.metadata().emplace_back(1); + value.metadata().emplace_back(2); + + json moved; + moved = std::move(value); + + CHECK(moved.metadata().size() == 2); + CHECK(moved.metadata().at(0) == 1); + CHECK(moved.metadata().at(1) == 2); + CHECK(value.metadata().size() == 0); + } + SECTION("copy assign") + { + using json = json_with_metadata>; + json value; + value.metadata().emplace_back(1); + value.metadata().emplace_back(2); + + json copy; + copy = value; + + CHECK(copy.metadata().size() == 2); + CHECK(copy.metadata().at(0) == 1); + CHECK(copy.metadata().at(1) == 2); + CHECK(value.metadata().size() == 2); + CHECK(value.metadata().at(0) == 1); + CHECK(value.metadata().at(1) == 2); + + value.metadata().clear(); + CHECK(copy.metadata().size() == 2); + CHECK(value.metadata().size() == 0); + } + SECTION("type unique_ptr") + { + using json = json_with_metadata>; + json value; + value.metadata().reset(new int); + (*value.metadata()) = 42; + auto moved = std::move(value); + + CHECK(value.metadata() == nullptr); + CHECK(moved.metadata() != nullptr); + CHECK(*moved.metadata() == 42); + } + SECTION("type vector in json array") + { + using json = json_with_metadata>; + json value; + value.metadata().emplace_back(1); + value.metadata().emplace_back(2); + + json array(10, value); + + CHECK(value.metadata().size() == 2); + CHECK(value.metadata().at(0) == 1); + CHECK(value.metadata().at(1) == 2); + + for (const auto& val : array) + { + CHECK(val.metadata().size() == 2); + CHECK(val.metadata().at(0) == 1); + CHECK(val.metadata().at(1) == 2); + } + } +}