From c850e9d82db4af16d995a455d8c0d20fb4c8448d Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Thu, 31 Jan 2019 19:15:36 +0000 Subject: [PATCH] Add operator/= and operator/ to construct a JSON pointer by appending two JSON pointers, as well as convenience op/= and op= to append a single unescaped token or array index; inspired by std::filesystem::path --- include/nlohmann/detail/json_pointer.hpp | 74 +++++++++++++++++------- single_include/nlohmann/json.hpp | 74 +++++++++++++++++------- test/src/unit-json_pointer.cpp | 20 +++++-- 3 files changed, 120 insertions(+), 48 deletions(-) diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 705346c50..8ec4179e2 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -76,6 +76,52 @@ class json_pointer return to_string(); } + /*! + @brief append another JSON pointer at the end of this JSON pointer + */ + json_pointer& operator/=(const json_pointer& ptr) + { + reference_tokens.insert(reference_tokens.end(), ptr.reference_tokens.begin(), ptr.reference_tokens.end()); + return *this; + } + + /// @copydoc push_back(std::string&&) + json_pointer& operator/=(std::string token) + { + push_back(std::move(token)); + return *this; + } + + /// @copydoc operator/=(std::string) + json_pointer& operator/=(std::size_t array_index) + { + return *this /= std::to_string(array_index); + } + + /*! + @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer + */ + friend json_pointer operator/(const json_pointer& left_ptr, const json_pointer& right_ptr) + { + return json_pointer(left_ptr) /= right_ptr; + } + + /*! + @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer + */ + friend json_pointer operator/(const json_pointer& ptr, std::string token) + { + return json_pointer(ptr) /= std::move(token); + } + + /*! + @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer + */ + friend json_pointer operator/(const json_pointer& lhs, std::size_t array_index) + { + return json_pointer(lhs) /= array_index; + } + /*! @param[in] s reference token to be converted into an array index @@ -98,7 +144,7 @@ class json_pointer } /*! - @brief remove and return last reference pointer + @brief remove and return last reference token @throw out_of_range.405 if JSON pointer has no parent */ std::string pop_back() @@ -114,31 +160,17 @@ class json_pointer } /*! - @brief append a token at the end of the reference pointer + @brief append an unescaped token at the end of the reference pointer */ - void push_back(const std::string& tok) + void push_back(const std::string& token) { - reference_tokens.push_back(tok); + reference_tokens.push_back(token); } - /*! - @brief append a key-token at the end of the reference pointer and return a new json-pointer. - */ - json_pointer operator+(const std::string& tok) const + /// @copydoc push_back(const std::string&) + void push_back(std::string&& token) { - auto ptr = *this; - ptr.push_back(tok); - return ptr; - } - - /*! - @brief append a array-index-token at the end of the reference pointer and return a new json-pointer. - */ - json_pointer operator+(const size_t& index) const - { - auto ptr = *this; - ptr.push_back(std::to_string(index)); - return ptr; + reference_tokens.push_back(std::move(token)); } private: diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index d845f77ee..dd7236c84 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -11886,6 +11886,52 @@ class json_pointer return to_string(); } + /*! + @brief append another JSON pointer at the end of this JSON pointer + */ + json_pointer& operator/=(const json_pointer& ptr) + { + reference_tokens.insert(reference_tokens.end(), ptr.reference_tokens.begin(), ptr.reference_tokens.end()); + return *this; + } + + /// @copydoc push_back(std::string&&) + json_pointer& operator/=(std::string token) + { + push_back(std::move(token)); + return *this; + } + + /// @copydoc operator/=(std::string) + json_pointer& operator/=(std::size_t array_index) + { + return *this /= std::to_string(array_index); + } + + /*! + @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer + */ + friend json_pointer operator/(const json_pointer& left_ptr, const json_pointer& right_ptr) + { + return json_pointer(left_ptr) /= right_ptr; + } + + /*! + @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer + */ + friend json_pointer operator/(const json_pointer& ptr, std::string token) + { + return json_pointer(ptr) /= std::move(token); + } + + /*! + @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer + */ + friend json_pointer operator/(const json_pointer& lhs, std::size_t array_index) + { + return json_pointer(lhs) /= array_index; + } + /*! @param[in] s reference token to be converted into an array index @@ -11908,7 +11954,7 @@ class json_pointer } /*! - @brief remove and return last reference pointer + @brief remove and return last reference token @throw out_of_range.405 if JSON pointer has no parent */ std::string pop_back() @@ -11924,31 +11970,17 @@ class json_pointer } /*! - @brief append a token at the end of the reference pointer + @brief append an unescaped token at the end of the reference pointer */ - void push_back(const std::string& tok) + void push_back(const std::string& token) { - reference_tokens.push_back(tok); + reference_tokens.push_back(token); } - /*! - @brief append a key-token at the end of the reference pointer and return a new json-pointer. - */ - json_pointer operator+(const std::string& tok) const + /// @copydoc push_back(const std::string&) + void push_back(std::string&& token) { - auto ptr = *this; - ptr.push_back(tok); - return ptr; - } - - /*! - @brief append a array-index-token at the end of the reference pointer and return a new json-pointer. - */ - json_pointer operator+(const size_t& index) const - { - auto ptr = *this; - ptr.push_back(std::to_string(index)); - return ptr; + reference_tokens.push_back(std::move(token)); } private: diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index 373b2c218..b16603a7b 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -499,7 +499,8 @@ TEST_CASE("JSON pointers") CHECK(j[ptr] == j); // object and children access - ptr.push_back("answer"); + const std::string answer("answer"); + ptr.push_back(answer); ptr.push_back("everything"); CHECK(j[ptr] == j["answer"]["everything"]); @@ -546,24 +547,31 @@ TEST_CASE("JSON pointers") CHECK(j[ptr] == j); // simple field access - ptr = ptr + "pi"; + ptr = ptr / "pi"; CHECK(j[ptr] == j["pi"]); ptr.pop_back(); CHECK(j[ptr] == j); // object and children access - ptr = ptr + "answer"; - ptr = ptr + "everything"; + const std::string answer("answer"); + ptr /= answer; + ptr = ptr / "everything"; CHECK(j[ptr] == j["answer"]["everything"]); ptr.pop_back(); ptr.pop_back(); CHECK(j[ptr] == j); + CHECK(ptr / ""_json_pointer == ptr); + CHECK(j["/answer"_json_pointer / "/everything"_json_pointer] == j["answer"]["everything"]); + + // list children access + CHECK(j["/list"_json_pointer / 1] == j["list"][1]); + // push key which has to be encoded - ptr = ptr + "object"; - ptr = ptr + "/"; + ptr /= "object"; + ptr = ptr / "/"; CHECK(j[ptr] == j["object"]["/"]); CHECK(ptr.to_string() == "/object/~1"); }