// Copyright 2018 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_VISITOR2_HPP #define JSONCONS_JSON_VISITOR2_HPP #include #include namespace jsoncons { template > class basic_json_visitor2_to_visitor_adaptor; template class basic_json_visitor2 { template friend class basic_json_visitor2_to_visitor_adaptor; public: using char_type = CharT; using char_traits_type = std::char_traits; using string_view_type = jsoncons::basic_string_view; basic_json_visitor2(basic_json_visitor2&&) = default; basic_json_visitor2& operator=(basic_json_visitor2&&) = default; basic_json_visitor2() = default; virtual ~basic_json_visitor2() noexcept = default; void flush() { visit_flush(); } bool begin_object(semantic_tag tag=semantic_tag::none, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_begin_object(tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool begin_object(std::size_t length, semantic_tag tag=semantic_tag::none, const ser_context& context = ser_context()) { std::error_code ec; bool more = visit_begin_object(length, tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool end_object(const ser_context& context = ser_context()) { std::error_code ec; bool more = visit_end_object(context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool begin_array(semantic_tag tag=semantic_tag::none, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_begin_array(tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool begin_array(std::size_t length, semantic_tag tag=semantic_tag::none, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_begin_array(length, tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool end_array(const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_end_array(context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool key(const string_view_type& name, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_string(name, semantic_tag::none, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool null_value(semantic_tag tag = semantic_tag::none, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_null(tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool bool_value(bool value, semantic_tag tag = semantic_tag::none, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_bool(value, tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool string_value(const string_view_type& value, semantic_tag tag = semantic_tag::none, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_string(value, tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } template bool byte_string_value(const Source& b, semantic_tag tag=semantic_tag::none, const ser_context& context=ser_context(), typename std::enable_if::value,int>::type = 0) { std::error_code ec; bool more = visit_byte_string(byte_string_view(reinterpret_cast(b.data()),b.size()), tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } template bool byte_string_value(const Source& b, uint64_t ext_tag, const ser_context& context=ser_context(), typename std::enable_if::value,int>::type = 0) { std::error_code ec; bool more = visit_byte_string(byte_string_view(reinterpret_cast(b.data()),b.size()), ext_tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool uint64_value(uint64_t value, semantic_tag tag = semantic_tag::none, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_uint64(value, tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool int64_value(int64_t value, semantic_tag tag = semantic_tag::none, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_int64(value, tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool half_value(uint16_t value, semantic_tag tag = semantic_tag::none, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_half(value, tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool double_value(double value, semantic_tag tag = semantic_tag::none, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_double(value, tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool begin_object(semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_begin_object(tag, context, ec); } bool begin_object(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_begin_object(length, tag, context, ec); } bool end_object(const ser_context& context, std::error_code& ec) { return visit_end_object(context, ec); } bool begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_begin_array(tag, context, ec); } bool begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_begin_array(length, tag, context, ec); } bool end_array(const ser_context& context, std::error_code& ec) { return visit_end_array(context, ec); } bool key(const string_view_type& name, const ser_context& context, std::error_code& ec) { return visit_string(name, semantic_tag::none, context, ec); } bool null_value(semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_null(tag, context, ec); } bool bool_value(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_bool(value, tag, context, ec); } bool string_value(const string_view_type& value, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_string(value, tag, context, ec); } template bool byte_string_value(const Source& b, semantic_tag tag, const ser_context& context, std::error_code& ec, typename std::enable_if::value,int>::type = 0) { return visit_byte_string(byte_string_view(reinterpret_cast(b.data()),b.size()), tag, context, ec); } template bool byte_string_value(const Source& b, uint64_t ext_tag, const ser_context& context, std::error_code& ec, typename std::enable_if::value,int>::type = 0) { return visit_byte_string(byte_string_view(reinterpret_cast(b.data()),b.size()), ext_tag, context, ec); } bool uint64_value(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_uint64(value, tag, context, ec); } bool int64_value(int64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_int64(value, tag, context, ec); } bool half_value(uint16_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_half(value, tag, context, ec); } bool double_value(double value, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_double(value, tag, context, ec); } template bool typed_array(const jsoncons::span& data, semantic_tag tag=semantic_tag::none, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_typed_array(data, tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } template bool typed_array(const jsoncons::span& data, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_typed_array(data, tag, context, ec); } bool typed_array(half_arg_t, const jsoncons::span& s, semantic_tag tag = semantic_tag::none, const ser_context& context = ser_context()) { std::error_code ec; bool more = visit_typed_array(half_arg, s, tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool typed_array(half_arg_t, const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_typed_array(half_arg, s, tag, context, ec); } bool begin_multi_dim(const jsoncons::span& shape, semantic_tag tag = semantic_tag::multi_dim_row_major, const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_begin_multi_dim(shape, tag, context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool begin_multi_dim(const jsoncons::span& shape, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_begin_multi_dim(shape, tag, context, ec); } bool end_multi_dim(const ser_context& context=ser_context()) { std::error_code ec; bool more = visit_end_multi_dim(context, ec); if (ec) { JSONCONS_THROW(ser_error(ec, context.line(), context.column())); } return more; } bool end_multi_dim(const ser_context& context, std::error_code& ec) { return visit_end_multi_dim(context, ec); } private: virtual void visit_flush() = 0; virtual bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code& ec) = 0; virtual bool visit_begin_object(std::size_t /*length*/, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_begin_object(tag, context, ec); } virtual bool visit_end_object(const ser_context& context, std::error_code& ec) = 0; virtual bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) = 0; virtual bool visit_begin_array(std::size_t /*length*/, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_begin_array(tag, context, ec); } virtual bool visit_end_array(const ser_context& context, std::error_code& ec) = 0; virtual bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) = 0; virtual bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code&) = 0; virtual bool visit_string(const string_view_type& value, semantic_tag tag, const ser_context& context, std::error_code& ec) = 0; virtual bool visit_byte_string(const byte_string_view& value, semantic_tag tag, const ser_context& context, std::error_code& ec) = 0; virtual bool visit_byte_string(const byte_string_view& value, uint64_t /*ext_tag*/, const ser_context& context, std::error_code& ec) { return visit_byte_string(value, semantic_tag::none, context, ec); } virtual bool visit_uint64(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) = 0; virtual bool visit_int64(int64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) = 0; virtual bool visit_half(uint16_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) { return visit_double(binary::decode_half(value), tag, context, ec); } virtual bool visit_double(double value, semantic_tag tag, const ser_context& context, std::error_code& ec) = 0; virtual bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) { bool more = begin_array(s.size(), tag, context, ec); for (auto p = s.begin(); more && p != s.end(); ++p) { more = uint64_value(*p, semantic_tag::none, context, ec); } if (more) { more = end_array(context, ec); } return more; } virtual bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) { bool more = begin_array(s.size(), tag, context, ec); for (auto p = s.begin(); more && p != s.end(); ++p) { more = uint64_value(*p, semantic_tag::none, context, ec); } if (more) { more = end_array(context, ec); } return more; } virtual bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) { bool more = begin_array(s.size(), tag, context, ec); for (auto p = s.begin(); more && p != s.end(); ++p) { more = uint64_value(*p, semantic_tag::none, context, ec); } if (more) { more = end_array(context, ec); } return more; } virtual bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) { bool more = begin_array(s.size(), tag, context, ec); for (auto p = s.begin(); more && p != s.end(); ++p) { more = uint64_value(*p,semantic_tag::none,context, ec); } if (more) { more = end_array(context, ec); } return more; } virtual bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) { bool more = begin_array(s.size(), tag,context, ec); for (auto p = s.begin(); more && p != s.end(); ++p) { more = int64_value(*p,semantic_tag::none,context, ec); } if (more) { more = end_array(context, ec); } return more; } virtual bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) { bool more = begin_array(s.size(), tag,context, ec); for (auto p = s.begin(); more && p != s.end(); ++p) { more = int64_value(*p,semantic_tag::none,context, ec); } if (more) { more = end_array(context, ec); } return more; } virtual bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) { bool more = begin_array(s.size(), tag,context, ec); for (auto p = s.begin(); more && p != s.end(); ++p) { more = int64_value(*p,semantic_tag::none,context, ec); } if (more) { more = end_array(context, ec); } return more; } virtual bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) { bool more = begin_array(s.size(), tag,context, ec); for (auto p = s.begin(); more && p != s.end(); ++p) { more = int64_value(*p,semantic_tag::none,context, ec); } if (more) { more = end_array(context, ec); } return more; } virtual bool visit_typed_array(half_arg_t, const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) { bool more = begin_array(s.size(), tag, context, ec); for (auto p = s.begin(); more && p != s.end(); ++p) { more = half_value(*p, semantic_tag::none, context, ec); } if (more) { more = end_array(context, ec); } return more; } virtual bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) { bool more = begin_array(s.size(), tag,context, ec); for (auto p = s.begin(); more && p != s.end(); ++p) { more = double_value(*p,semantic_tag::none,context, ec); } if (more) { more = end_array(context, ec); } return more; } virtual bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) { bool more = begin_array(s.size(), tag,context, ec); for (auto p = s.begin(); more && p != s.end(); ++p) { more = double_value(*p,semantic_tag::none,context, ec); } if (more) { more = end_array(context, ec); } return more; } virtual bool visit_begin_multi_dim(const jsoncons::span& shape, semantic_tag tag, const ser_context& context, std::error_code& ec) { bool more = visit_begin_array(2, tag, context, ec); if (more) { more = visit_begin_array(shape.size(), tag, context, ec); for (auto it = shape.begin(); more && it != shape.end(); ++it) { visit_uint64(*it, semantic_tag::none, context, ec); } if (more) { more = visit_end_array(context, ec); } } return more; } virtual bool visit_end_multi_dim(const ser_context& context, std::error_code& ec) { return visit_end_array(context, ec); } }; template class basic_json_visitor2_to_visitor_adaptor : public basic_json_visitor2 { public: using typename basic_json_visitor2::char_type; using typename basic_json_visitor2::string_view_type; private: using char_allocator_type = typename std::allocator_traits:: template rebind_alloc; using string_type = std::basic_string,char_allocator_type>; enum class container_t {root, array, object}; enum class target_t {destination, buffer}; struct level { private: target_t state_; container_t type_; int even_odd_; std::size_t count_; public: level(target_t state, container_t type) noexcept : state_(state), type_(type), even_odd_(type == container_t::object ? 0 : 1), count_(0) { } void advance() { if (!is_key()) { ++count_; } if (is_object()) { even_odd_ = !even_odd_; } } bool is_key() const { return even_odd_ == 0; } bool is_object() const { return type_ == container_t::object; } target_t target() const { return state_; } std::size_t count() const { return count_; } }; using level_allocator_type = typename std::allocator_traits:: template rebind_alloc; basic_default_json_visitor default_visitor_; basic_json_visitor* destination_; string_type key_; string_type key_buffer_; std::vector level_stack_; const std::basic_string null_constant = {'n','u','l','l'}; const std::basic_string true_constant = { 't','r','u','e' }; const std::basic_string false_constant = { 'f', 'a', 'l', 's', 'e' }; // noncopyable and nonmoveable basic_json_visitor2_to_visitor_adaptor(const basic_json_visitor2_to_visitor_adaptor&) = delete; basic_json_visitor2_to_visitor_adaptor& operator=(const basic_json_visitor2_to_visitor_adaptor&) = delete; public: explicit basic_json_visitor2_to_visitor_adaptor(const Allocator& alloc = Allocator()) : default_visitor_(), destination_(std::addressof(default_visitor_)), key_(alloc), key_buffer_(alloc), level_stack_(alloc) { level_stack_.emplace_back(target_t::destination,container_t::root); // root } explicit basic_json_visitor2_to_visitor_adaptor(basic_json_visitor& visitor, const Allocator& alloc = Allocator()) : destination_(std::addressof(visitor)), key_(alloc), key_buffer_(alloc), level_stack_(alloc) { level_stack_.emplace_back(target_t::destination,container_t::root); // root } void reset() { key_.clear(); key_buffer_.clear(); level_stack_.clear(); level_stack_.emplace_back(target_t::destination,container_t::root); // root } basic_json_visitor& destination() { return *destination_; } void destination(basic_json_visitor& dest) { destination_ = std::addressof(dest); } private: void visit_flush() override { destination_->flush(); } bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (level_stack_.back().is_key()) { if (level_stack_.back().target() == target_t::buffer && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } level_stack_.emplace_back(target_t::buffer, container_t::object); key_buffer_.push_back('{'); return true; } else { switch (level_stack_.back().target()) { case target_t::buffer: level_stack_.emplace_back(target_t::buffer, container_t::object); key_buffer_.push_back('{'); return true; default: level_stack_.emplace_back(target_t::destination, container_t::object); return destination_->begin_object(tag, context, ec); } } } bool visit_begin_object(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (level_stack_.back().is_key()) { if (level_stack_.back().target() == target_t::buffer && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } level_stack_.emplace_back(target_t::buffer, container_t::object); key_buffer_.push_back('{'); return true; } else { switch (level_stack_.back().target()) { case target_t::buffer: if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } level_stack_.emplace_back(target_t::buffer, container_t::object); key_buffer_.push_back('{'); return true; default: level_stack_.emplace_back(target_t::destination, container_t::object); return destination_->begin_object(length, tag, context, ec); } } } bool visit_end_object(const ser_context& context, std::error_code& ec) override { bool retval = true; switch (level_stack_.back().target()) { case target_t::buffer: key_buffer_.push_back('}'); JSONCONS_ASSERT(level_stack_.size() > 1); level_stack_.pop_back(); if (level_stack_.back().target() == target_t::destination) { retval = destination_->key(key_buffer_,context, ec); key_buffer_.clear(); } else if (level_stack_.back().is_key()) { key_buffer_.push_back(':'); } level_stack_.back().advance(); break; default: JSONCONS_ASSERT(level_stack_.size() > 1); level_stack_.pop_back(); level_stack_.back().advance(); retval = destination_->end_object(context, ec); break; } return retval; } bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (level_stack_.back().is_key()) { if (level_stack_.back().target() == target_t::buffer && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } level_stack_.emplace_back(target_t::buffer, container_t::array); key_buffer_.push_back('['); return true; } else { switch (level_stack_.back().target()) { case target_t::buffer: if (level_stack_.back().is_object() && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } level_stack_.emplace_back(target_t::buffer, container_t::array); key_buffer_.push_back('['); return true; default: level_stack_.emplace_back(target_t::destination, container_t::array); return destination_->begin_array(tag, context, ec); } } } bool visit_begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (level_stack_.back().is_key()) { if (level_stack_.back().target() == target_t::buffer && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } level_stack_.emplace_back(target_t::buffer, container_t::array); key_buffer_.push_back('['); return true; } else { switch (level_stack_.back().target()) { case target_t::buffer: if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } level_stack_.emplace_back(target_t::buffer, container_t::array); key_buffer_.push_back('['); return true; default: level_stack_.emplace_back(target_t::destination, container_t::array); return destination_->begin_array(length, tag, context, ec); } } } bool visit_end_array(const ser_context& context, std::error_code& ec) override { bool retval = true; switch (level_stack_.back().target()) { case target_t::buffer: key_buffer_.push_back(']'); JSONCONS_ASSERT(level_stack_.size() > 1); level_stack_.pop_back(); if (level_stack_.back().target() == target_t::destination) { retval = destination_->key(key_buffer_, context, ec); key_buffer_.clear(); } else if (level_stack_.back().is_key()) { key_buffer_.push_back(':'); } level_stack_.back().advance(); break; default: JSONCONS_ASSERT(level_stack_.size() > 1); level_stack_.pop_back(); level_stack_.back().advance(); retval = destination_->end_array(context, ec); break; } return retval; } bool visit_string(const string_view_type& value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool retval = true; if (level_stack_.back().is_key()) { switch (level_stack_.back().target()) { case target_t::buffer: if (level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.push_back('\"'); key_buffer_.insert(key_buffer_.end(), value.begin(), value.end()); key_buffer_.push_back('\"'); key_buffer_.push_back(':'); retval = true; break; default: retval = destination_->key(value, context, ec); break; } } else { switch (level_stack_.back().target()) { case target_t::buffer: if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.push_back('\"'); key_buffer_.insert(key_buffer_.end(), value.begin(), value.end()); key_buffer_.push_back('\"'); retval = true; break; default: retval = destination_->string_value(value, tag, context, ec); break; } } level_stack_.back().advance(); return retval; } bool visit_byte_string(const byte_string_view& value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool retval = true; if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) { key_.clear(); switch (tag) { case semantic_tag::base64: encode_base64(value.begin(), value.end(), key_); break; case semantic_tag::base16: encode_base16(value.begin(), value.end(),key_); break; default: encode_base64url(value.begin(), value.end(),key_); break; } } if (level_stack_.back().is_key()) { switch (level_stack_.back().target()) { case target_t::buffer: if (level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.push_back('\"'); key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); key_buffer_.push_back('\"'); key_buffer_.push_back(':'); retval = true; break; default: retval = destination_->key(key_, context, ec); break; } } else { switch (level_stack_.back().target()) { case target_t::buffer: if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.push_back('\"'); key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); key_buffer_.push_back('\"'); retval = true; break; default: retval = destination_->byte_string_value(value, tag, context, ec); break; } } level_stack_.back().advance(); return retval; } bool visit_byte_string(const byte_string_view& value, uint64_t ext_tag, const ser_context& context, std::error_code& ec) override { bool retval = true; if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) { key_.clear(); encode_base64url(value.begin(), value.end(),key_); } if (level_stack_.back().is_key()) { switch (level_stack_.back().target()) { case target_t::buffer: if (level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.push_back('\"'); key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); key_buffer_.push_back('\"'); key_buffer_.push_back(':'); retval = true; break; default: retval = destination_->key(key_, context, ec); break; } } else { switch (level_stack_.back().target()) { case target_t::buffer: if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.push_back('\"'); key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); key_buffer_.push_back('\"'); retval = true; break; default: retval = destination_->byte_string_value(value, ext_tag, context, ec); break; } } level_stack_.back().advance(); return retval; } bool visit_uint64(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool retval = true; if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) { key_.clear(); jsoncons::detail::from_integer(value,key_); } if (level_stack_.back().is_key()) { switch (level_stack_.back().target()) { case target_t::buffer: if (level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); key_buffer_.push_back(':'); retval = true; break; default: retval = destination_->key(key_, context, ec); break; } } else { switch (level_stack_.back().target()) { case target_t::buffer: if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); retval = true; break; default: retval = destination_->uint64_value(value, tag, context, ec); break; } } level_stack_.back().advance(); return retval; } bool visit_int64(int64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool retval = true; if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) { key_.clear(); jsoncons::detail::from_integer(value,key_); } if (level_stack_.back().is_key()) { switch (level_stack_.back().target()) { case target_t::buffer: if (level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); key_buffer_.push_back(':'); retval = true; break; default: retval = destination_->key(key_, context, ec); break; } } else { switch (level_stack_.back().target()) { case target_t::buffer: if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); retval = true; break; default: retval = destination_->int64_value(value, tag, context, ec); break; } } level_stack_.back().advance(); return retval; } bool visit_half(uint16_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool retval = true; if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) { key_.clear(); jsoncons::string_sink sink(key_); jsoncons::detail::write_double f{float_chars_format::general,0}; double x = binary::decode_half(value); f(x, sink); } if (level_stack_.back().is_key()) { switch (level_stack_.back().target()) { case target_t::buffer: if (level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); key_buffer_.push_back(':'); retval = true; break; default: retval = destination_->key(key_, context, ec); break; } } else { switch (level_stack_.back().target()) { case target_t::buffer: if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); retval = true; break; default: retval = destination_->half_value(value, tag, context, ec); break; } } level_stack_.back().advance(); return retval; } bool visit_double(double value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool retval = true; if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) { key_.clear(); string_sink sink(key_); jsoncons::detail::write_double f{float_chars_format::general,0}; f(value, sink); } if (level_stack_.back().is_key()) { switch (level_stack_.back().target()) { case target_t::buffer: if (level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); key_buffer_.push_back(':'); retval = true; break; default: retval = destination_->key(key_, context, ec); break; } } else { switch (level_stack_.back().target()) { case target_t::buffer: if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); retval = true; break; default: retval = destination_->double_value(value, tag, context, ec); break; } } level_stack_.back().advance(); return retval; } bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool retval = true; if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) { key_ = value ? true_constant : false_constant; } if (level_stack_.back().is_key()) { switch (level_stack_.back().target()) { case target_t::buffer: if (level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); key_buffer_.push_back(':'); retval = true; break; default: retval = destination_->key(key_, context, ec); break; } } else { switch (level_stack_.back().target()) { case target_t::buffer: if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); retval = true; break; default: retval = destination_->bool_value(value, tag, context, ec); break; } } level_stack_.back().advance(); return retval; } bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool retval = true; if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) { key_ = null_constant; } if (level_stack_.back().is_key()) { switch (level_stack_.back().target()) { case target_t::buffer: if (level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); key_buffer_.push_back(':'); retval = true; break; default: retval = destination_->key(key_, context, ec); break; } } else { switch (level_stack_.back().target()) { case target_t::buffer: if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) { key_buffer_.push_back(','); } key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); retval = true; break; default: retval = destination_->null_value(tag, context, ec); break; } } level_stack_.back().advance(); return retval; } bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool is_key = level_stack_.back().is_key(); level_stack_.back().advance(); if (is_key || level_stack_.back().target() == target_t::buffer) { return basic_json_visitor2::visit_typed_array(s,tag,context,ec); } else { return destination_->typed_array(s, tag, context, ec); } } bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool is_key = level_stack_.back().is_key(); level_stack_.back().advance(); if (is_key || level_stack_.back().target() == target_t::buffer) { return basic_json_visitor2::visit_typed_array(s,tag,context,ec); } else { return destination_->typed_array(s, tag, context, ec); } } bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool is_key = level_stack_.back().is_key(); level_stack_.back().advance(); if (is_key || level_stack_.back().target() == target_t::buffer) { return basic_json_visitor2::visit_typed_array(s,tag,context,ec); } else { return destination_->typed_array(s, tag, context, ec); } } bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool is_key = level_stack_.back().is_key(); level_stack_.back().advance(); if (is_key || level_stack_.back().target() == target_t::buffer) { return basic_json_visitor2::visit_typed_array(s,tag,context,ec); } else { return destination_->typed_array(s, tag, context, ec); } } bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool is_key = level_stack_.back().is_key(); level_stack_.back().advance(); if (is_key || level_stack_.back().target() == target_t::buffer) { return basic_json_visitor2::visit_typed_array(s,tag,context,ec); } else { return destination_->typed_array(s, tag, context, ec); } } bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool is_key = level_stack_.back().is_key(); level_stack_.back().advance(); if (is_key || level_stack_.back().target() == target_t::buffer) { return basic_json_visitor2::visit_typed_array(s,tag,context,ec); } else { return destination_->typed_array(s, tag, context, ec); } } bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool is_key = level_stack_.back().is_key(); level_stack_.back().advance(); if (is_key || level_stack_.back().target() == target_t::buffer) { return basic_json_visitor2::visit_typed_array(s,tag,context,ec); } else { return destination_->typed_array(s, tag, context, ec); } } bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool is_key = level_stack_.back().is_key(); level_stack_.back().advance(); if (is_key || level_stack_.back().target() == target_t::buffer) { return basic_json_visitor2::visit_typed_array(s,tag,context,ec); } else { return destination_->typed_array(s, tag, context, ec); } } bool visit_typed_array(half_arg_t, const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool is_key = level_stack_.back().is_key(); level_stack_.back().advance(); if (is_key || level_stack_.back().target() == target_t::buffer) { return basic_json_visitor2::visit_typed_array(half_arg,s,tag,context,ec); } else { return destination_->typed_array(half_arg, s, tag, context, ec); } } bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool is_key = level_stack_.back().is_key(); level_stack_.back().advance(); if (is_key || level_stack_.back().target() == target_t::buffer) { return basic_json_visitor2::visit_typed_array(s,tag,context,ec); } else { return destination_->typed_array(s, tag, context, ec); } } bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context& context, std::error_code& ec) override { bool is_key = level_stack_.back().is_key(); level_stack_.back().advance(); if (is_key || level_stack_.back().target() == target_t::buffer) { return basic_json_visitor2::visit_typed_array(s,tag,context,ec); } else { return destination_->typed_array(s, tag, context, ec); } } }; template class basic_default_json_visitor2 : public basic_json_visitor2 { bool parse_more_; std::error_code ec_; public: using typename basic_json_visitor2::string_view_type; basic_default_json_visitor2(bool accept_more = true, std::error_code ec = std::error_code()) : parse_more_(accept_more), ec_(ec) { } private: void visit_flush() override { } bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_begin_object(std::size_t, semantic_tag, const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_end_object(const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_begin_array(std::size_t, semantic_tag, const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_end_array(const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_null(semantic_tag, const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_string(const string_view_type&, semantic_tag, const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_byte_string(const byte_string_view&, semantic_tag, const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_uint64(uint64_t, semantic_tag, const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_int64(int64_t, semantic_tag, const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_half(uint16_t, semantic_tag, const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_double(double, semantic_tag, const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } bool visit_bool(bool, semantic_tag, const ser_context&, std::error_code& ec) override { if (ec_) { ec = ec_; } return parse_more_; } }; // basic_json_visitor_to_visitor2_adaptor template class basic_json_visitor_to_visitor2_adaptor : public basic_json_visitor { public: using typename basic_json_visitor::char_type; using typename basic_json_visitor::string_view_type; private: basic_json_visitor2& destination_; // noncopyable and nonmoveable basic_json_visitor_to_visitor2_adaptor(const basic_json_visitor_to_visitor2_adaptor&) = delete; basic_json_visitor_to_visitor2_adaptor& operator=(const basic_json_visitor_to_visitor2_adaptor&) = delete; public: basic_json_visitor_to_visitor2_adaptor(basic_json_visitor2& visitor) : destination_(visitor) { } basic_json_visitor2& destination() { return destination_; } private: void visit_flush() override { destination_.flush(); } bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code& ec) override { return destination_.begin_object(tag, context, ec); } bool visit_begin_object(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override { return destination_.begin_object(length, tag, context, ec); } bool visit_end_object(const ser_context& context, std::error_code& ec) override { return destination_.end_object(context, ec); } bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) override { return destination_.begin_array(tag, context, ec); } bool visit_begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override { return destination_.begin_array(length, tag, context, ec); } bool visit_end_array(const ser_context& context, std::error_code& ec) override { return destination_.end_array(context, ec); } bool visit_key(const string_view_type& name, const ser_context& context, std::error_code& ec) override { return destination_.visit_string(name, context, ec); } bool visit_string(const string_view_type& value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { return destination_.string_value(value, tag, context, ec); } bool visit_byte_string(const byte_string_view& b, semantic_tag tag, const ser_context& context, std::error_code& ec) override { return destination_.byte_string_value(b, tag, context, ec); } bool visit_uint64(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { return destination_.uint64_value(value, tag, context, ec); } bool visit_int64(int64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { return destination_.int64_value(value, tag, context, ec); } bool visit_half(uint16_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { return destination_.half_value(value, tag, context, ec); } bool visit_double(double value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { return destination_.double_value(value, tag, context, ec); } bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { return destination_.bool_value(value, tag, context, ec); } bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) override { return destination_.null_value(tag, context, ec); } }; class diagnostics_visitor2 : public basic_default_json_visitor2 { bool visit_begin_object(semantic_tag, const ser_context&, std::error_code&) override { std::cout << "visit_begin_object" << std::endl; return true; } bool visit_begin_object(std::size_t length, semantic_tag, const ser_context&, std::error_code&) override { std::cout << "visit_begin_object " << length << std::endl; return true; } bool visit_end_object(const ser_context&, std::error_code&) override { std::cout << "visit_end_object" << std::endl; return true; } bool visit_begin_array(semantic_tag, const ser_context&, std::error_code&) override { std::cout << "visit_begin_array" << std::endl; return true; } bool visit_begin_array(std::size_t length, semantic_tag, const ser_context&, std::error_code&) override { std::cout << "visit_begin_array " << length << std::endl; return true; } bool visit_end_array(const ser_context&, std::error_code&) override { std::cout << "visit_end_array" << std::endl; return true; } bool visit_string(const string_view_type& s, semantic_tag, const ser_context&, std::error_code&) override { std::cout << "visit_string " << s << std::endl; return true; } bool visit_int64(int64_t val, semantic_tag, const ser_context&, std::error_code&) override { std::cout << "visit_int64 " << val << std::endl; return true; } bool visit_uint64(uint64_t val, semantic_tag, const ser_context&, std::error_code&) override { std::cout << "visit_uint64 " << val << std::endl; return true; } bool visit_bool(bool val, semantic_tag, const ser_context&, std::error_code&) override { std::cout << "visit_bool " << val << std::endl; return true; } bool visit_null(semantic_tag, const ser_context&, std::error_code&) override { std::cout << "visit_null " << std::endl; return true; } bool visit_typed_array(const jsoncons::span& s, semantic_tag tag, const ser_context&, std::error_code&) override { std::cout << "visit_typed_array uint16_t " << tag << std::endl; for (auto val : s) { std::cout << val << "" << std::endl; } std::cout << "" << std::endl; return true; } bool visit_typed_array(half_arg_t, const jsoncons::span& s, semantic_tag tag, const ser_context&, std::error_code&) override { std::cout << "visit_typed_array half_arg_t uint16_t " << tag << "" << std::endl; for (auto val : s) { std::cout << val << "" << std::endl; } std::cout << "" << std::endl; return true; } }; using json_visitor2 = basic_json_visitor2; using default_json_visitor2 = basic_default_json_visitor2; using json_visitor2_to_visitor_adaptor = basic_json_visitor2_to_visitor_adaptor; } // namespace jsoncons #endif