summaryrefslogtreecommitdiff
path: root/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/json_query.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/json_query.hpp')
-rw-r--r--vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/json_query.hpp1119
1 files changed, 1119 insertions, 0 deletions
diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/json_query.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/json_query.hpp
new file mode 100644
index 00000000..b042bbbb
--- /dev/null
+++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/json_query.hpp
@@ -0,0 +1,1119 @@
+// Copyright 2013 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_JSONPATH_JSONQUERY_HPP
+#define JSONCONS_JSONPATH_JSONQUERY_HPP
+
+#include <string>
+#include <sstream>
+#include <vector>
+#include <istream>
+#include <cstdlib>
+#include <memory>
+#include <jsoncons/json.hpp>
+#include "jsonpath_filter.hpp"
+#include "jsonpath_error_category.hpp"
+
+namespace jsoncons { namespace jsonpath {
+
+enum class result_type {value,path};
+
+template<class Json>
+Json json_query(const Json& root, const typename Json::string_view_type& path, result_type result_t = result_type::value)
+{
+ if (result_t == result_type::value)
+ {
+ detail::jsonpath_evaluator<Json,const Json&,detail::VoidPathConstructor<Json>> evaluator;
+ evaluator.evaluate(root,path.data(),path.length());
+ return evaluator.get_values();
+ }
+ else
+ {
+ detail::jsonpath_evaluator<Json,const Json&,detail::PathConstructor<Json>> evaluator;
+ evaluator.evaluate(root,path.data(),path.length());
+ return evaluator.get_normalized_paths();
+ }
+}
+
+template<class Json, class T>
+void json_replace(Json& root, const typename Json::string_view_type& path, T&& new_value)
+{
+ detail::jsonpath_evaluator<Json,Json&,detail::VoidPathConstructor<Json>> evaluator;
+ evaluator.evaluate(root,path.data(),path.length());
+ evaluator.replace(std::forward<T>(new_value));
+}
+
+namespace detail {
+
+template<class CharT>
+bool try_string_to_index(const CharT *s, size_t length, size_t* value, bool* positive)
+{
+ static const size_t max_value = (std::numeric_limits<size_t>::max)();
+ static const size_t max_value_div_10 = max_value / 10;
+
+ size_t start = 0;
+ size_t n = 0;
+ if (length > 0)
+ {
+ if (s[start] == '-')
+ {
+ *positive = false;
+ ++start;
+ }
+ else
+ {
+ *positive = true;
+ }
+ }
+ if (length > start)
+ {
+ for (size_t i = start; i < length; ++i)
+ {
+ CharT c = s[i];
+ switch (c)
+ {
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ {
+ size_t x = c - '0';
+ if (n > max_value_div_10)
+ {
+ return false;
+ }
+ n = n * 10;
+ if (n > max_value - x)
+ {
+ return false;
+ }
+
+ n += x;
+ }
+ break;
+ default:
+ return false;
+ break;
+ }
+ }
+ *value = n;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+enum class path_state
+{
+ start,
+ cr,
+ lf,
+ expect_dot_or_left_bracket,
+ expect_unquoted_name_or_left_bracket,
+ unquoted_name,
+ left_bracket_single_quoted_string,
+ left_bracket_double_quoted_string,
+ left_bracket,
+ left_bracket_start,
+ left_bracket_end,
+ left_bracket_end2,
+ left_bracket_step,
+ left_bracket_step2,
+ expect_comma_or_right_bracket,
+ dot
+};
+
+template<class Json,
+ class JsonReference=const Json&,
+ class PathCons=PathConstructor<Json>>
+class jsonpath_evaluator : private parsing_context
+{
+private:
+ typedef typename Json::char_type char_type;
+ typedef typename Json::char_traits_type char_traits_type;
+ typedef std::basic_string<char_type,char_traits_type> string_type;
+ typedef typename Json::string_view_type string_view_type;
+ typedef JsonReference reference;
+ using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type;
+ struct node_type
+ {
+ node_type() = default;
+ node_type(const string_type& p, const pointer& valp)
+ : skip_contained_object(false),path(p),val_ptr(valp)
+ {
+ }
+ node_type(string_type&& p, pointer&& valp)
+ : skip_contained_object(false),path(std::move(p)),val_ptr(valp)
+ {
+ }
+ node_type(const node_type&) = default;
+ node_type(node_type&&) = default;
+
+ bool skip_contained_object;
+ string_type path;
+ pointer val_ptr;
+ };
+ typedef std::vector<node_type> node_set;
+
+ static string_view_type length_literal()
+ {
+ static const char_type data[] = {'l','e','n','g','t','h'};
+ return string_view_type{data,sizeof(data)/sizeof(char_type)};
+ }
+
+ class selector
+ {
+ public:
+ virtual ~selector()
+ {
+ }
+ virtual void select(node_type& node, const string_type& path, reference val,
+ node_set& nodes, std::vector<std::shared_ptr<Json>>& temp_json_values) = 0;
+ };
+
+ class expr_selector final : public selector
+ {
+ private:
+ jsonpath_filter_expr<Json> result_;
+ public:
+ expr_selector(const jsonpath_filter_expr<Json>& result)
+ : result_(result)
+ {
+ }
+
+ void select(node_type& node, const string_type& path, reference val,
+ node_set& nodes, std::vector<std::shared_ptr<Json>>& temp_json_values) override
+ {
+ auto index = result_.eval(val);
+ if (index.template is<size_t>())
+ {
+ size_t start = index. template as<size_t>();
+ if (val.is_array() && start < val.size())
+ {
+ nodes.emplace_back(PathCons()(path,start),std::addressof(val[start]));
+ }
+ }
+ else if (index.is_string())
+ {
+ name_selector selector(index.as_string_view(),true);
+ selector.select(node, path, val, nodes, temp_json_values);
+ }
+ }
+ };
+
+ class filter_selector final : public selector
+ {
+ private:
+ jsonpath_filter_expr<Json> result_;
+ public:
+ filter_selector(const jsonpath_filter_expr<Json>& result)
+ : result_(result)
+ {
+ }
+
+ void select(node_type& node, const string_type& path, reference val,
+ node_set& nodes, std::vector<std::shared_ptr<Json>>&) override
+ {
+ if (val.is_array())
+ {
+ node.skip_contained_object =true;
+ for (size_t i = 0; i < val.size(); ++i)
+ {
+ if (result_.exists(val[i]))
+ {
+ nodes.emplace_back(PathCons()(path,i),std::addressof(val[i]));
+ }
+ }
+ }
+ else if (val.is_object())
+ {
+ if (!node.skip_contained_object)
+ {
+ if (result_.exists(val))
+ {
+ nodes.emplace_back(path, std::addressof(val));
+ }
+ }
+ else
+ {
+ node.skip_contained_object = false;
+ }
+ }
+ }
+ };
+
+ class name_selector final : public selector
+ {
+ private:
+ string_type name_;
+ bool positive_start_;
+ public:
+ name_selector(const string_view_type& name, bool positive_start)
+ : name_(name), positive_start_(positive_start)
+ {
+ }
+
+ void select(node_type& node, const string_type& path, reference val,
+ node_set& nodes,
+ std::vector<std::shared_ptr<Json>>& temp_json_values) override
+ {
+ if (val.is_object() && val.count(name_) > 0)
+ {
+ nodes.emplace_back(PathCons()(path,name_),std::addressof(val.at(name_)));
+ }
+ else if (val.is_array())
+ {
+ size_t pos = 0;
+ if (try_string_to_index(name_.data(), name_.size(), &pos, &positive_start_))
+ {
+ size_t index = positive_start_ ? pos : val.size() - pos;
+ if (index < val.size())
+ {
+ nodes.emplace_back(PathCons()(path,index),std::addressof(val[index]));
+ }
+ }
+ else if (name_ == length_literal() && val.size() > 0)
+ {
+ auto temp = std::make_shared<Json>(val.size());
+ temp_json_values.push_back(temp);
+ nodes.emplace_back(PathCons()(path,name_),temp.get());
+ }
+ }
+ else if (val.is_string())
+ {
+ size_t pos = 0;
+ string_view_type sv = val.as_string_view();
+ if (try_string_to_index(name_.data(), name_.size(), &pos, &positive_start_))
+ {
+ size_t index = positive_start_ ? pos : sv.size() - pos;
+ auto sequence = unicons::sequence_at(sv.data(), sv.data() + sv.size(), index);
+ if (sequence.length() > 0)
+ {
+ auto temp = std::make_shared<Json>(sequence.begin(),sequence.length());
+ temp_json_values.push_back(temp);
+ nodes.emplace_back(PathCons()(path,index),temp.get());
+ }
+ }
+ else if (name_ == length_literal() && sv.size() > 0)
+ {
+ size_t count = unicons::u32_length(sv.begin(),sv.end());
+ auto temp = std::make_shared<Json>(count);
+ temp_json_values.push_back(temp);
+ nodes.emplace_back(PathCons()(path,name_),temp.get());
+ }
+ }
+ }
+ };
+
+ class array_slice_selector final : public selector
+ {
+ private:
+ size_t start_;
+ bool positive_start_;
+ size_t end_;
+ bool positive_end_;
+ bool undefined_end_;
+ size_t step_;
+ bool positive_step_;
+ public:
+ array_slice_selector(size_t start, bool positive_start,
+ size_t end, bool positive_end,
+ size_t step, bool positive_step,
+ bool undefined_end)
+ : start_(start), positive_start_(positive_start),
+ end_(end), positive_end_(positive_end),undefined_end_(undefined_end),
+ step_(step), positive_step_(positive_step)
+ {
+ }
+
+ void select(node_type& node, const string_type& path, reference val,
+ node_set& nodes,
+ std::vector<std::shared_ptr<Json>>&) override
+ {
+ if (positive_step_)
+ {
+ end_array_slice1(path, val, nodes);
+ }
+ else
+ {
+ end_array_slice2(path, val, nodes);
+ }
+ }
+
+ void end_array_slice1(const string_type& path, reference val, node_set& nodes)
+ {
+ if (val.is_array())
+ {
+ size_t start = positive_start_ ? start_ : val.size() - start_;
+ size_t end;
+ if (!undefined_end_)
+ {
+ end = positive_end_ ? end_ : val.size() - end_;
+ }
+ else
+ {
+ end = val.size();
+ }
+ for (size_t j = start; j < end; j += step_)
+ {
+ if (j < val.size())
+ {
+ nodes.emplace_back(PathCons()(path,j),std::addressof(val[j]));
+ }
+ }
+ }
+ }
+
+ void end_array_slice2(const string_type& path, reference val, node_set& nodes)
+ {
+ if (val.is_array())
+ {
+ size_t start = positive_start_ ? start_ : val.size() - start_;
+ size_t end;
+ if (!undefined_end_)
+ {
+ end = positive_end_ ? end_ : val.size() - end_;
+ }
+ else
+ {
+ end = val.size();
+ }
+
+ size_t j = end + step_ - 1;
+ while (j > (start+step_-1))
+ {
+ j -= step_;
+ if (j < val.size())
+ {
+ nodes.emplace_back(PathCons()(path,j),std::addressof(val[j]));
+ }
+ }
+ }
+ }
+ };
+
+ default_parse_error_handler default_err_handler_;
+ parse_error_handler *err_handler_;
+ path_state state_;
+ string_type buffer_;
+ size_t start_;
+ bool positive_start_;
+ size_t end_;
+ bool positive_end_;
+ bool undefined_end_;
+ size_t step_;
+ bool positive_step_;
+ bool recursive_descent_;
+ node_set nodes_;
+ std::vector<node_set> stack_;
+ std::vector<std::shared_ptr<Json>> temp_json_values_;
+ size_t line_;
+ size_t column_;
+ const char_type* begin_input_;
+ const char_type* end_input_;
+ const char_type* p_;
+ std::vector<std::shared_ptr<selector>> selectors_;
+
+public:
+ jsonpath_evaluator()
+ : err_handler_(&default_err_handler_),
+ state_(path_state::start),
+ start_(0), positive_start_(true),
+ end_(0), positive_end_(true), undefined_end_(false),
+ step_(0), positive_step_(true),
+ recursive_descent_(false),
+ line_(0), column_(0),
+ begin_input_(nullptr), end_input_(nullptr),
+ p_(nullptr)
+ {
+ }
+
+ Json get_values() const
+ {
+ Json result = typename Json::array();
+
+ if (stack_.size() > 0)
+ {
+ result.reserve(stack_.back().size());
+ for (const auto& p : stack_.back())
+ {
+ result.push_back(*(p.val_ptr));
+ }
+ }
+ return result;
+ }
+
+ Json get_normalized_paths() const
+ {
+ Json result = typename Json::array();
+ if (stack_.size() > 0)
+ {
+ result.reserve(stack_.back().size());
+ for (const auto& p : stack_.back())
+ {
+ result.push_back(p.path);
+ }
+ }
+ return result;
+ }
+
+ template <class T>
+ void replace(T&& new_value)
+ {
+ if (stack_.size() > 0)
+ {
+ for (size_t i = 0; i < stack_.back().size(); ++i)
+ {
+ *(stack_.back()[i].val_ptr) = new_value;
+ }
+ }
+ }
+
+ void evaluate(reference root, const string_view_type& path)
+ {
+ evaluate(root,path.data(),path.length());
+ }
+ void evaluate(reference root, const char_type* path)
+ {
+ evaluate(root,path,char_traits_type::length(path));
+ }
+
+ void evaluate(reference root,
+ const char_type* path,
+ size_t length)
+ {
+ std::error_code ec;
+ evaluate(root, path, length, ec);
+ if (ec)
+ {
+ throw parse_error(ec,line_,column_);
+ }
+ }
+
+ void evaluate(reference root,
+ const char_type* path,
+ size_t length,
+ std::error_code& ec)
+ {
+ path_state pre_line_break_state = path_state::start;
+
+ begin_input_ = path;
+ end_input_ = path + length;
+ p_ = begin_input_;
+
+ line_ = 1;
+ column_ = 1;
+ state_ = path_state::start;
+
+ recursive_descent_ = false;
+
+ clear_index();
+
+ while (p_ < end_input_)
+ {
+ switch (state_)
+ {
+ case path_state::cr:
+ ++line_;
+ column_ = 1;
+ switch (*p_)
+ {
+ case '\n':
+ state_ = pre_line_break_state;
+ ++p_;
+ ++column_;
+ break;
+ default:
+ state_ = pre_line_break_state;
+ break;
+ }
+ break;
+ case path_state::lf:
+ ++line_;
+ column_ = 1;
+ state_ = pre_line_break_state;
+ break;
+ case path_state::start:
+ switch (*p_)
+ {
+ case ' ':case '\t':
+ break;
+ case '$':
+ case '@':
+ {
+ string_type s;
+ s.push_back('$');
+ node_set v;
+ v.emplace_back(std::move(s),std::addressof(root));
+ stack_.push_back(v);
+
+ state_ = path_state::expect_dot_or_left_bracket;
+ }
+ break;
+ default:
+ err_handler_->fatal_error(jsonpath_parser_errc::expected_root, *this);
+ ec = jsonpath_parser_errc::expected_root;
+ return;
+ };
+ ++p_;
+ ++column_;
+ break;
+ case path_state::dot:
+ switch (*p_)
+ {
+ case '.':
+ recursive_descent_ = true;
+ ++p_;
+ ++column_;
+ state_ = path_state::expect_unquoted_name_or_left_bracket;
+ break;
+ default:
+ state_ = path_state::expect_unquoted_name_or_left_bracket;
+ break;
+ }
+ break;
+ case path_state::expect_unquoted_name_or_left_bracket:
+ switch (*p_)
+ {
+ case '.':
+ err_handler_->fatal_error(jsonpath_parser_errc::expected_name, *this);
+ ec = jsonpath_parser_errc::expected_name;
+ return;
+ case '*':
+ end_all();
+ transfer_nodes();
+ state_ = path_state::expect_dot_or_left_bracket;
+ ++p_;
+ ++column_;
+ break;
+ case '[':
+ state_ = path_state::left_bracket;
+ ++p_;
+ ++column_;
+ break;
+ default:
+ buffer_.clear();
+ state_ = path_state::unquoted_name;
+ break;
+ }
+ break;
+ case path_state::expect_dot_or_left_bracket:
+ switch (*p_)
+ {
+ case ' ':case '\t':
+ break;
+ case '.':
+ state_ = path_state::dot;
+ break;
+ case '[':
+ state_ = path_state::left_bracket;
+ break;
+ default:
+ err_handler_->fatal_error(jsonpath_parser_errc::expected_separator, *this);
+ ec = jsonpath_parser_errc::expected_separator;
+ return;
+ };
+ ++p_;
+ ++column_;
+ break;
+ case path_state::expect_comma_or_right_bracket:
+ switch (*p_)
+ {
+ case ',':
+ state_ = path_state::left_bracket;
+ break;
+ case ']':
+ apply_selectors();
+ state_ = path_state::expect_dot_or_left_bracket;
+ break;
+ case ' ':case '\t':
+ break;
+ default:
+ err_handler_->fatal_error(jsonpath_parser_errc::expected_right_bracket, *this);
+ ec = jsonpath_parser_errc::expected_right_bracket;
+ return;
+ }
+ ++p_;
+ ++column_;
+ break;
+ case path_state::left_bracket:
+ switch (*p_)
+ {
+ case ' ':case '\t':
+ ++p_;
+ ++column_;
+ break;
+ case '(':
+ {
+ jsonpath_filter_parser<Json> parser(line_,column_);
+ auto result = parser.parse(root, p_,end_input_,&p_);
+ line_ = parser.line();
+ column_ = parser.column();
+ selectors_.push_back(std::make_shared<expr_selector>(result));
+ state_ = path_state::expect_comma_or_right_bracket;
+ }
+ break;
+ case '?':
+ {
+ jsonpath_filter_parser<Json> parser(line_,column_);
+ auto result = parser.parse(root,p_,end_input_,&p_);
+ line_ = parser.line();
+ column_ = parser.column();
+ selectors_.push_back(std::make_shared<filter_selector>(result));
+ state_ = path_state::expect_comma_or_right_bracket;
+ }
+ break;
+ case ':':
+ clear_index();
+ state_ = path_state::left_bracket_end;
+ ++p_;
+ ++column_;
+ break;
+ case '*':
+ end_all();
+ state_ = path_state::expect_comma_or_right_bracket;
+ ++p_;
+ ++column_;
+ break;
+ case '\'':
+ state_ = path_state::left_bracket_single_quoted_string;
+ ++p_;
+ ++column_;
+ break;
+ case '\"':
+ state_ = path_state::left_bracket_double_quoted_string;
+ ++p_;
+ ++column_;
+ break;
+ default:
+ clear_index();
+ buffer_.push_back(*p_);
+ state_ = path_state::left_bracket_start;
+ ++p_;
+ ++column_;
+ break;
+ }
+ break;
+ case path_state::left_bracket_start:
+ switch (*p_)
+ {
+ case ':':
+ if (!try_string_to_index(buffer_.data(), buffer_.size(), &start_, &positive_start_))
+ {
+ err_handler_->fatal_error(jsonpath_parser_errc::expected_index, *this);
+ ec = jsonpath_parser_errc::expected_index;
+ return;
+ }
+ state_ = path_state::left_bracket_end;
+ break;
+ case ',':
+ selectors_.push_back(std::make_shared<name_selector>(buffer_,positive_start_));
+ buffer_.clear();
+ state_ = path_state::left_bracket;
+ break;
+ case ']':
+ selectors_.push_back(std::make_shared<name_selector>(buffer_,positive_start_));
+ buffer_.clear();
+ apply_selectors();
+ state_ = path_state::expect_dot_or_left_bracket;
+ break;
+ default:
+ buffer_.push_back(*p_);
+ break;
+ }
+ ++p_;
+ ++column_;
+ break;
+ case path_state::left_bracket_end:
+ switch (*p_)
+ {
+ case '-':
+ positive_end_ = false;
+ state_ = path_state::left_bracket_end2;
+ break;
+ case ':':
+ step_ = 0;
+ state_ = path_state::left_bracket_step;
+ break;
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ undefined_end_ = false;
+ end_ = static_cast<size_t>(*p_-'0');
+ state_ = path_state::left_bracket_end2;
+ break;
+ case ',':
+ selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_));
+ state_ = path_state::left_bracket;
+ break;
+ case ']':
+ selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_));
+ apply_selectors();
+ state_ = path_state::expect_dot_or_left_bracket;
+ break;
+ }
+ ++p_;
+ ++column_;
+ break;
+ case path_state::left_bracket_end2:
+ switch (*p_)
+ {
+ case ':':
+ step_ = 0;
+ state_ = path_state::left_bracket_step;
+ break;
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ undefined_end_ = false;
+ end_ = end_*10 + static_cast<size_t>(*p_-'0');
+ break;
+ case ',':
+ selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_));
+ state_ = path_state::left_bracket;
+ break;
+ case ']':
+ selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_));
+ apply_selectors();
+ state_ = path_state::expect_dot_or_left_bracket;
+ break;
+ }
+ ++p_;
+ ++column_;
+ break;
+ case path_state::left_bracket_step:
+ switch (*p_)
+ {
+ case '-':
+ positive_step_ = false;
+ state_ = path_state::left_bracket_step2;
+ break;
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ step_ = static_cast<size_t>(*p_-'0');
+ state_ = path_state::left_bracket_step2;
+ break;
+ case ',':
+ selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_));
+ state_ = path_state::left_bracket;
+ break;
+ case ']':
+ selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_));
+ apply_selectors();
+ state_ = path_state::expect_dot_or_left_bracket;
+ break;
+ }
+ ++p_;
+ ++column_;
+ break;
+ case path_state::left_bracket_step2:
+ switch (*p_)
+ {
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ step_ = step_*10 + static_cast<size_t>(*p_-'0');
+ break;
+ case ',':
+ selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_));
+ state_ = path_state::left_bracket;
+ break;
+ case ']':
+ selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_));
+ apply_selectors();
+ state_ = path_state::expect_dot_or_left_bracket;
+ break;
+ }
+ ++p_;
+ ++column_;
+ break;
+ case path_state::unquoted_name:
+ switch (*p_)
+ {
+ case '[':
+ apply_unquoted_string(buffer_);
+ transfer_nodes();
+ start_ = 0;
+ state_ = path_state::left_bracket;
+ break;
+ case '.':
+ apply_unquoted_string(buffer_);
+ transfer_nodes();
+ state_ = path_state::dot;
+ break;
+ case ' ':case '\t':
+ apply_unquoted_string(buffer_);
+ transfer_nodes();
+ state_ = path_state::expect_dot_or_left_bracket;
+ break;
+ case '\r':
+ apply_unquoted_string(buffer_);
+ transfer_nodes();
+ pre_line_break_state = path_state::expect_dot_or_left_bracket;
+ state_= path_state::cr;
+ break;
+ case '\n':
+ apply_unquoted_string(buffer_);
+ transfer_nodes();
+ pre_line_break_state = path_state::expect_dot_or_left_bracket;
+ state_= path_state::lf;
+ break;
+ default:
+ buffer_.push_back(*p_);
+ break;
+ };
+ ++p_;
+ ++column_;
+ break;
+ case path_state::left_bracket_single_quoted_string:
+ switch (*p_)
+ {
+ case '\'':
+ selectors_.push_back(std::make_shared<name_selector>(buffer_,positive_start_));
+ buffer_.clear();
+ state_ = path_state::expect_comma_or_right_bracket;
+ break;
+ case '\\':
+ buffer_.push_back(*p_);
+ if (p_+1 < end_input_)
+ {
+ ++p_;
+ ++column_;
+ buffer_.push_back(*p_);
+ }
+ break;
+ default:
+ buffer_.push_back(*p_);
+ break;
+ };
+ ++p_;
+ ++column_;
+ break;
+ case path_state::left_bracket_double_quoted_string:
+ switch (*p_)
+ {
+ case '\"':
+ selectors_.push_back(std::make_shared<name_selector>(buffer_,positive_start_));
+ buffer_.clear();
+ state_ = path_state::expect_comma_or_right_bracket;
+ break;
+ case '\\':
+ buffer_.push_back(*p_);
+ if (p_+1 < end_input_)
+ {
+ ++p_;
+ ++column_;
+ buffer_.push_back(*p_);
+ }
+ break;
+ default:
+ buffer_.push_back(*p_);
+ break;
+ };
+ ++p_;
+ ++column_;
+ break;
+ default:
+ ++p_;
+ ++column_;
+ break;
+ }
+ }
+ switch (state_)
+ {
+ case path_state::unquoted_name:
+ {
+ apply_unquoted_string(buffer_);
+ transfer_nodes();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ void clear_index()
+ {
+ buffer_.clear();
+ start_ = 0;
+ positive_start_ = true;
+ end_ = 0;
+ positive_end_ = true;
+ undefined_end_ = true;
+ step_ = 1;
+ positive_step_ = true;
+ }
+
+ void end_all()
+ {
+ for (size_t i = 0; i < stack_.back().size(); ++i)
+ {
+ const auto& path = stack_.back()[i].path;
+ pointer p = stack_.back()[i].val_ptr;
+
+ if (p->is_array())
+ {
+ for (auto it = p->array_range().begin(); it != p->array_range().end(); ++it)
+ {
+ nodes_.emplace_back(PathCons()(path,it - p->array_range().begin()),std::addressof(*it));
+ }
+ }
+ else if (p->is_object())
+ {
+ for (auto it = p->object_range().begin(); it != p->object_range().end(); ++it)
+ {
+ nodes_.emplace_back(PathCons()(path,it->key()),std::addressof(it->value()));
+ }
+ }
+
+ }
+ start_ = 0;
+ }
+
+ void apply_unquoted_string(const string_view_type& name)
+ {
+ if (name.length() > 0)
+ {
+ for (size_t i = 0; i < stack_.back().size(); ++i)
+ {
+ apply_unquoted_string(stack_.back()[i].path, *(stack_.back()[i].val_ptr), name);
+ }
+ }
+ buffer_.clear();
+ }
+
+ void apply_unquoted_string(const string_type& path, reference val, const string_view_type& name)
+ {
+ if (val.is_object())
+ {
+ if (val.count(name) > 0)
+ {
+ nodes_.emplace_back(PathCons()(path,name),std::addressof(val.at(name)));
+ }
+ if (recursive_descent_)
+ {
+ for (auto it = val.object_range().begin(); it != val.object_range().end(); ++it)
+ {
+ if (it->value().is_object() || it->value().is_array())
+ {
+ apply_unquoted_string(path, it->value(), name);
+ }
+ }
+ }
+ }
+ else if (val.is_array())
+ {
+ size_t pos = 0;
+ if (try_string_to_index(name.data(),name.size(),&pos, &positive_start_))
+ {
+ size_t index = positive_start_ ? pos : val.size() - pos;
+ if (index < val.size())
+ {
+ nodes_.emplace_back(PathCons()(path,index),std::addressof(val[index]));
+ }
+ }
+ else if (name == length_literal() && val.size() > 0)
+ {
+ auto temp = std::make_shared<Json>(val.size());
+ temp_json_values_.push_back(temp);
+ nodes_.emplace_back(PathCons()(path,name),temp.get());
+ }
+ if (recursive_descent_)
+ {
+ for (auto it = val.array_range().begin(); it != val.array_range().end(); ++it)
+ {
+ if (it->is_object() || it->is_array())
+ {
+ apply_unquoted_string(path, *it, name);
+ }
+ }
+ }
+ }
+ else if (val.is_string())
+ {
+ string_view_type sv = val.as_string_view();
+ size_t pos = 0;
+ if (try_string_to_index(name.data(),name.size(),&pos, &positive_start_))
+ {
+ auto sequence = unicons::sequence_at(sv.data(), sv.data() + sv.size(), pos);
+ if (sequence.length() > 0)
+ {
+ auto temp = std::make_shared<Json>(sequence.begin(),sequence.length());
+ temp_json_values_.push_back(temp);
+ nodes_.emplace_back(PathCons()(path,pos),temp.get());
+ }
+ }
+ else if (name == length_literal() && sv.size() > 0)
+ {
+ size_t count = unicons::u32_length(sv.begin(),sv.end());
+ auto temp = std::make_shared<Json>(count);
+ temp_json_values_.push_back(temp);
+ nodes_.emplace_back(PathCons()(path,name),temp.get());
+ }
+ }
+ }
+
+ void apply_selectors()
+ {
+ if (selectors_.size() > 0)
+ {
+ for (size_t i = 0; i < stack_.back().size(); ++i)
+ {
+ node_type& node = stack_.back()[i];
+ apply_selectors(node, node.path, *(node.val_ptr));
+ }
+ selectors_.clear();
+ }
+ transfer_nodes();
+ }
+
+ void apply_selectors(node_type& node, const string_type& path, reference val)
+ {
+ for (const auto& selector : selectors_)
+ {
+ selector->select(node, path, val, nodes_, temp_json_values_);
+ }
+ if (recursive_descent_)
+ {
+ if (val.is_object())
+ {
+ for (auto& nvp : val.object_range())
+ {
+ if (nvp.value().is_object() || nvp.value().is_array())
+ {
+ apply_selectors(node,PathCons()(path,nvp.key()),nvp.value());
+ }
+ }
+ }
+ else if (val.is_array())
+ {
+ for (auto& elem : val.array_range())
+ {
+ if (elem.is_object() || elem.is_array())
+ {
+ apply_selectors(node,path, elem);
+ }
+ }
+ }
+ }
+ }
+
+ void transfer_nodes()
+ {
+ stack_.push_back(nodes_);
+ nodes_.clear();
+ recursive_descent_ = false;
+ }
+
+ size_t do_line_number() const override
+ {
+ return line_;
+ }
+
+ size_t do_column_number() const override
+ {
+ return column_;
+ }
+
+};
+
+}
+
+}}
+
+#endif