// 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_STAJ2_CURSOR_HPP #define JSONCONS_STAJ2_CURSOR_HPP #include <memory> // std::allocator #include <string> #include <stdexcept> #include <system_error> #include <ios> #include <type_traits> // std::enable_if #include <array> // std::array #include <functional> // std::function #include <jsoncons/json_exception.hpp> #include <jsoncons/json_visitor2.hpp> #include <jsoncons/bigint.hpp> #include <jsoncons/json_parser.hpp> #include <jsoncons/ser_context.hpp> #include <jsoncons/sink.hpp> #include <jsoncons/detail/write_number.hpp> #include <jsoncons/json_type_traits.hpp> #include <jsoncons/typed_array_view.hpp> #include <jsoncons/converter.hpp> namespace jsoncons { enum class staj2_event_type { begin_array, end_array, begin_object, end_object, string_value, byte_string_value, null_value, bool_value, int64_value, uint64_value, half_value, double_value }; template <class CharT> std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, staj2_event_type tag) { static constexpr const CharT* begin_array_name = JSONCONS_CSTRING_CONSTANT(CharT, "begin_array"); static constexpr const CharT* end_array_name = JSONCONS_CSTRING_CONSTANT(CharT, "end_array"); static constexpr const CharT* begin_object_name = JSONCONS_CSTRING_CONSTANT(CharT, "begin_object"); static constexpr const CharT* end_object_name = JSONCONS_CSTRING_CONSTANT(CharT, "end_object"); static constexpr const CharT* string_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "string_value"); static constexpr const CharT* byte_string_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "byte_string_value"); static constexpr const CharT* null_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "null_value"); static constexpr const CharT* bool_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "bool_value"); static constexpr const CharT* uint64_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "uint64_value"); static constexpr const CharT* int64_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "int64_value"); static constexpr const CharT* half_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "half_value"); static constexpr const CharT* double_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "double_value"); switch (tag) { case staj2_event_type::begin_array: { os << begin_array_name; break; } case staj2_event_type::end_array: { os << end_array_name; break; } case staj2_event_type::begin_object: { os << begin_object_name; break; } case staj2_event_type::end_object: { os << end_object_name; break; } case staj2_event_type::string_value: { os << string_value_name; break; } case staj2_event_type::byte_string_value: { os << byte_string_value_name; break; } case staj2_event_type::null_value: { os << null_value_name; break; } case staj2_event_type::bool_value: { os << bool_value_name; break; } case staj2_event_type::int64_value: { os << int64_value_name; break; } case staj2_event_type::uint64_value: { os << uint64_value_name; break; } case staj2_event_type::half_value: { os << half_value_name; break; } case staj2_event_type::double_value: { os << double_value_name; break; } } return os; } template<class CharT> class basic_staj2_event { staj2_event_type event_type_; semantic_tag tag_; uint64_t ext_tag_; union { bool bool_value_; int64_t int64_value_; uint64_t uint64_value_; uint16_t half_value_; double double_value_; const CharT* string_data_; const uint8_t* byte_string_data_; } value_; std::size_t length_; public: using string_view_type = jsoncons::basic_string_view<CharT>; basic_staj2_event(staj2_event_type event_type, semantic_tag tag = semantic_tag::none) : event_type_(event_type), tag_(tag), ext_tag_(0), value_(), length_(0) { } basic_staj2_event(staj2_event_type event_type, std::size_t length, semantic_tag tag = semantic_tag::none) : event_type_(event_type), tag_(tag), ext_tag_(0), value_(), length_(length) { } basic_staj2_event(null_type, semantic_tag tag) : event_type_(staj2_event_type::null_value), tag_(tag), ext_tag_(0), value_(), length_(0) { } basic_staj2_event(bool value, semantic_tag tag) : event_type_(staj2_event_type::bool_value), tag_(tag), ext_tag_(0), length_(0) { value_.bool_value_ = value; } basic_staj2_event(int64_t value, semantic_tag tag) : event_type_(staj2_event_type::int64_value), tag_(tag), ext_tag_(0), length_(0) { value_.int64_value_ = value; } basic_staj2_event(uint64_t value, semantic_tag tag) : event_type_(staj2_event_type::uint64_value), tag_(tag), ext_tag_(0), length_(0) { value_.uint64_value_ = value; } basic_staj2_event(half_arg_t, uint16_t value, semantic_tag tag) : event_type_(staj2_event_type::half_value), tag_(tag), ext_tag_(0), length_(0) { value_.half_value_ = value; } basic_staj2_event(double value, semantic_tag tag) : event_type_(staj2_event_type::double_value), tag_(tag), ext_tag_(0), length_(0) { value_.double_value_ = value; } basic_staj2_event(const string_view_type& s, staj2_event_type event_type, semantic_tag tag = semantic_tag::none) : event_type_(event_type), tag_(tag), ext_tag_(0), length_(s.length()) { value_.string_data_ = s.data(); } basic_staj2_event(const byte_string_view& s, staj2_event_type event_type, semantic_tag tag = semantic_tag::none) : event_type_(event_type), tag_(tag), ext_tag_(0), length_(s.size()) { value_.byte_string_data_ = s.data(); } basic_staj2_event(const byte_string_view& s, staj2_event_type event_type, uint64_t ext_tag) : event_type_(event_type), tag_(semantic_tag::ext), ext_tag_(ext_tag), length_(s.size()) { value_.byte_string_data_ = s.data(); } std::size_t size() const { return length_; } template <class T> T get() const { std::error_code ec; T val = get<T>(ec); if (ec) { JSONCONS_THROW(ser_error(ec)); } return val; } template<class T, class CharT_ = CharT> typename std::enable_if<type_traits::is_basic_string<T>::value && std::is_same<typename T::value_type, CharT_>::value, T>::type get(std::error_code& ec) const { converter<T> conv; switch (event_type_) { case staj2_event_type::string_value: return conv.from(jsoncons::basic_string_view<CharT>(value_.string_data_, length_), tag(), ec); case staj2_event_type::byte_string_value: { return conv.from(byte_string_view(value_.byte_string_data_,length_), tag(), ec); } case staj2_event_type::uint64_value: { return conv.from(value_.uint64_value_, tag(), ec); } case staj2_event_type::int64_value: { return conv.from(value_.int64_value_, tag(), ec); } case staj2_event_type::half_value: { return conv.from(half_arg, value_.half_value_, tag(), ec); } case staj2_event_type::double_value: { return conv.from(value_.double_value_, tag(), ec); } case staj2_event_type::bool_value: { return conv.from(value_.bool_value_,tag(),ec); } case staj2_event_type::null_value: { return conv.from(null_type(),tag(),ec); } default: { ec = conv_errc::not_string; return T{}; } } } template<class T, class CharT_ = CharT> typename std::enable_if<type_traits::is_basic_string_view<T>::value && std::is_same<typename T::value_type, CharT_>::value, T>::type get(std::error_code& ec) const { T s; switch (event_type_) { case staj2_event_type::string_value: s = T(value_.string_data_, length_); break; default: ec = conv_errc::not_string_view; break; } return s; } template<class T> typename std::enable_if<std::is_same<T, byte_string_view>::value, T>::type get(std::error_code& ec) const { T s; switch (event_type_) { case staj2_event_type::byte_string_value: s = T(value_.byte_string_data_, length_); break; default: ec = conv_errc::not_byte_string_view; break; } return s; } template<class T> typename std::enable_if<type_traits::is_list_like<T>::value && std::is_same<typename T::value_type,uint8_t>::value,T>::type get(std::error_code& ec) const { converter<T> conv; switch (event_type_) { case staj2_event_type::byte_string_value: return conv.from(byte_string_view(value_.byte_string_data_, length_), tag(), ec); case staj2_event_type::string_value: return conv.from(jsoncons::basic_string_view<CharT>(value_.string_data_, length_), tag(), ec); default: ec = conv_errc::not_byte_string; return T{}; } } template <class IntegerType> typename std::enable_if<type_traits::is_integer<IntegerType>::value, IntegerType>::type get(std::error_code& ec) const { switch (event_type_) { case staj2_event_type::string_value: { IntegerType val; auto result = jsoncons::detail::to_integer(value_.string_data_, length_, val); if (!result) { ec = conv_errc::not_integer; return IntegerType(); } return val; } case staj2_event_type::half_value: return static_cast<IntegerType>(value_.half_value_); case staj2_event_type::double_value: return static_cast<IntegerType>(value_.double_value_); case staj2_event_type::int64_value: return static_cast<IntegerType>(value_.int64_value_); case staj2_event_type::uint64_value: return static_cast<IntegerType>(value_.uint64_value_); case staj2_event_type::bool_value: return static_cast<IntegerType>(value_.bool_value_ ? 1 : 0); default: ec = conv_errc::not_integer; return IntegerType(); } } template<class T> typename std::enable_if<std::is_floating_point<T>::value, T>::type get(std::error_code& ec) const { return static_cast<T>(as_double(ec)); } template<class T> typename std::enable_if<type_traits::is_bool<T>::value, T>::type get(std::error_code& ec) const { return as_bool(ec); } staj2_event_type event_type() const noexcept { return event_type_; } semantic_tag tag() const noexcept { return tag_; } uint64_t ext_tag() const noexcept { return ext_tag_; } private: double as_double(std::error_code& ec) const { switch (event_type_) { case staj2_event_type::string_value: { jsoncons::detail::chars_to f; return f(value_.string_data_, length_); } case staj2_event_type::double_value: return value_.double_value_; case staj2_event_type::int64_value: return static_cast<double>(value_.int64_value_); case staj2_event_type::uint64_value: return static_cast<double>(value_.uint64_value_); case staj2_event_type::half_value: { double x = binary::decode_half(value_.half_value_); return static_cast<double>(x); } default: ec = conv_errc::not_double; return double(); } } bool as_bool(std::error_code& ec) const { switch (event_type_) { case staj2_event_type::bool_value: return value_.bool_value_; case staj2_event_type::double_value: return value_.double_value_ != 0.0; case staj2_event_type::int64_value: return value_.int64_value_ != 0; case staj2_event_type::uint64_value: return value_.uint64_value_ != 0; default: ec = conv_errc::not_bool; return bool(); } } }; // basic_staj2_visitor enum class staj2_cursor_state { typed_array = 1, multi_dim, shape }; template <class CharT> class basic_staj2_visitor : public basic_json_visitor2<CharT> { using super_type = basic_json_visitor2<CharT>; public: using char_type = CharT; using typename super_type::string_view_type; private: std::function<bool(const basic_staj2_event<CharT>&, const ser_context&)> pred_; basic_staj2_event<CharT> event_; staj2_cursor_state state_; typed_array_view data_; jsoncons::span<const size_t> shape_; std::size_t index_; public: basic_staj2_visitor() : pred_(accept), event_(staj2_event_type::null_value), state_(), data_(), shape_(), index_(0) { } basic_staj2_visitor(std::function<bool(const basic_staj2_event<CharT>&, const ser_context&)> pred) : pred_(pred), event_(staj2_event_type::null_value), state_(), data_(), shape_(), index_(0) { } void reset() { event_ = staj2_event_type::null_value; state_ = {}; data_ = {}; shape_ = {}; index_ = 0; } const basic_staj2_event<CharT>& event() const { return event_; } bool in_available() const { return state_ != staj2_cursor_state(); } void send_available(std::error_code& ec) { switch (state_) { case staj2_cursor_state::typed_array: advance_typed_array(ec); break; case staj2_cursor_state::multi_dim: case staj2_cursor_state::shape: advance_multi_dim(ec); break; default: break; } } bool is_typed_array() const { return data_.type() != typed_array_type(); } staj2_cursor_state state() const { return state_; } void advance_typed_array(std::error_code& ec) { if (is_typed_array()) { if (index_ < data_.size()) { switch (data_.type()) { case typed_array_type::uint8_value: { this->uint64_value(data_.data(uint8_array_arg)[index_], semantic_tag::none, ser_context(), ec); break; } case typed_array_type::uint16_value: { this->uint64_value(data_.data(uint16_array_arg)[index_], semantic_tag::none, ser_context(), ec); break; } case typed_array_type::uint32_value: { this->uint64_value(data_.data(uint32_array_arg)[index_], semantic_tag::none, ser_context(), ec); break; } case typed_array_type::uint64_value: { this->uint64_value(data_.data(uint64_array_arg)[index_], semantic_tag::none, ser_context(), ec); break; } case typed_array_type::int8_value: { this->int64_value(data_.data(int8_array_arg)[index_], semantic_tag::none, ser_context(), ec); break; } case typed_array_type::int16_value: { this->int64_value(data_.data(int16_array_arg)[index_], semantic_tag::none, ser_context(), ec); break; } case typed_array_type::int32_value: { this->int64_value(data_.data(int32_array_arg)[index_], semantic_tag::none, ser_context(), ec); break; } case typed_array_type::int64_value: { this->int64_value(data_.data(int64_array_arg)[index_], semantic_tag::none, ser_context(), ec); break; } case typed_array_type::half_value: { this->half_value(data_.data(half_array_arg)[index_], semantic_tag::none, ser_context(), ec); break; } case typed_array_type::float_value: { this->double_value(data_.data(float_array_arg)[index_], semantic_tag::none, ser_context(), ec); break; } case typed_array_type::double_value: { this->double_value(data_.data(double_array_arg)[index_], semantic_tag::none, ser_context(), ec); break; } default: break; } ++index_; } else { this->end_array(); state_ = staj2_cursor_state(); data_ = typed_array_view(); index_ = 0; } } } void advance_multi_dim(std::error_code& ec) { if (shape_.size() != 0) { if (state_ == staj2_cursor_state::multi_dim) { this->begin_array(shape_.size(), semantic_tag::none, ser_context(), ec); state_ = staj2_cursor_state::shape; } else if (index_ < shape_.size()) { this->uint64_value(shape_[index_], semantic_tag::none, ser_context(), ec); ++index_; } else { state_ = staj2_cursor_state(); this->end_array(ser_context(), ec); shape_ = jsoncons::span<const size_t>(); index_ = 0; } } } bool dump(basic_json_visitor2<CharT>& visitor, const ser_context& context, std::error_code& ec) { bool more = true; if (is_typed_array()) { if (index_ != 0) { more = staj2_to_saj_event(event(), visitor, context, ec); while (more && is_typed_array()) { if (index_ < data_.size()) { switch (data_.type()) { case typed_array_type::uint8_value: { more = visitor.uint64_value(data_.data(uint8_array_arg)[index_]); break; } case typed_array_type::uint16_value: { more = visitor.uint64_value(data_.data(uint16_array_arg)[index_]); break; } case typed_array_type::uint32_value: { more = visitor.uint64_value(data_.data(uint32_array_arg)[index_]); break; } case typed_array_type::uint64_value: { more = visitor.uint64_value(data_.data(uint64_array_arg)[index_]); break; } case typed_array_type::int8_value: { more = visitor.int64_value(data_.data(int8_array_arg)[index_]); break; } case typed_array_type::int16_value: { more = visitor.int64_value(data_.data(int16_array_arg)[index_]); break; } case typed_array_type::int32_value: { more = visitor.int64_value(data_.data(int32_array_arg)[index_]); break; } case typed_array_type::int64_value: { more = visitor.int64_value(data_.data(int64_array_arg)[index_]); break; } case typed_array_type::float_value: { more = visitor.double_value(data_.data(float_array_arg)[index_]); break; } case typed_array_type::double_value: { more = visitor.double_value(data_.data(double_array_arg)[index_]); break; } default: break; } ++index_; } else { more = visitor.end_array(); state_ = staj2_cursor_state(); data_ = typed_array_view(); index_ = 0; } } } else { switch (data_.type()) { case typed_array_type::uint8_value: { more = visitor.typed_array(data_.data(uint8_array_arg)); break; } case typed_array_type::uint16_value: { more = visitor.typed_array(data_.data(uint16_array_arg)); break; } case typed_array_type::uint32_value: { more = visitor.typed_array(data_.data(uint32_array_arg)); break; } case typed_array_type::uint64_value: { more = visitor.typed_array(data_.data(uint64_array_arg)); break; } case typed_array_type::int8_value: { more = visitor.typed_array(data_.data(int8_array_arg)); break; } case typed_array_type::int16_value: { more = visitor.typed_array(data_.data(int16_array_arg)); break; } case typed_array_type::int32_value: { more = visitor.typed_array(data_.data(int32_array_arg)); break; } case typed_array_type::int64_value: { more = visitor.typed_array(data_.data(int64_array_arg)); break; } case typed_array_type::float_value: { more = visitor.typed_array(data_.data(float_array_arg)); break; } case typed_array_type::double_value: { more = visitor.typed_array(data_.data(double_array_arg)); break; } default: break; } state_ = staj2_cursor_state(); data_ = typed_array_view(); } } else { more = staj2_to_saj_event(event(), visitor, context, ec); } return more; } private: static constexpr bool accept(const basic_staj2_event<CharT>&, const ser_context&) { return true; } bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(staj2_event_type::begin_object, tag); return !pred_(event_, context); } bool visit_begin_object(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(staj2_event_type::begin_object, length, tag); return !pred_(event_, context); } bool visit_end_object(const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(staj2_event_type::end_object); return !pred_(event_, context); } bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(staj2_event_type::begin_array, tag); return !pred_(event_, context); } bool visit_begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(staj2_event_type::begin_array, length, tag); return !pred_(event_, context); } bool visit_end_array(const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(staj2_event_type::end_array); return !pred_(event_, context); } bool visit_null(semantic_tag tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(staj2_event_type::null_value, tag); return !pred_(event_, context); } bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(value, tag); return !pred_(event_, context); } bool visit_string(const string_view_type& s, semantic_tag tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(s, staj2_event_type::string_value, tag); return !pred_(event_, context); } bool visit_byte_string(const byte_string_view& s, semantic_tag tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(s, staj2_event_type::byte_string_value, tag); return !pred_(event_, context); } bool visit_byte_string(const byte_string_view& s, uint64_t ext_tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(s, staj2_event_type::byte_string_value, ext_tag); return !pred_(event_, context); } bool visit_uint64(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(value, tag); return !pred_(event_, context); } bool visit_int64(int64_t value, semantic_tag tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(value, tag); return !pred_(event_, context); } bool visit_half(uint16_t value, semantic_tag tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(half_arg, value, tag); return !pred_(event_, context); } bool visit_double(double value, semantic_tag tag, const ser_context& context, std::error_code&) override { event_ = basic_staj2_event<CharT>(value, tag); return !pred_(event_, context); } bool visit_typed_array(const jsoncons::span<const uint8_t>& v, semantic_tag tag, const ser_context& context, std::error_code& ec) override { state_ = staj2_cursor_state::typed_array; data_ = typed_array_view(v.data(), v.size()); index_ = 0; return this->begin_array(tag, context, ec); } bool visit_typed_array(const jsoncons::span<const uint16_t>& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { state_ = staj2_cursor_state::typed_array; data_ = typed_array_view(data.data(), data.size()); index_ = 0; return this->begin_array(tag, context, ec); } bool visit_typed_array(const jsoncons::span<const uint32_t>& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { state_ = staj2_cursor_state::typed_array; data_ = typed_array_view(data.data(), data.size()); index_ = 0; return this->begin_array(tag, context, ec); } bool visit_typed_array(const jsoncons::span<const uint64_t>& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { state_ = staj2_cursor_state::typed_array; data_ = typed_array_view(data.data(), data.size()); index_ = 0; return this->begin_array(tag, context, ec); } bool visit_typed_array(const jsoncons::span<const int8_t>& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { state_ = staj2_cursor_state::typed_array; data_ = typed_array_view(data.data(), data.size()); index_ = 0; return this->begin_array(tag, context, ec); } bool visit_typed_array(const jsoncons::span<const int16_t>& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { state_ = staj2_cursor_state::typed_array; data_ = typed_array_view(data.data(), data.size()); index_ = 0; return this->begin_array(tag, context, ec); } bool visit_typed_array(const jsoncons::span<const int32_t>& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { state_ = staj2_cursor_state::typed_array; data_ = typed_array_view(data.data(), data.size()); index_ = 0; return this->begin_array(tag, context, ec); } bool visit_typed_array(const jsoncons::span<const int64_t>& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { state_ = staj2_cursor_state::typed_array; data_ = typed_array_view(data.data(), data.size()); index_ = 0; return this->begin_array(tag, context, ec); } bool visit_typed_array(half_arg_t, const jsoncons::span<const uint16_t>& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { state_ = staj2_cursor_state::typed_array; data_ = typed_array_view(data.data(), data.size()); index_ = 0; return this->begin_array(tag, context, ec); } bool visit_typed_array(const jsoncons::span<const float>& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { state_ = staj2_cursor_state::typed_array; data_ = typed_array_view(data.data(), data.size()); index_ = 0; return this->begin_array(tag, context, ec); } bool visit_typed_array(const jsoncons::span<const double>& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { state_ = staj2_cursor_state::typed_array; data_ = typed_array_view(data.data(), data.size()); index_ = 0; return this->begin_array(tag, context, ec); } /* bool visit_typed_array(const jsoncons::span<const float128_type>&, semantic_tag, const ser_context&, std::error_code&) override { return true; } */ bool visit_begin_multi_dim(const jsoncons::span<const size_t>& shape, semantic_tag tag, const ser_context& context, std::error_code& ec) override { state_ = staj2_cursor_state::multi_dim; shape_ = shape; return this->begin_array(2, tag, context, ec); } bool visit_end_multi_dim(const ser_context& context, std::error_code& ec) override { return this->end_array(context, ec); } void visit_flush() override { } }; template<class CharT> bool staj2_to_saj_event(const basic_staj2_event<CharT>& ev, basic_json_visitor2<CharT>& visitor, const ser_context& context, std::error_code& ec) { switch (ev.event_type()) { case staj2_event_type::begin_array: return visitor.begin_array(ev.tag(), context); case staj2_event_type::end_array: return visitor.end_array(context); case staj2_event_type::begin_object: return visitor.begin_object(ev.tag(), context, ec); case staj2_event_type::end_object: return visitor.end_object(context, ec); case staj2_event_type::string_value: return visitor.string_value(ev.template get<jsoncons::basic_string_view<CharT>>(), ev.tag(), context); case staj2_event_type::byte_string_value: return visitor.byte_string_value(ev.template get<byte_string_view>(), ev.tag(), context); case staj2_event_type::null_value: return visitor.null_value(ev.tag(), context); case staj2_event_type::bool_value: return visitor.bool_value(ev.template get<bool>(), ev.tag(), context); case staj2_event_type::int64_value: return visitor.int64_value(ev.template get<int64_t>(), ev.tag(), context); case staj2_event_type::uint64_value: return visitor.uint64_value(ev.template get<uint64_t>(), ev.tag(), context); case staj2_event_type::half_value: return visitor.half_value(ev.template get<uint16_t>(), ev.tag(), context); case staj2_event_type::double_value: return visitor.double_value(ev.template get<double>(), ev.tag(), context); default: return false; } } // basic_staj2_cursor template<class CharT> class basic_staj2_cursor { public: virtual ~basic_staj2_cursor() noexcept = default; virtual void array_expected(std::error_code& ec) { if (!(current().event_type() == staj2_event_type::begin_array || current().event_type() == staj2_event_type::byte_string_value)) { ec = conv_errc::not_vector; } } virtual bool done() const = 0; virtual const basic_staj2_event<CharT>& current() const = 0; virtual void read_to(basic_json_visitor2<CharT>& visitor) = 0; virtual void read_to(basic_json_visitor2<CharT>& visitor, std::error_code& ec) = 0; virtual void next() = 0; virtual void next(std::error_code& ec) = 0; virtual const ser_context& context() const = 0; }; template<class CharT> class basic_staj2_filter_view : basic_staj2_cursor<CharT> { basic_staj2_cursor<CharT>* cursor_; std::function<bool(const basic_staj2_event<CharT>&, const ser_context&)> pred_; public: basic_staj2_filter_view(basic_staj2_cursor<CharT>& cursor, std::function<bool(const basic_staj2_event<CharT>&, const ser_context&)> pred) : cursor_(std::addressof(cursor)), pred_(pred) { while (!done() && !pred_(current(),context())) { cursor_->next(); } } bool done() const override { return cursor_->done(); } const basic_staj2_event<CharT>& current() const override { return cursor_->current(); } void read_to(basic_json_visitor2<CharT>& visitor) override { cursor_->read_to(visitor); } void read_to(basic_json_visitor2<CharT>& visitor, std::error_code& ec) override { cursor_->read_to(visitor, ec); } void next() override { cursor_->next(); while (!done() && !pred_(current(),context())) { cursor_->next(); } } void next(std::error_code& ec) override { cursor_->next(ec); while (!done() && !pred_(current(),context()) && !ec) { cursor_->next(ec); } } const ser_context& context() const override { return cursor_->context(); } friend basic_staj2_filter_view<CharT> operator|(basic_staj2_filter_view& cursor, std::function<bool(const basic_staj2_event<CharT>&, const ser_context&)> pred) { return basic_staj2_filter_view<CharT>(cursor, pred); } }; using staj2_event = basic_staj2_event<char>; using wstaj2_event = basic_staj2_event<wchar_t>; using staj2_cursor = basic_staj2_cursor<char>; using wstaj2_cursor = basic_staj2_cursor<wchar_t>; using staj2_filter_view = basic_staj2_filter_view<char>; using wstaj2_filter_view = basic_staj2_filter_view<wchar_t>; } // namespace jsoncons #endif