aboutsummaryrefslogtreecommitdiff
path: root/include/jsoncons/json_decoder.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/jsoncons/json_decoder.hpp')
-rw-r--r--include/jsoncons/json_decoder.hpp420
1 files changed, 420 insertions, 0 deletions
diff --git a/include/jsoncons/json_decoder.hpp b/include/jsoncons/json_decoder.hpp
new file mode 100644
index 0000000..c5aa0b2
--- /dev/null
+++ b/include/jsoncons/json_decoder.hpp
@@ -0,0 +1,420 @@
+// Copyright 2013-2016 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_JSON_DECODER_HPP
+#define JSONCONS_JSON_DECODER_HPP
+
+#include <string>
+#include <vector>
+#include <type_traits> // std::true_type
+#include <memory> // std::allocator
+#include <iterator> // std::make_move_iterator
+#include <utility> // std::move
+#include <jsoncons/json_exception.hpp>
+#include <jsoncons/json_visitor.hpp>
+
+namespace jsoncons {
+
+template <class Json,class TempAllocator=std::allocator<char>>
+class json_decoder final : public basic_json_visitor<typename Json::char_type>
+{
+public:
+ using char_type = typename Json::char_type;
+ using typename basic_json_visitor<char_type>::string_view_type;
+
+ using key_value_type = typename Json::key_value_type;
+ using key_type = typename Json::key_type;
+ using array = typename Json::array;
+ using object = typename Json::object;
+ using result_allocator_type = typename Json::allocator_type;
+ using json_string_allocator = typename key_type::allocator_type;
+ using json_array_allocator = typename array::allocator_type;
+ using json_object_allocator = typename object::allocator_type;
+ typedef typename std::allocator_traits<result_allocator_type>:: template rebind_alloc<uint8_t> json_byte_allocator_type;
+private:
+ struct stack_item
+ {
+ key_type name_;
+ Json value_;
+
+ template <class... Args>
+ stack_item(key_type&& name, Args&& ... args)
+ : name_(std::move(name)), value_(std::forward<Args>(args)...)
+ {
+ }
+
+ stack_item() = default;
+ stack_item(const stack_item&) = default;
+ stack_item(stack_item&&) = default;
+ stack_item& operator=(const stack_item&) = default;
+ stack_item& operator=(stack_item&&) = default;
+ };
+
+ enum class structure_type {root_t, array_t, object_t};
+
+ struct structure_info
+ {
+ structure_type type_;
+ std::size_t container_index_;
+
+ structure_info(structure_type type, std::size_t offset) noexcept
+ : type_(type), container_index_(offset)
+ {
+ }
+
+ };
+
+ using temp_allocator_type = TempAllocator;
+ typedef typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<stack_item> stack_item_allocator_type;
+ typedef typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<structure_info> structure_info_allocator_type;
+
+ result_allocator_type result_allocator_;
+ temp_allocator_type temp_allocator_;
+
+ Json result_;
+
+ key_type name_;
+ std::vector<stack_item,stack_item_allocator_type> item_stack_;
+ std::vector<structure_info,structure_info_allocator_type> structure_stack_;
+ bool is_valid_;
+
+public:
+ json_decoder(const temp_allocator_type& temp_alloc = temp_allocator_type())
+ : result_allocator_(result_allocator_type()),
+ temp_allocator_(temp_alloc),
+ result_(),
+ name_(result_allocator_),
+ item_stack_(temp_allocator_),
+ structure_stack_(temp_allocator_),
+ is_valid_(false)
+ {
+ item_stack_.reserve(1000);
+ structure_stack_.reserve(100);
+ structure_stack_.emplace_back(structure_type::root_t, 0);
+ }
+
+ json_decoder(result_allocator_arg_t,
+ const result_allocator_type& result_alloc)
+ : result_allocator_(result_alloc),
+ temp_allocator_(),
+ result_(),
+ name_(result_allocator_),
+ item_stack_(),
+ structure_stack_(),
+ is_valid_(false)
+ {
+ item_stack_.reserve(1000);
+ structure_stack_.reserve(100);
+ structure_stack_.emplace_back(structure_type::root_t, 0);
+ }
+
+ json_decoder(result_allocator_arg_t,
+ const result_allocator_type& result_alloc,
+ const temp_allocator_type& temp_alloc)
+ : result_allocator_(result_alloc),
+ temp_allocator_(temp_alloc),
+ result_(),
+ name_(result_allocator_),
+ item_stack_(temp_allocator_),
+ structure_stack_(temp_allocator_),
+ is_valid_(false)
+ {
+ item_stack_.reserve(1000);
+ structure_stack_.reserve(100);
+ structure_stack_.emplace_back(structure_type::root_t, 0);
+ }
+
+ void reset()
+ {
+ is_valid_ = false;
+ item_stack_.clear();
+ structure_stack_.clear();
+ structure_stack_.emplace_back(structure_type::root_t, 0);
+ }
+
+ bool is_valid() const
+ {
+ return is_valid_;
+ }
+
+ Json get_result()
+ {
+ JSONCONS_ASSERT(is_valid_);
+ is_valid_ = false;
+ return std::move(result_);
+ }
+
+#if !defined(JSONCONS_NO_DEPRECATED)
+ JSONCONS_DEPRECATED_MSG("Instead, use get_result()")
+ Json& root()
+ {
+ return result_;
+ }
+#endif
+
+private:
+
+ void visit_flush() override
+ {
+ }
+
+ bool visit_begin_object(semantic_tag tag, const ser_context&, std::error_code&) override
+ {
+ if (structure_stack_.back().type_ == structure_type::root_t)
+ {
+ item_stack_.clear();
+ is_valid_ = false;
+ }
+ item_stack_.emplace_back(std::forward<key_type>(name_), json_object_arg, tag, result_allocator_);
+ structure_stack_.emplace_back(structure_type::object_t, item_stack_.size()-1);
+ return true;
+ }
+
+ bool visit_end_object(const ser_context&, std::error_code&) override
+ {
+ JSONCONS_ASSERT(structure_stack_.size() > 0);
+ JSONCONS_ASSERT(structure_stack_.back().type_ == structure_type::object_t);
+ const size_t structure_index = structure_stack_.back().container_index_;
+ JSONCONS_ASSERT(item_stack_.size() > structure_index);
+ const size_t count = item_stack_.size() - (structure_index + 1);
+ auto first = item_stack_.begin() + (structure_index+1);
+ auto last = first + count;
+ item_stack_[structure_index].value_.object_value().insert(
+ std::make_move_iterator(first),
+ std::make_move_iterator(last),
+ [](stack_item&& val){return key_value_type(std::move(val.name_), std::move(val.value_));}
+ );
+ item_stack_.erase(item_stack_.begin()+structure_index+1, item_stack_.end());
+ structure_stack_.pop_back();
+ if (structure_stack_.back().type_ == structure_type::root_t)
+ {
+ result_.swap(item_stack_.front().value_);
+ item_stack_.pop_back();
+ is_valid_ = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visit_begin_array(semantic_tag tag, const ser_context&, std::error_code&) override
+ {
+ if (structure_stack_.back().type_ == structure_type::root_t)
+ {
+ item_stack_.clear();
+ is_valid_ = false;
+ }
+ item_stack_.emplace_back(std::forward<key_type>(name_), json_array_arg, tag, result_allocator_);
+ structure_stack_.emplace_back(structure_type::array_t, item_stack_.size()-1);
+ return true;
+ }
+
+ bool visit_end_array(const ser_context&, std::error_code&) override
+ {
+ JSONCONS_ASSERT(structure_stack_.size() > 1);
+ JSONCONS_ASSERT(structure_stack_.back().type_ == structure_type::array_t);
+ const size_t container_index = structure_stack_.back().container_index_;
+ JSONCONS_ASSERT(item_stack_.size() > container_index);
+
+ auto& container = item_stack_[container_index].value_;
+
+ const size_t size = item_stack_.size() - (container_index + 1);
+ //std::cout << "size on item stack: " << size << "\n";
+
+ if (size > 0)
+ {
+ container.reserve(size);
+ auto first = item_stack_.begin() + (container_index+1);
+ auto last = first + size;
+ for (auto it = first; it != last; ++it)
+ {
+ container.push_back(std::move(it->value_));
+ }
+ item_stack_.erase(first, item_stack_.end());
+ }
+
+ structure_stack_.pop_back();
+ if (structure_stack_.back().type_ == structure_type::root_t)
+ {
+ result_.swap(item_stack_.front().value_);
+ item_stack_.pop_back();
+ is_valid_ = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override
+ {
+ name_ = key_type(name.data(),name.length(),result_allocator_);
+ return true;
+ }
+
+ bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) override
+ {
+ switch (structure_stack_.back().type_)
+ {
+ case structure_type::object_t:
+ case structure_type::array_t:
+ item_stack_.emplace_back(std::forward<key_type>(name_), sv, tag, result_allocator_);
+ break;
+ case structure_type::root_t:
+ result_ = Json(sv, tag, result_allocator_);
+ is_valid_ = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visit_byte_string(const byte_string_view& b,
+ semantic_tag tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ switch (structure_stack_.back().type_)
+ {
+ case structure_type::object_t:
+ case structure_type::array_t:
+ item_stack_.emplace_back(std::forward<key_type>(name_), byte_string_arg, b, tag, result_allocator_);
+ break;
+ case structure_type::root_t:
+ result_ = Json(byte_string_arg, b, tag, result_allocator_);
+ is_valid_ = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visit_byte_string(const byte_string_view& b,
+ uint64_t ext_tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ switch (structure_stack_.back().type_)
+ {
+ case structure_type::object_t:
+ case structure_type::array_t:
+ item_stack_.emplace_back(std::forward<key_type>(name_), byte_string_arg, b, ext_tag, result_allocator_);
+ break;
+ case structure_type::root_t:
+ result_ = Json(byte_string_arg, b, ext_tag, result_allocator_);
+ is_valid_ = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visit_int64(int64_t value,
+ semantic_tag tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ switch (structure_stack_.back().type_)
+ {
+ case structure_type::object_t:
+ case structure_type::array_t:
+ item_stack_.emplace_back(std::forward<key_type>(name_), value, tag);
+ break;
+ case structure_type::root_t:
+ result_ = Json(value,tag);
+ is_valid_ = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visit_uint64(uint64_t value,
+ semantic_tag tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ switch (structure_stack_.back().type_)
+ {
+ case structure_type::object_t:
+ case structure_type::array_t:
+ item_stack_.emplace_back(std::forward<key_type>(name_), value, tag);
+ break;
+ case structure_type::root_t:
+ result_ = Json(value,tag);
+ is_valid_ = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visit_half(uint16_t value,
+ semantic_tag tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ switch (structure_stack_.back().type_)
+ {
+ case structure_type::object_t:
+ case structure_type::array_t:
+ item_stack_.emplace_back(std::forward<key_type>(name_), half_arg, value, tag);
+ break;
+ case structure_type::root_t:
+ result_ = Json(half_arg, value, tag);
+ is_valid_ = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visit_double(double value,
+ semantic_tag tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ switch (structure_stack_.back().type_)
+ {
+ case structure_type::object_t:
+ case structure_type::array_t:
+ item_stack_.emplace_back(std::forward<key_type>(name_), value, tag);
+ break;
+ case structure_type::root_t:
+ result_ = Json(value, tag);
+ is_valid_ = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visit_bool(bool value, semantic_tag tag, const ser_context&, std::error_code&) override
+ {
+ switch (structure_stack_.back().type_)
+ {
+ case structure_type::object_t:
+ case structure_type::array_t:
+ item_stack_.emplace_back(std::forward<key_type>(name_), value, tag);
+ break;
+ case structure_type::root_t:
+ result_ = Json(value, tag);
+ is_valid_ = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool visit_null(semantic_tag tag, const ser_context&, std::error_code&) override
+ {
+ switch (structure_stack_.back().type_)
+ {
+ case structure_type::object_t:
+ case structure_type::array_t:
+ item_stack_.emplace_back(std::forward<key_type>(name_), null_type(), tag);
+ break;
+ case structure_type::root_t:
+ result_ = Json(null_type(), tag);
+ is_valid_ = true;
+ return false;
+ }
+ return true;
+ }
+};
+
+}
+
+#endif