// 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 #include #include // std::true_type #include // std::allocator #include // std::make_move_iterator #include // std::move #include #include namespace jsoncons { template > class json_decoder final : public basic_json_visitor { public: using char_type = typename Json::char_type; using typename basic_json_visitor::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:: template rebind_alloc json_byte_allocator_type; private: struct stack_item { key_type name_; Json value_; template stack_item(key_type&& name, Args&& ... args) : name_(std::move(name)), value_(std::forward(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:: template rebind_alloc stack_item_allocator_type; typedef typename std::allocator_traits:: template rebind_alloc structure_info_allocator_type; result_allocator_type result_allocator_; temp_allocator_type temp_allocator_; Json result_; key_type name_; std::vector item_stack_; std::vector 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(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(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(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(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(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(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(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(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(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(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(name_), null_type(), tag); break; case structure_type::root_t: result_ = Json(null_type(), tag); is_valid_ = true; return false; } return true; } }; } #endif