diff options
Diffstat (limited to 'vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer.hpp')
-rw-r--r-- | vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer.hpp | 810 |
1 files changed, 810 insertions, 0 deletions
diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer.hpp new file mode 100644 index 00000000..56b4efa2 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer.hpp @@ -0,0 +1,810 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPOINTER_JSONPOINTER_HPP +#define JSONCONS_JSONPOINTER_JSONPOINTER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <jsoncons/json.hpp> +#include <jsoncons_ext/jsonpointer/jsonpointer_error_category.hpp> + +namespace jsoncons { namespace jsonpointer { + +class jsonpointer_error : public std::exception, public virtual json_exception +{ +public: + jsonpointer_error(const std::error_code& ec) + : error_code_(ec) + { + } + jsonpointer_error(const jsonpointer_error& other) = default; + + jsonpointer_error(jsonpointer_error&& other) = default; + + const char* what() const JSONCONS_NOEXCEPT override + { + try + { + const_cast<std::string&>(buffer_) = error_code_.message(); + return buffer_.c_str(); + } + catch (...) + { + return ""; + } + } + + const std::error_code code() const + { + return error_code_; + } + + jsonpointer_error& operator=(const jsonpointer_error& e) = default; + jsonpointer_error& operator=(jsonpointer_error&& e) = default; +private: + std::string buffer_; + std::error_code error_code_; +}; + +namespace detail { + +enum class pointer_state +{ + start, + array_reference_token, + zero_array_reference_token, + nonzero_array_reference_token, + after_last_array_reference_token, + object_reference_token, + escaped +}; +template <class Json,class JsonReference, class Enable = void> +class json_wrapper +{ +}; + +template <class Json,class JsonReference> +class json_wrapper<Json,JsonReference,typename std::enable_if<std::is_reference<decltype(std::declval<Json>().at(typename Json::string_view_type()))>::value>::type> +{ +public: + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + json_wrapper(reference ref) JSONCONS_NOEXCEPT + : ptr_(std::addressof(ref)) + { + } + + json_wrapper(const json_wrapper&) JSONCONS_NOEXCEPT = default; + + json_wrapper& operator=(const json_wrapper&) JSONCONS_NOEXCEPT = default; + + reference get() const JSONCONS_NOEXCEPT + { + return *ptr_; + } +private: + pointer ptr_; +}; + +template <class Json,class JsonReference> +class json_wrapper<Json,JsonReference,typename std::enable_if<!std::is_reference<decltype(std::declval<Json>().at(typename Json::string_view_type()))>::value>::type> +{ +public: + using value_type = typename Json::value_type; + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + json_wrapper(reference ref) JSONCONS_NOEXCEPT + : val_(ref) + { + } + + json_wrapper(const json_wrapper& w) JSONCONS_NOEXCEPT + : val_(w.val_) + { + } + + json_wrapper& operator=(const json_wrapper&) JSONCONS_NOEXCEPT = default; + + value_type get() const JSONCONS_NOEXCEPT + { + return val_; + } +private: + value_type val_; +}; + +template<class Json,class JsonReference> +struct path_resolver +{ + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + jsonpointer_errc operator()(std::vector<json_wrapper<Json,JsonReference>>& current, + size_t index) const + { + if (index >= current.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + current.push_back(current.back().get().at(index)); + return jsonpointer_errc(); + } + + jsonpointer_errc operator()(std::vector<json_wrapper<Json,JsonReference>>& current, + const string_view_type& name) const + { + if (!current.back().get().has_key(name)) + { + return jsonpointer_errc::name_not_found; + } + current.push_back(current.back().get().at(name)); + return jsonpointer_errc(); + } +}; + +template<class Json, class JsonReference> +struct path_setter +{ + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + jsonpointer_errc operator()(std::vector<json_wrapper<Json,JsonReference>>& current, + size_t index) const + { + if (index >= current.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + current.push_back(current.back().get().at(index)); + return jsonpointer_errc(); + } + + jsonpointer_errc operator()(std::vector<json_wrapper<Json,JsonReference>>& current, + const string_view_type& name) const + { + jsonpointer_errc ec = jsonpointer_errc(); + if (!current.back().get().has_key(name)) + { + return jsonpointer_errc::name_not_found; + } + current.push_back(current.back().get().at(name)); + return ec; + } +}; + +template<class Json,class JsonReference> +class jsonpointer_evaluator : private parsing_context +{ + typedef typename Json::string_type string_type; + typedef typename string_type::value_type char_type; + typedef typename Json::string_view_type string_view_type; + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + jsonpointer::detail::pointer_state state_; + size_t line_; + size_t column_; + const char_type* begin_input_; + const char_type* end_input_; + const char_type* p_; + string_type buffer_; + size_t index_; + std::vector<json_wrapper<Json,JsonReference>> current_; +public: + Json get_result() + { + return std::move(current_.back().get()); + } + + size_t line_number() const + { + return line_; + } + + size_t column_number() const + { + return column_; + } + + jsonpointer_errc get(reference root, const string_view_type& path) + { + path_resolver<Json,reference> op; + jsonpointer_errc ec = evaluate(root,op,path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case pointer_state::start: + break; + case pointer_state::zero_array_reference_token: + case pointer_state::nonzero_array_reference_token: + ec = op(current_,index_); + break; + case pointer_state::object_reference_token: + ec = op(current_,buffer_); + break; + default: + return jsonpointer_errc::end_of_input; + } + return ec; + } + + string_type normalized_path(reference root, const string_view_type& path) + { + jsonpointer_errc ec = evaluate(root,path_setter<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return string_type(path); + } + if (state_ == jsonpointer::detail::pointer_state::after_last_array_reference_token) + { + string_type p = string_type(path.substr(0,path.length()-1)); + std::string s = std::to_string(current_.back().get().size()); + for (auto c : s) + { + p.push_back(c); + } + return p; + } + else + { + return string_type(path); + } + } + + jsonpointer_errc insert_or_assign(reference root, const string_view_type& path, const Json& value) + { + jsonpointer_errc ec = evaluate(root,path_setter<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + if (index_ > current_.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + if (index_ == current_.back().get().size()) + { + current_.back().get().push_back(value); + } + else + { + current_.back().get().insert(current_.back().get().array_range().begin()+index_,value); + } + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + current_.back().get().push_back(value); + break; + case jsonpointer::detail::pointer_state::object_reference_token: + current_.back().get().insert_or_assign(buffer_,value); + break; + default: + return jsonpointer_errc::end_of_input; + } + return ec; + } + + jsonpointer_errc insert(reference root, const string_view_type& path, const Json& value) + { + jsonpointer_errc ec = evaluate(root,path_setter<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + if (index_ > current_.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + if (index_ == current_.back().get().size()) + { + current_.back().get().push_back(value); + } + else + { + current_.back().get().insert(current_.back().get().array_range().begin()+index_,value); + } + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + current_.back().get().push_back(value); + break; + case jsonpointer::detail::pointer_state::object_reference_token: + if (current_.back().get().has_key(buffer_)) + { + ec = jsonpointer_errc::key_already_exists; + } + else + { + current_.back().get().insert_or_assign(buffer_,value); + } + break; + default: + return jsonpointer_errc::end_of_input; + } + return ec; + } + + jsonpointer_errc remove(reference root, const string_view_type& path) + { + jsonpointer_errc ec = evaluate(root,path_resolver<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + if (index_ >= current_.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + current_.back().get().erase(current_.back().get().array_range().begin()+index_); + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + return jsonpointer_errc::index_exceeds_array_size; + case jsonpointer::detail::pointer_state::object_reference_token: + if (!current_.back().get().has_key(buffer_)) + { + return jsonpointer_errc::name_not_found; + } + current_.back().get().erase(buffer_); + break; + default: + return jsonpointer_errc::end_of_input; + } + return ec; + } + + jsonpointer_errc replace(reference root, const string_view_type& path, const Json& value) + { + jsonpointer_errc ec = evaluate(root,path_resolver<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + if (index_ >= current_.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + (current_.back().get())[index_] = value; + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + return jsonpointer_errc::index_exceeds_array_size; + case jsonpointer::detail::pointer_state::object_reference_token: + if (!current_.back().get().has_key(buffer_)) + { + return jsonpointer_errc::name_not_found; + } + current_.back().get().insert_or_assign(buffer_,value); + break; + default: + return jsonpointer_errc::end_of_input; + } + return jsonpointer_errc(); + } + + template <class Op> + jsonpointer_errc evaluate(reference root, Op op, const string_view_type& path) + { + jsonpointer_errc ec = jsonpointer_errc(); + + line_ = 1; + column_ = 1; + state_ = jsonpointer::detail::pointer_state::start; + begin_input_ = path.data(); + end_input_ = path.data() + path.length(); + p_ = begin_input_; + + index_ = 0; + + current_.push_back(root); + + while (p_ < end_input_) + { + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + switch (*p_) + { + case '/': + if (current_.back().get().is_array()) + { + state_ = jsonpointer::detail::pointer_state::array_reference_token; + index_ = 0; + } + else if (current_.back().get().is_object()) + { + state_ = jsonpointer::detail::pointer_state::object_reference_token; + buffer_.clear(); + } + else + { + return jsonpointer_errc::expected_object_or_array; + } + break; + default: + return jsonpointer_errc::expected_slash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::array_reference_token: + switch (*p_) + { + case '0': + index_ = 0; + state_ = jsonpointer::detail::pointer_state::zero_array_reference_token; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + index_ = (*p_ - '0'); + state_ = jsonpointer::detail::pointer_state::nonzero_array_reference_token; + break; + case '-': + state_ = jsonpointer::detail::pointer_state::after_last_array_reference_token; + break; + default: + return jsonpointer_errc::expected_digit_or_dash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + switch (*p_) + { + case '/': + ec = op(current_,index_); + if (ec != jsonpointer_errc()) + { + return ec; + } + if (current_.back().get().is_array()) + { + state_ = jsonpointer::detail::pointer_state::array_reference_token; + index_ = 0; + } + else if (current_.back().get().is_object()) + { + state_ = jsonpointer::detail::pointer_state::object_reference_token; + buffer_.clear(); + } + else + { + return jsonpointer_errc::expected_object_or_array; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return jsonpointer_errc::unexpected_leading_zero; + case '-': + return jsonpointer_errc::index_exceeds_array_size; + default: + return jsonpointer_errc::expected_digit_or_dash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + switch (*p_) + { + case '/': + return jsonpointer_errc::index_exceeds_array_size; + default: + return jsonpointer_errc::expected_slash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + switch (*p_) + { + case '/': + ec = op(current_,index_); + if (ec != jsonpointer_errc()) + { + return ec; + } + if (current_.back().get().is_array()) + { + state_ = jsonpointer::detail::pointer_state::array_reference_token; + index_ = 0; + } + else if (current_.back().get().is_object()) + { + state_ = jsonpointer::detail::pointer_state::object_reference_token; + buffer_.clear(); + } + else + { + return jsonpointer_errc::expected_object_or_array; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + index_ = index_ * 10 + (*p_ - '0'); + break; + case '-': + return jsonpointer_errc::index_exceeds_array_size; + default: + return jsonpointer_errc::expected_digit_or_dash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::object_reference_token: + switch (*p_) + { + case '/': + ec = op(current_,buffer_); + if (ec != jsonpointer_errc()) + { + return ec; + } + if (current_.back().get().is_array()) + { + state_ = jsonpointer::detail::pointer_state::array_reference_token; + index_ = 0; + } + else if (current_.back().get().is_object()) + { + state_ = jsonpointer::detail::pointer_state::object_reference_token; + buffer_.clear(); + } + else + { + return jsonpointer_errc::expected_object_or_array; + } + break; + case '~': + state_ = jsonpointer::detail::pointer_state::escaped; + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::escaped: + switch (*p_) + { + case '0': + buffer_.push_back('~'); + state_ = jsonpointer::detail::pointer_state::object_reference_token; + break; + case '1': + buffer_.push_back('/'); + state_ = jsonpointer::detail::pointer_state::object_reference_token; + break; + default: + return jsonpointer_errc::expected_0_or_1; + }; + ++p_; + ++column_; + break; + } + } + return ec; + } + +private: + + // parsing_context + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } +}; + +} + +template<class Json> +typename Json::string_type normalized_path(const Json& root, const typename Json::string_view_type& path) +{ + detail::jsonpointer_evaluator<Json,const Json&> evaluator; + return evaluator.normalized_path(root,path); +} + +template<class Json> +Json get(const Json& root, const typename Json::string_view_type& path) +{ + detail::jsonpointer_evaluator<Json,const Json&> evaluator; + jsonpointer_errc ec = evaluator.get(root,path); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } + return evaluator.get_result(); +} + +template<class Json> +Json get(const Json& root, const typename Json::string_view_type& path, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,const Json&> evaluator; + ec = evaluator.get(root,path); + return evaluator.get_result(); +} + +template<class Json> +bool contains(const Json& root, const typename Json::string_view_type& path) +{ + detail::jsonpointer_evaluator<Json,const Json&> evaluator; + jsonpointer_errc ec = evaluator.get(root,path); + return ec == jsonpointer_errc() ? true : false; +} + +template<class Json> +void insert_or_assign(Json& root, const typename Json::string_view_type& path, const Json& value) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + jsonpointer_errc ec = evaluator.insert_or_assign(root,path,value); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template<class Json> +void insert_or_assign(Json& root, const typename Json::string_view_type& path, const Json& value, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + ec = evaluator.insert_or_assign(root,path,value); +} + +template<class Json> +void insert(Json& root, const typename Json::string_view_type& path, const Json& value) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + jsonpointer_errc ec = evaluator.insert(root,path,value); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template<class Json> +void insert(Json& root, const typename Json::string_view_type& path, const Json& value, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + ec = evaluator.insert(root,path,value); +} + +template<class Json> +void remove(Json& root, const typename Json::string_view_type& path) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + jsonpointer_errc ec = evaluator.remove(root,path); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template<class Json> +void remove(Json& root, const typename Json::string_view_type& path, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + ec = evaluator.remove(root,path); +} + +template<class Json> +void replace(Json& root, const typename Json::string_view_type& path, const Json& value) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + jsonpointer_errc ec = evaluator.replace(root,path,value); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template<class Json> +void replace(Json& root, const typename Json::string_view_type& path, const Json& value, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + ec = evaluator.replace(root,path,value); +} + +template <class String> +void escape(const String& s, std::basic_ostringstream<typename String::value_type>& os) +{ + for (auto c : s) + { + if (c == '~') + { + os.put('~'); + os.put('0'); + } + else if (c == '/') + { + os.put('~'); + os.put('1'); + } + else + { + os.put(c); + } + } +} + +}} + +#endif |