From 37659cb528e41f64cdca483f60117ac5dbdd9e02 Mon Sep 17 00:00:00 2001 From: Daniel Parker Date: Thu, 9 Nov 2023 11:20:11 -0500 Subject: [PATCH] path_element --- include/jsoncons/detail/string_view.hpp | 19 ++++ .../jsoncons_ext/jsonpath/json_location.hpp | 106 +++++++++++++++--- .../jsonpath/jsonpath_selector.hpp | 4 +- 3 files changed, 109 insertions(+), 20 deletions(-) diff --git a/include/jsoncons/detail/string_view.hpp b/include/jsoncons/detail/string_view.hpp index 12860473a3..dcfa66bfd4 100644 --- a/include/jsoncons/detail/string_view.hpp +++ b/include/jsoncons/detail/string_view.hpp @@ -534,4 +534,23 @@ namespace detail { } // namespace detail } // namespace jsoncons +namespace std { + template + struct std::hash> + { + std::size_t operator()(const jsoncons::detail::basic_string_view& s) const noexcept + { + const int p = 53; + const int m = 1e9 + 9; + std::size_t hash_value = 0; + std::size_t p_pow = 1; + for (char c : s) { + hash_value = (hash_value + (c - 'a' + 1) * p_pow) % m; + p_pow = (p_pow * p) % m; + } + return hash_value; + } + }; +} // namespace std + #endif diff --git a/include/jsoncons_ext/jsonpath/json_location.hpp b/include/jsoncons_ext/jsonpath/json_location.hpp index 07bdd089cb..b9d2dd07a2 100644 --- a/include/jsoncons_ext/jsonpath/json_location.hpp +++ b/include/jsoncons_ext/jsonpath/json_location.hpp @@ -167,6 +167,79 @@ namespace jsonpath { } }; + template + class basic_path_element + { + template friend class basic_json_location; + public: + using char_type = CharT; + using string_view_type = jsoncons::basic_string_view; + private: + path_node_kind node_kind_; + string_view_type name_; + std::size_t index_; + + public: + basic_path_element() = default; + + basic_path_element(path_node_kind node_kind, string_view_type name, std::size_t index) + : node_kind_(node_kind), name_(name), index_(index) + { + } + + path_node_kind node_kind() const + { + return node_kind_; + } + + const string_view_type& name() const + { + return name_; + } + + std::size_t index() const + { + return index_; + } + + basic_path_element(const basic_path_element&) = default; + basic_path_element& operator=(const basic_path_element&) = default; + + private: + + std::size_t node_hash() const + { + std::size_t h = node_kind_ == path_node_kind::index ? std::hash{}(index_) : std::hash{}(name_); + + return h; + } + + int compare_node(const basic_path_element& other) const + { + int diff = 0; + if (node_kind_ != other.node_kind_) + { + diff = static_cast(node_kind_) - static_cast(other.node_kind_); + } + else + { + switch (node_kind_) + { + case path_node_kind::root: + case path_node_kind::name: + diff = name_.compare(other.name_); + break; + case path_node_kind::index: + diff = index_ < other.index_ ? -1 : index_ > other.index_ ? 1 : 0; + break; + default: + break; + } + } + return diff; + } + }; + namespace detail { template @@ -327,10 +400,10 @@ namespace jsonpath { using path_node_type = path_node; private: allocator_type alloc_; - std::vector nodes_; + std::vector> nodes_; public: - using iterator = typename detail::json_location_iterator::iterator>; - using const_iterator = typename detail::json_location_iterator::const_iterator>; + using iterator = typename std::vector>::iterator; + using const_iterator = typename std::vector>::const_iterator; basic_json_location(const path_node_type& node, const allocator_type& alloc = allocator_type()) : alloc_(alloc) @@ -341,7 +414,7 @@ namespace jsonpath { const path_node_type* p = std::addressof(node); do { - nodes_[--len] = p; + nodes_[--len] = basic_path_element(p->node_kind(), p->name(), p->index()); p = p->parent_; } while (p != nullptr); @@ -349,27 +422,22 @@ namespace jsonpath { iterator begin() { - return iterator(nodes_.begin()); + return nodes_.begin(); } iterator end() { - return iterator(nodes_.end()); + return nodes_.end(); } const_iterator begin() const { - return const_iterator(nodes_.begin()); + return nodes_.begin(); } const_iterator end() const { - return const_iterator(nodes_.end()); - } - - const path_node_type& last() const - { - return *nodes_.back(); + return nodes_.end(); } string_type to_string() const @@ -378,21 +446,21 @@ namespace jsonpath { for (const auto& node : nodes_) { - switch (node->node_kind()) + switch (node.node_kind()) { case path_node_kind::root: - buffer.append(node->name().data(), node->name().size()); + buffer.append(node.name().data(), node.name().size()); break; case path_node_kind::name: buffer.push_back('['); buffer.push_back('\''); - jsoncons::jsonpath::escape_string(node->name().data(), node->name().size(), buffer); + jsoncons::jsonpath::escape_string(node.name().data(), node.name().size(), buffer); buffer.push_back('\''); buffer.push_back(']'); break; case path_node_kind::index: buffer.push_back('['); - jsoncons::detail::from_integer(node->index(), buffer); + jsoncons::detail::from_integer(node.index(), buffer); buffer.push_back(']'); break; } @@ -412,7 +480,7 @@ namespace jsonpath { auto it2 = other.nodes_.begin(); while (it1 != nodes_.end() && it2 != other.nodes_.end()) { - int diff = (*it1)->compare_node(*(*it2)); + int diff = it1->compare_node(*it2); if (diff != 0) { return diff; @@ -488,6 +556,8 @@ namespace jsonpath { using json_location = basic_json_location; using wjson_location = basic_json_location; + using path_element = basic_path_element; + using wpath_element = basic_path_element; } // namespace jsonpath } // namespace jsoncons diff --git a/include/jsoncons_ext/jsonpath/jsonpath_selector.hpp b/include/jsoncons_ext/jsonpath/jsonpath_selector.hpp index 8d95cb3ae1..e08529b5c0 100644 --- a/include/jsoncons_ext/jsonpath/jsonpath_selector.hpp +++ b/include/jsoncons_ext/jsonpath/jsonpath_selector.hpp @@ -587,7 +587,7 @@ namespace detail { pointer ptr = jsoncons::jsonpath::select(root,path); if (ptr != nullptr) { - this->tail_select(resources, root, path.last(), *ptr, receiver, options); + this->tail_select(resources, root, *ancestor, *ptr, receiver, options); } } } @@ -613,7 +613,7 @@ namespace detail { pointer ptr = jsoncons::jsonpath::select(root,path); if (ptr != nullptr) { - return this->evaluate_tail(resources, root, path.last(), *ptr, options, ec); + return this->evaluate_tail(resources, root, /*path.last()*/ *ancestor, *ptr, options, ec); } else {