// 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_STAJ_READER_HPP #define JSONCONS_STAJ_READER_HPP #include // std::allocator #include #include #include #include #include // std::enable_if #include // std::array #include #include #include #include #include #include #include namespace jsoncons { enum class staj_event_type { begin_array, end_array, begin_object, end_object, name, string_value, byte_string_value, null_value, bool_value, int64_value, uint64_value, double_value }; JSONCONS_STRING_LITERAL(null,'n','u','l','l') JSONCONS_STRING_LITERAL(true,'t','r','u','e') JSONCONS_STRING_LITERAL(false,'f','a','l','s','e') template class basic_staj_event { staj_event_type event_type_; semantic_tag semantic_tag_; union { bool bool_value_; int64_t int64_value_; uint64_t uint64_value_; double double_value_; const CharT* string_data_; const uint8_t* byte_string_data_; } value_; size_t length_; public: basic_staj_event(staj_event_type event_type, semantic_tag semantic_tag = semantic_tag::none) : event_type_(event_type), semantic_tag_(semantic_tag), length_(0) { } basic_staj_event(null_type) : event_type_(staj_event_type::null_value), semantic_tag_(semantic_tag::none), length_(0) { } basic_staj_event(bool value) : event_type_(staj_event_type::bool_value), semantic_tag_(semantic_tag::none), length_(0) { value_.bool_value_ = value; } basic_staj_event(int64_t value, semantic_tag semantic_tag) : event_type_(staj_event_type::int64_value), semantic_tag_(semantic_tag), length_(0) { value_.int64_value_ = value; } basic_staj_event(uint64_t value, semantic_tag semantic_tag) : event_type_(staj_event_type::uint64_value), semantic_tag_(semantic_tag), length_(0) { value_.uint64_value_ = value; } basic_staj_event(double value, semantic_tag semantic_tag) : event_type_(staj_event_type::double_value), semantic_tag_(semantic_tag), length_(0) { value_.double_value_ = value; } basic_staj_event(const CharT* data, size_t length, staj_event_type event_type, semantic_tag semantic_tag = semantic_tag::none) : event_type_(event_type), semantic_tag_(semantic_tag), length_(length) { value_.string_data_ = data; } template typename std::enable_if::value && std::is_same::value, T>::type as() const { T s; switch (event_type_) { case staj_event_type::name: case staj_event_type::string_value: s = T(value_.string_data_, length_); break; case staj_event_type::int64_value: { jsoncons::string_result result(s); jsoncons::detail::print_integer(value_.int64_value_, result); break; } case staj_event_type::uint64_value: { jsoncons::string_result result(s); jsoncons::detail::print_uinteger(value_.uint64_value_, result); break; } case staj_event_type::double_value: { jsoncons::string_result result(s); jsoncons::detail::print_double f{ floating_point_options() }; f(value_.double_value_, result); break; } case staj_event_type::bool_value: { jsoncons::string_result result(s); if (value_.bool_value_) { result.append(true_literal().data(),true_literal().size()); } else { result.append(false_literal().data(),false_literal().size()); } break; } case staj_event_type::null_value: { jsoncons::string_result result(s); result.append(null_literal().data(),null_literal().size()); break; } default: JSONCONS_THROW(json_runtime_error("Not a string")); } return s; } template typename std::enable_if::value && std::is_same::value, T>::type as() const { T s; switch (event_type_) { case staj_event_type::name: case staj_event_type::string_value: s = T(value_.string_data_, length_); break; default: JSONCONS_THROW(json_runtime_error("Not a string")); } return s; } template typename std::enable_if::value, T>::type as() const { return static_cast(as_int64()); } template typename std::enable_if::value, T>::type as() const { return static_cast(as_uint64()); } template typename std::enable_if::value, T>::type as() const { return static_cast(as_double()); } template> typename std::enable_if>::value, T>::type as() const { return as_bignum(); } template typename std::enable_if::value, T>::type as() const { return as_bool(); } staj_event_type event_type() const noexcept { return event_type_; } semantic_tag get_semantic_tag() const noexcept { return semantic_tag_; } private: int64_t as_int64() const { int64_t value = 0; switch (event_type_) { case staj_event_type::name: case staj_event_type::string_value: { auto result = jsoncons::detail::to_integer(value_.string_data_, length_); if (result.ec != jsoncons::detail::to_integer_errc()) { JSONCONS_THROW(json_runtime_error(make_error_code(result.ec).message())); } value = result.value; break; } case staj_event_type::double_value: value = static_cast(value_.double_value_); break; case staj_event_type::int64_value: value = value_.int64_value_; break; case staj_event_type::uint64_value: value = static_cast(value_.uint64_value_); break; case staj_event_type::bool_value: value = value_.bool_value_ ? 1 : 0; break; default: JSONCONS_THROW(json_runtime_error("Not an integer")); } return value; } uint64_t as_uint64() const { uint64_t value = 0; switch (event_type_) { case staj_event_type::name: case staj_event_type::string_value: { auto result = jsoncons::detail::to_integer(value_.string_data_, length_); if (result.ec != jsoncons::detail::to_integer_errc()) { JSONCONS_THROW(json_runtime_error(make_error_code(result.ec).message())); } value = result.value; break; } case staj_event_type::double_value: value = static_cast(value_.double_value_); break; case staj_event_type::int64_value: value = static_cast(value_.int64_value_); break; case staj_event_type::uint64_value: value = value_.uint64_value_; break; case staj_event_type::bool_value: value = value_.bool_value_ ? 1 : 0; break; default: JSONCONS_THROW(json_runtime_error("Not an unsigned integer")); } return value; } double as_double() const { switch (event_type_) { case staj_event_type::name: case staj_event_type::string_value: { std::string target; auto result = unicons::convert( value_.string_data_, value_.string_data_ + length_, std::back_inserter(target), unicons::conv_flags::strict); if (result.ec != unicons::conv_errc()) { JSONCONS_THROW(json_runtime_error("Not a double")); } jsoncons::detail::string_to_double f; return f(target.data(), target.length()); } case staj_event_type::double_value: return value_.double_value_; case staj_event_type::int64_value: return static_cast(value_.int64_value_); case staj_event_type::uint64_value: return static_cast(value_.uint64_value_); default: JSONCONS_THROW(json_runtime_error("Not a double")); } } bool as_bool() const { switch (event_type_) { case staj_event_type::bool_value: return value_.bool_value_; case staj_event_type::double_value: return value_.double_value_ != 0.0; case staj_event_type::int64_value: return value_.int64_value_ != 0; case staj_event_type::uint64_value: return value_.uint64_value_ != 0; default: JSONCONS_THROW(json_runtime_error("Not a bool")); } } template > basic_bignum as_bignum() const { switch (event_type_) { case staj_event_type::string_value: if (!jsoncons::detail::is_integer(value_.string_data_, length_)) { JSONCONS_THROW(json_runtime_error("Not a bignum")); } return basic_bignum(value_.string_data_, length_); case staj_event_type::double_value: return basic_bignum(value_.double_value_); case staj_event_type::int64_value: return basic_bignum(value_.int64_value_); case staj_event_type::uint64_value: return basic_bignum(value_.uint64_value_); case staj_event_type::bool_value: return basic_bignum(value_.bool_value_ ? 1 : 0); default: JSONCONS_THROW(json_runtime_error("Not a bignum")); } } }; template class basic_staj_reader { public: virtual ~basic_staj_reader() = default; virtual bool done() const = 0; virtual const basic_staj_event& current() const = 0; virtual void accept(basic_json_content_handler& handler) = 0; virtual void accept(basic_json_content_handler& handler, 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 basic_staj_filter { public: virtual ~basic_staj_filter() = default; virtual bool accept(const basic_staj_event& event, const ser_context& context) = 0; }; template class default_basic_staj_filter : public basic_staj_filter { public: bool accept(const basic_staj_event&, const ser_context&) override { return true; } }; typedef basic_staj_event staj_event; typedef basic_staj_event wstaj_event; typedef basic_staj_reader staj_reader; typedef basic_staj_reader wstaj_reader; typedef basic_staj_filter staj_filter; typedef basic_staj_filter wstaj_filter; #if !defined(JSONCONS_NO_DEPRECATED) typedef staj_event_type stream_event_type; template using basic_stream_event = basic_staj_event; template using basic_stream_reader = basic_staj_reader; template using basic_stream_filter = basic_staj_filter; typedef basic_staj_event stream_event; typedef basic_staj_event wstream_event; typedef basic_staj_reader stream_reader; typedef basic_staj_reader wstream_reader; typedef basic_staj_filter stream_filter; typedef basic_staj_filter wstream_filter; #endif } #endif