// Copyright 2013 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_BASIC_JSON_HPP #define JSONCONS_BASIC_JSON_HPP #include // std::numeric_limits #include #include #include #include #include #include // std::allocator #include #include // std::memcpy #include // std::swap #include // std::initializer_list #include // std::move #include // std::enable_if #include // std::basic_istream #include #include #include #include #include #include #include #include #include #include #include #include #include namespace jsoncons { struct sorted_policy { static constexpr bool preserve_order = false; template using sequence_container_type = std::vector; template using key_storage = std::basic_string; template using string_storage = std::basic_string; typedef default_parse_error_handler parse_error_handler_type; }; struct preserve_order_policy : public sorted_policy { static constexpr bool preserve_order = true; }; template class range { IteratorT first_; IteratorT last_; public: range(const IteratorT& first, const IteratorT& last) : first_(first), last_(last) { } public: IteratorT begin() { return first_; } IteratorT end() { return last_; } }; enum class storage_type : uint8_t { null_val = 0x00, bool_val = 0x01, int64_val = 0x02, uint64_val = 0x03, double_val = 0x04, short_string_val = 0x05, long_string_val = 0x06, byte_string_val = 0x07, array_val = 0x08, empty_object_val = 0x09, object_val = 0x0a, tag_val = 0x0b }; template class basic_json { public: typedef Allocator allocator_type; typedef ImplementationPolicy implementation_policy; typedef typename ImplementationPolicy::parse_error_handler_type parse_error_handler_type; typedef CharT char_type; typedef typename std::char_traits char_traits_type; typedef basic_string_view string_view_type; typedef typename std::allocator_traits:: template rebind_alloc char_allocator_type; typedef std::basic_string string_type; typedef basic_json json_type; typedef json_type& reference; typedef const json_type& const_reference; typedef json_type* pointer; typedef const json_type* const_pointer; typedef key_value key_value_type; #if !defined(JSONCONS_NO_DEPRECATED) typedef json_type value_type; typedef string_type key_type; typedef key_value_type kvp_type; typedef key_value_type member_type; typedef jsoncons::null_type null_type; #endif typedef typename std::allocator_traits:: template rebind_alloc byte_allocator_type; using byte_string_storage_type = typename implementation_policy::template sequence_container_type; typedef json_array array; typedef typename std::allocator_traits:: template rebind_alloc key_value_allocator_type; typedef json_object object; typedef typename std::allocator_traits:: template rebind_alloc array_allocator; typedef typename std::allocator_traits:: template rebind_alloc object_allocator; typedef typename object::iterator object_iterator; typedef typename object::const_iterator const_object_iterator; typedef typename array::iterator array_iterator; typedef typename array::const_iterator const_array_iterator; struct variant { class data_base { static const uint8_t major_type_shift = 0x04; static const uint8_t additional_information_mask = (1U << 4) - 1; uint8_t type_; public: data_base(uint8_t type) : type_(type) {} data_base(storage_type data_type, semantic_tag semantic_type) : type_((static_cast(data_type) << major_type_shift) | static_cast(semantic_type)) {} uint8_t type() const { return type_; } storage_type get_storage_type() const { uint8_t value = type_ >> major_type_shift; return static_cast(value); } semantic_tag get_semantic_tag() const { uint8_t value = type_ & additional_information_mask; return static_cast(value); } }; class null_data final : public data_base { public: null_data() : data_base(storage_type::null_val, semantic_tag::none) { } null_data(semantic_tag tag) : data_base(storage_type::null_val, tag) { } }; class empty_object_data final : public data_base { public: empty_object_data(semantic_tag tag) : data_base(storage_type::empty_object_val, tag) { } }; class bool_data final : public data_base { bool val_; public: bool_data(bool val, semantic_tag tag) : data_base(storage_type::bool_val, tag),val_(val) { } bool_data(const bool_data& val) : data_base(val.type()),val_(val.val_) { } bool value() const { return val_; } }; class int64_data final : public data_base { int64_t val_; public: int64_data(int64_t val, semantic_tag tag = semantic_tag::none) : data_base(storage_type::int64_val, tag),val_(val) { } int64_data(const int64_data& val) : data_base(val.type()),val_(val.val_) { } int64_t value() const { return val_; } }; class uint64_data final : public data_base { uint64_t val_; public: uint64_data(uint64_t val, semantic_tag tag = semantic_tag::none) : data_base(storage_type::uint64_val, tag),val_(val) { } uint64_data(const uint64_data& val) : data_base(val.type()),val_(val.val_) { } uint64_t value() const { return val_; } }; class double_data final : public data_base { double val_; public: double_data(double val, semantic_tag tag = semantic_tag::none) : data_base(storage_type::double_val, tag), val_(val) { } double_data(const double_data& val) : data_base(val.type()), val_(val.val_) { } double value() const { return val_; } }; class short_string_data final : public data_base { static const size_t capacity = 14/sizeof(char_type); uint8_t length_; char_type data_[capacity]; public: static const size_t max_length = (14 / sizeof(char_type)) - 1; short_string_data(semantic_tag tag, const char_type* p, uint8_t length) : data_base(storage_type::short_string_val, tag), length_(length) { JSONCONS_ASSERT(length <= max_length); std::memcpy(data_,p,length*sizeof(char_type)); data_[length] = 0; } short_string_data(const short_string_data& val) : data_base(val.type()), length_(val.length_) { std::memcpy(data_,val.data_,val.length_*sizeof(char_type)); data_[length_] = 0; } uint8_t length() const { return length_; } const char_type* data() const { return data_; } const char_type* c_str() const { return data_; } }; // long_string_data class long_string_data final : public data_base { typedef typename jsoncons::detail::heap_only_string_factory::string_pointer pointer; pointer ptr_; public: long_string_data(semantic_tag tag, const char_type* data, size_t length, const Allocator& a) : data_base(storage_type::long_string_val, tag) { ptr_ = jsoncons::detail::heap_only_string_factory::create(data,length,a); } long_string_data(const long_string_data& val) : data_base(val.type()) { ptr_ = jsoncons::detail::heap_only_string_factory::create(val.data(),val.length(),val.get_allocator()); } long_string_data(long_string_data&& val) : data_base(val.type()), ptr_(nullptr) { std::swap(val.ptr_,ptr_); } long_string_data(const long_string_data& val, const Allocator& a) : data_base(val.type()) { ptr_ = jsoncons::detail::heap_only_string_factory::create(val.data(),val.length(),a); } ~long_string_data() { if (ptr_ != nullptr) { jsoncons::detail::heap_only_string_factory::destroy(ptr_); } } void swap(long_string_data& val) { std::swap(val.ptr_,ptr_); } const char_type* data() const { return ptr_->data(); } const char_type* c_str() const { return ptr_->c_str(); } size_t length() const { return ptr_->length(); } allocator_type get_allocator() const { return ptr_->get_allocator(); } }; // byte_string_data class byte_string_data final : public data_base { typedef typename std::allocator_traits:: template rebind_alloc string_holder_allocator_type; typedef typename std::allocator_traits::pointer pointer; pointer ptr_; template void create(string_holder_allocator_type allocator, Args&& ... args) { typename std::allocator_traits:: template rebind_alloc alloc(allocator); ptr_ = alloc.allocate(1); try { std::allocator_traits:: template rebind_traits::construct(alloc, jsoncons::detail::to_plain_pointer(ptr_), std::forward(args)...); } catch (...) { alloc.deallocate(ptr_,1); throw; } } public: byte_string_data(semantic_tag semantic_type, const uint8_t* data, size_t length, const Allocator& a) : data_base(storage_type::byte_string_val, semantic_type) { create(string_holder_allocator_type(a), data, data+length, a); } byte_string_data(const byte_string_data& val) : data_base(val.type()) { create(val.ptr_->get_allocator(), *(val.ptr_)); } byte_string_data(byte_string_data&& val) : data_base(val.type()), ptr_(nullptr) { std::swap(val.ptr_,ptr_); } byte_string_data(const byte_string_data& val, const Allocator& a) : data_base(val.type()) { create(string_holder_allocator_type(a), *(val.ptr_), a); } ~byte_string_data() { if (ptr_ != nullptr) { typename std::allocator_traits:: template rebind_alloc alloc(ptr_->get_allocator()); std::allocator_traits:: template rebind_traits::destroy(alloc, jsoncons::detail::to_plain_pointer(ptr_)); alloc.deallocate(ptr_,1); } } void swap(byte_string_data& val) { std::swap(val.ptr_,ptr_); } const uint8_t* data() const { return ptr_->data(); } size_t length() const { return ptr_->size(); } const uint8_t* begin() const { return ptr_->data(); } const uint8_t* end() const { return ptr_->data() + ptr_->size(); } allocator_type get_allocator() const { return ptr_->get_allocator(); } }; // array_data class array_data final : public data_base { typedef typename std::allocator_traits::pointer pointer; pointer ptr_; template void create(array_allocator allocator, Args&& ... args) { typename std::allocator_traits:: template rebind_alloc alloc(allocator); ptr_ = alloc.allocate(1); try { std::allocator_traits:: template rebind_traits::construct(alloc, jsoncons::detail::to_plain_pointer(ptr_), std::forward(args)...); } catch (...) { alloc.deallocate(ptr_,1); throw; } } public: array_data(const array& val, semantic_tag tag) : data_base(storage_type::array_val, tag) { create(val.get_allocator(), val); } array_data(const array& val, semantic_tag tag, const Allocator& a) : data_base(storage_type::array_val, tag) { create(array_allocator(a), val, a); } array_data(const array_data& val) : data_base(val.type()) { create(val.ptr_->get_allocator(), *(val.ptr_)); } array_data(array_data&& val) : data_base(val.type()), ptr_(nullptr) { std::swap(val.ptr_, ptr_); } array_data(const array_data& val, const Allocator& a) : data_base(val.type()) { create(array_allocator(a), *(val.ptr_), a); } ~array_data() { if (ptr_ != nullptr) { typename std::allocator_traits:: template rebind_alloc alloc(ptr_->get_allocator()); std::allocator_traits:: template rebind_traits::destroy(alloc, jsoncons::detail::to_plain_pointer(ptr_)); alloc.deallocate(ptr_,1); } } allocator_type get_allocator() const { return ptr_->get_allocator(); } void swap(array_data& val) { std::swap(val.ptr_,ptr_); } array& value() { return *ptr_; } const array& value() const { return *ptr_; } }; // object_data class object_data final : public data_base { typedef typename std::allocator_traits::pointer pointer; pointer ptr_; template void create(Allocator allocator, Args&& ... args) { typename std::allocator_traits:: template rebind_alloc alloc(allocator); ptr_ = alloc.allocate(1); try { std::allocator_traits:: template rebind_traits::construct(alloc, jsoncons::detail::to_plain_pointer(ptr_), std::forward(args)...); } catch (...) { alloc.deallocate(ptr_,1); throw; } } public: explicit object_data(const object& val, semantic_tag tag) : data_base(storage_type::object_val, tag) { create(val.get_allocator(), val); } explicit object_data(const object& val, semantic_tag tag, const Allocator& a) : data_base(storage_type::object_val, tag) { create(object_allocator(a), val, a); } explicit object_data(const object_data& val) : data_base(val.type()) { create(val.ptr_->get_allocator(), *(val.ptr_)); } explicit object_data(object_data&& val) : data_base(val.type()), ptr_(nullptr) { std::swap(val.ptr_,ptr_); } explicit object_data(const object_data& val, const Allocator& a) : data_base(val.type()) { create(object_allocator(a), *(val.ptr_), a); } ~object_data() { if (ptr_ != nullptr) { typename std::allocator_traits:: template rebind_alloc alloc(ptr_->get_allocator()); std::allocator_traits:: template rebind_traits::destroy(alloc, jsoncons::detail::to_plain_pointer(ptr_)); alloc.deallocate(ptr_,1); } } void swap(object_data& val) { std::swap(val.ptr_,ptr_); } object& value() { return *ptr_; } const object& value() const { return *ptr_; } allocator_type get_allocator() const { return ptr_->get_allocator(); } }; private: static const size_t data_size = static_max::value; static const size_t data_align = static_max::value; typedef typename std::aligned_storage::type data_t; data_t data_; public: variant(semantic_tag tag) { new(reinterpret_cast(&data_))empty_object_data(tag); } explicit variant(null_type, semantic_tag tag) { new(reinterpret_cast(&data_))null_data(tag); } explicit variant(bool val, semantic_tag tag) { new(reinterpret_cast(&data_))bool_data(val,tag); } explicit variant(int64_t val, semantic_tag tag) { new(reinterpret_cast(&data_))int64_data(val, tag); } explicit variant(uint64_t val, semantic_tag tag) { new(reinterpret_cast(&data_))uint64_data(val, tag); } variant(double val, semantic_tag tag) { new(reinterpret_cast(&data_))double_data(val, tag); } variant(const char_type* s, size_t length, semantic_tag tag) { if (length <= short_string_data::max_length) { new(reinterpret_cast(&data_))short_string_data(tag, s, static_cast(length)); } else { new(reinterpret_cast(&data_))long_string_data(tag, s, length, char_allocator_type()); } } variant(const char_type* s, size_t length, semantic_tag tag, const Allocator& alloc) { if (length <= short_string_data::max_length) { new(reinterpret_cast(&data_))short_string_data(tag, s, static_cast(length)); } else { new(reinterpret_cast(&data_))long_string_data(tag, s, length, char_allocator_type(alloc)); } } variant(const byte_string_view& bs, semantic_tag tag) { new(reinterpret_cast(&data_))byte_string_data(tag, bs.data(), bs.length(), byte_allocator_type()); } variant(const byte_string_view& bs, semantic_tag tag, const Allocator& allocator) { new(reinterpret_cast(&data_))byte_string_data(tag, bs.data(), bs.length(), allocator); } variant(const basic_bignum& n) { std::basic_string s; n.dump(s); if (s.length() <= short_string_data::max_length) { new(reinterpret_cast(&data_))short_string_data(semantic_tag::bigint, s.data(), static_cast(s.length())); } else { new(reinterpret_cast(&data_))long_string_data(semantic_tag::bigint, s.data(), s.length(), char_allocator_type()); } } variant(const basic_bignum& n, const Allocator& allocator) { std::basic_string s; n.dump(s); if (s.length() <= short_string_data::max_length) { new(reinterpret_cast(&data_))short_string_data(semantic_tag::bigint, s.data(), static_cast(s.length())); } else { new(reinterpret_cast(&data_))long_string_data(semantic_tag::bigint, s.data(), s.length(), char_allocator_type(allocator)); } } variant(const object& val, semantic_tag tag) { new(reinterpret_cast(&data_))object_data(val, tag); } variant(const object& val, semantic_tag tag, const Allocator& alloc) { new(reinterpret_cast(&data_))object_data(val, tag, alloc); } variant(const array& val, semantic_tag tag) { new(reinterpret_cast(&data_))array_data(val, tag); } variant(const array& val, semantic_tag tag, const Allocator& alloc) { new(reinterpret_cast(&data_))array_data(val, tag, alloc); } variant(const variant& val) { Init_(val); } variant(const variant& val, const Allocator& allocator) { Init_(val,allocator); } variant(variant&& val) noexcept { Init_rv_(std::forward(val)); } variant(variant&& val, const Allocator& allocator) noexcept { Init_rv_(std::forward(val), allocator, typename std::allocator_traits::propagate_on_container_move_assignment()); } ~variant() { Destroy_(); } void Destroy_() { switch (get_storage_type()) { case storage_type::long_string_val: reinterpret_cast(&data_)->~long_string_data(); break; case storage_type::byte_string_val: reinterpret_cast(&data_)->~byte_string_data(); break; case storage_type::array_val: reinterpret_cast(&data_)->~array_data(); break; case storage_type::object_val: reinterpret_cast(&data_)->~object_data(); break; default: break; } } variant& operator=(const variant& val) { if (this !=&val) { Destroy_(); switch (val.get_storage_type()) { case storage_type::null_val: new(reinterpret_cast(&data_))null_data(*(val.null_data_cast())); break; case storage_type::empty_object_val: new(reinterpret_cast(&data_))empty_object_data(*(val.empty_object_data_cast())); break; case storage_type::bool_val: new(reinterpret_cast(&data_))bool_data(*(val.bool_data_cast())); break; case storage_type::int64_val: new(reinterpret_cast(&data_))int64_data(*(val.int64_data_cast())); break; case storage_type::uint64_val: new(reinterpret_cast(&data_))uint64_data(*(val.uint64_data_cast())); break; case storage_type::double_val: new(reinterpret_cast(&data_))double_data(*(val.double_data_cast())); break; case storage_type::short_string_val: new(reinterpret_cast(&data_))short_string_data(*(val.short_string_data_cast())); break; case storage_type::long_string_val: new(reinterpret_cast(&data_))long_string_data(*(val.string_data_cast())); break; case storage_type::byte_string_val: new(reinterpret_cast(&data_))byte_string_data(*(val.byte_string_data_cast())); break; case storage_type::array_val: new(reinterpret_cast(&data_))array_data(*(val.array_data_cast())); break; case storage_type::object_val: new(reinterpret_cast(&data_))object_data(*(val.object_data_cast())); break; default: JSONCONS_UNREACHABLE(); break; } } return *this; } variant& operator=(variant&& val) noexcept { if (this !=&val) { swap(val); } return *this; } storage_type get_storage_type() const { return reinterpret_cast(&data_)->get_storage_type(); } semantic_tag get_semantic_tag() const { return reinterpret_cast(&data_)->get_semantic_tag(); } const null_data* null_data_cast() const { return reinterpret_cast(&data_); } const empty_object_data* empty_object_data_cast() const { return reinterpret_cast(&data_); } const bool_data* bool_data_cast() const { return reinterpret_cast(&data_); } const int64_data* int64_data_cast() const { return reinterpret_cast(&data_); } const uint64_data* uint64_data_cast() const { return reinterpret_cast(&data_); } const double_data* double_data_cast() const { return reinterpret_cast(&data_); } const short_string_data* short_string_data_cast() const { return reinterpret_cast(&data_); } long_string_data* string_data_cast() { return reinterpret_cast(&data_); } const long_string_data* string_data_cast() const { return reinterpret_cast(&data_); } byte_string_data* byte_string_data_cast() { return reinterpret_cast(&data_); } const byte_string_data* byte_string_data_cast() const { return reinterpret_cast(&data_); } object_data* object_data_cast() { return reinterpret_cast(&data_); } const object_data* object_data_cast() const { return reinterpret_cast(&data_); } array_data* array_data_cast() { return reinterpret_cast(&data_); } const array_data* array_data_cast() const { return reinterpret_cast(&data_); } size_t size() const { switch (get_storage_type()) { case storage_type::array_val: return array_data_cast()->value().size(); case storage_type::object_val: return object_data_cast()->value().size(); default: return 0; } } string_view_type as_string_view() const { switch (get_storage_type()) { case storage_type::short_string_val: return string_view_type(short_string_data_cast()->data(),short_string_data_cast()->length()); case storage_type::long_string_val: return string_view_type(string_data_cast()->data(),string_data_cast()->length()); default: JSONCONS_THROW(json_runtime_error("Not a string")); } } template > basic_byte_string as_byte_string() const { switch (get_storage_type()) { case storage_type::short_string_val: case storage_type::long_string_val: { switch (get_semantic_tag()) { case semantic_tag::base16: { basic_byte_string bs; auto s = as_string_view(); decode_base16(s.begin(), s.end(), bs); return bs; } case semantic_tag::base64: { basic_byte_string bs; auto s = as_string_view(); decode_base64(s.begin(), s.end(), bs); return bs; } case semantic_tag::base64url: { basic_byte_string bs; auto s = as_string_view(); decode_base64url(s.begin(), s.end(), bs); return bs; } default: JSONCONS_THROW(json_runtime_error("Not a byte string")); } break; } case storage_type::byte_string_val: return basic_byte_string(byte_string_data_cast()->data(),byte_string_data_cast()->length()); default: JSONCONS_THROW(json_runtime_error("Not a byte string")); } } byte_string_view as_byte_string_view() const { switch (get_storage_type()) { case storage_type::byte_string_val: return byte_string_view(byte_string_data_cast()->data(),byte_string_data_cast()->length()); default: JSONCONS_THROW(json_runtime_error("Not a byte string")); } } template > basic_bignum as_bignum() const { switch (get_storage_type()) { case storage_type::short_string_val: case storage_type::long_string_val: if (!jsoncons::detail::is_integer(as_string_view().data(), as_string_view().length())) { JSONCONS_THROW(json_runtime_error("Not an integer")); } return basic_bignum(as_string_view().data(), as_string_view().length()); case storage_type::double_val: return basic_bignum(double_data_cast()->value()); case storage_type::int64_val: return basic_bignum(int64_data_cast()->value()); case storage_type::uint64_val: return basic_bignum(uint64_data_cast()->value()); case storage_type::bool_val: return basic_bignum(bool_data_cast()->value() ? 1 : 0); default: JSONCONS_THROW(json_runtime_error("Not a bignum")); } } bool operator==(const variant& rhs) const { if (this ==&rhs) { return true; } switch (get_storage_type()) { case storage_type::null_val: switch (rhs.get_storage_type()) { case storage_type::null_val: return true; default: return false; } break; case storage_type::empty_object_val: switch (rhs.get_storage_type()) { case storage_type::empty_object_val: return true; case storage_type::object_val: return rhs.size() == 0; default: return false; } break; case storage_type::bool_val: switch (rhs.get_storage_type()) { case storage_type::bool_val: return bool_data_cast()->value() == rhs.bool_data_cast()->value(); default: return false; } break; case storage_type::int64_val: switch (rhs.get_storage_type()) { case storage_type::int64_val: return int64_data_cast()->value() == rhs.int64_data_cast()->value(); case storage_type::uint64_val: return int64_data_cast()->value() >= 0 ? static_cast(int64_data_cast()->value()) == rhs.uint64_data_cast()->value() : false; case storage_type::double_val: return static_cast(int64_data_cast()->value()) == rhs.double_data_cast()->value(); default: return false; } break; case storage_type::uint64_val: switch (rhs.get_storage_type()) { case storage_type::int64_val: return rhs.int64_data_cast()->value() >= 0 ? uint64_data_cast()->value() == static_cast(rhs.int64_data_cast()->value()) : false; case storage_type::uint64_val: return uint64_data_cast()->value() == rhs.uint64_data_cast()->value(); case storage_type::double_val: return static_cast(uint64_data_cast()->value()) == rhs.double_data_cast()->value(); default: return false; } break; case storage_type::double_val: switch (rhs.get_storage_type()) { case storage_type::int64_val: return double_data_cast()->value() == static_cast(rhs.int64_data_cast()->value()); case storage_type::uint64_val: return double_data_cast()->value() == static_cast(rhs.uint64_data_cast()->value()); case storage_type::double_val: return double_data_cast()->value() == rhs.double_data_cast()->value(); default: return false; } break; case storage_type::short_string_val: switch (rhs.get_storage_type()) { case storage_type::short_string_val: return as_string_view() == rhs.as_string_view(); case storage_type::long_string_val: return as_string_view() == rhs.as_string_view(); default: return false; } break; case storage_type::long_string_val: switch (rhs.get_storage_type()) { case storage_type::short_string_val: return as_string_view() == rhs.as_string_view(); case storage_type::long_string_val: return as_string_view() == rhs.as_string_view(); default: return false; } break; case storage_type::byte_string_val: switch (rhs.get_storage_type()) { case storage_type::byte_string_val: { return as_byte_string_view() == rhs.as_byte_string_view(); } default: return false; } break; case storage_type::array_val: switch (rhs.get_storage_type()) { case storage_type::array_val: return array_data_cast()->value() == rhs.array_data_cast()->value(); default: return false; } break; case storage_type::object_val: switch (rhs.get_storage_type()) { case storage_type::empty_object_val: return size() == 0; case storage_type::object_val: return object_data_cast()->value() == rhs.object_data_cast()->value(); default: return false; } break; default: JSONCONS_UNREACHABLE(); break; } } bool operator!=(const variant& rhs) const { return !(*this == rhs); } bool operator<(const variant& rhs) const { if (this == &rhs) { return false; } switch (get_storage_type()) { case storage_type::null_val: return (int)get_storage_type() < (int)rhs.get_storage_type(); case storage_type::empty_object_val: switch (rhs.get_storage_type()) { case storage_type::empty_object_val: return false; case storage_type::object_val: return rhs.size() != 0; default: return (int)get_storage_type() < (int)rhs.get_storage_type(); } break; case storage_type::bool_val: switch (rhs.get_storage_type()) { case storage_type::bool_val: return bool_data_cast()->value() < rhs.bool_data_cast()->value(); default: return (int)get_storage_type() < (int)rhs.get_storage_type(); } break; case storage_type::int64_val: switch (rhs.get_storage_type()) { case storage_type::int64_val: return int64_data_cast()->value() < rhs.int64_data_cast()->value(); case storage_type::uint64_val: return int64_data_cast()->value() >= 0 ? static_cast(int64_data_cast()->value()) < rhs.uint64_data_cast()->value() : true; case storage_type::double_val: return static_cast(int64_data_cast()->value()) < rhs.double_data_cast()->value(); default: return (int)get_storage_type() < (int)rhs.get_storage_type(); } break; case storage_type::uint64_val: switch (rhs.get_storage_type()) { case storage_type::int64_val: return rhs.int64_data_cast()->value() >= 0 ? uint64_data_cast()->value() < static_cast(rhs.int64_data_cast()->value()) : true; case storage_type::uint64_val: return uint64_data_cast()->value() < rhs.uint64_data_cast()->value(); case storage_type::double_val: return static_cast(uint64_data_cast()->value()) < rhs.double_data_cast()->value(); default: return (int)get_storage_type() < (int)rhs.get_storage_type(); } break; case storage_type::double_val: switch (rhs.get_storage_type()) { case storage_type::int64_val: return double_data_cast()->value() < static_cast(rhs.int64_data_cast()->value()); case storage_type::uint64_val: return double_data_cast()->value() < static_cast(rhs.uint64_data_cast()->value()); case storage_type::double_val: return double_data_cast()->value() < rhs.double_data_cast()->value(); default: return (int)get_storage_type() < (int)rhs.get_storage_type(); } break; case storage_type::short_string_val: switch (rhs.get_storage_type()) { case storage_type::short_string_val: return as_string_view() < rhs.as_string_view(); case storage_type::long_string_val: return as_string_view() < rhs.as_string_view(); default: return (int)get_storage_type() < (int)rhs.get_storage_type(); } break; case storage_type::long_string_val: switch (rhs.get_storage_type()) { case storage_type::short_string_val: return as_string_view() < rhs.as_string_view(); case storage_type::long_string_val: return as_string_view() < rhs.as_string_view(); default: return (int)get_storage_type() < (int)rhs.get_storage_type(); } break; case storage_type::byte_string_val: switch (rhs.get_storage_type()) { case storage_type::byte_string_val: { return as_byte_string_view() < rhs.as_byte_string_view(); } default: return (int)get_storage_type() < (int)rhs.get_storage_type(); } break; case storage_type::array_val: switch (rhs.get_storage_type()) { case storage_type::array_val: return array_data_cast()->value() < rhs.array_data_cast()->value(); default: return (int)get_storage_type() < (int)rhs.get_storage_type(); } break; case storage_type::object_val: switch (rhs.get_storage_type()) { case storage_type::empty_object_val: return false; case storage_type::object_val: return object_data_cast()->value() < rhs.object_data_cast()->value(); default: return (int)get_storage_type() < (int)rhs.get_storage_type(); } break; default: JSONCONS_UNREACHABLE(); break; } } template typename std::enable_if::pointer>::value,void>::type swap(variant& other) noexcept { if (this ==&other) { return; } std::swap(data_,other.data_); } template typename std::enable_if::pointer>::value, void>::type swap(variant& other) noexcept { if (this ==&other) { return; } variant temp(other); switch (get_storage_type()) { case storage_type::null_val: new(reinterpret_cast(&(other.data_)))null_data(*null_data_cast()); break; case storage_type::empty_object_val: new(reinterpret_cast(&(other.data_)))empty_object_data(*empty_object_data_cast()); break; case storage_type::bool_val: new(reinterpret_cast(&(other.data_)))bool_data(*bool_data_cast()); break; case storage_type::int64_val: new(reinterpret_cast(&(other.data_)))int64_data(*int64_data_cast()); break; case storage_type::uint64_val: new(reinterpret_cast(&(other.data_)))uint64_data(*uint64_data_cast()); break; case storage_type::double_val: new(reinterpret_cast(&(other.data_)))double_data(*double_data_cast()); break; case storage_type::short_string_val: new(reinterpret_cast(&(other.data_)))short_string_data(*short_string_data_cast()); break; case storage_type::long_string_val: new(reinterpret_cast(&other.data_))long_string_data(std::move(*string_data_cast())); break; case storage_type::byte_string_val: new(reinterpret_cast(&other.data_))byte_string_data(std::move(*byte_string_data_cast())); break; case storage_type::array_val: new(reinterpret_cast(&(other.data_)))array_data(std::move(*array_data_cast())); break; case storage_type::object_val: new(reinterpret_cast(&(other.data_)))object_data(std::move(*object_data_cast())); break; default: JSONCONS_UNREACHABLE(); break; } switch (temp.get_storage_type()) { case storage_type::long_string_val: new(reinterpret_cast(&data_))long_string_data(std::move(*temp.string_data_cast())); break; case storage_type::byte_string_val: new(reinterpret_cast(&data_))byte_string_data(std::move(*temp.byte_string_data_cast())); break; case storage_type::array_val: new(reinterpret_cast(&(data_)))array_data(std::move(*temp.array_data_cast())); break; case storage_type::object_val: new(reinterpret_cast(&(data_)))object_data(std::move(*temp.object_data_cast())); break; default: std::swap(data_,temp.data_); break; } } private: void Init_(const variant& val) { switch (val.get_storage_type()) { case storage_type::null_val: new(reinterpret_cast(&data_))null_data(*(val.null_data_cast())); break; case storage_type::empty_object_val: new(reinterpret_cast(&data_))empty_object_data(*(val.empty_object_data_cast())); break; case storage_type::bool_val: new(reinterpret_cast(&data_))bool_data(*(val.bool_data_cast())); break; case storage_type::int64_val: new(reinterpret_cast(&data_))int64_data(*(val.int64_data_cast())); break; case storage_type::uint64_val: new(reinterpret_cast(&data_))uint64_data(*(val.uint64_data_cast())); break; case storage_type::double_val: new(reinterpret_cast(&data_))double_data(*(val.double_data_cast())); break; case storage_type::short_string_val: new(reinterpret_cast(&data_))short_string_data(*(val.short_string_data_cast())); break; case storage_type::long_string_val: new(reinterpret_cast(&data_))long_string_data(*(val.string_data_cast())); break; case storage_type::byte_string_val: new(reinterpret_cast(&data_))byte_string_data(*(val.byte_string_data_cast())); break; case storage_type::object_val: new(reinterpret_cast(&data_))object_data(*(val.object_data_cast())); break; case storage_type::array_val: new(reinterpret_cast(&data_))array_data(*(val.array_data_cast())); break; default: break; } } void Init_(const variant& val, const Allocator& a) { switch (val.get_storage_type()) { case storage_type::null_val: case storage_type::empty_object_val: case storage_type::bool_val: case storage_type::int64_val: case storage_type::uint64_val: case storage_type::double_val: case storage_type::short_string_val: Init_(val); break; case storage_type::long_string_val: new(reinterpret_cast(&data_))long_string_data(*(val.string_data_cast()),a); break; case storage_type::byte_string_val: new(reinterpret_cast(&data_))byte_string_data(*(val.byte_string_data_cast()),a); break; case storage_type::array_val: new(reinterpret_cast(&data_))array_data(*(val.array_data_cast()),a); break; case storage_type::object_val: new(reinterpret_cast(&data_))object_data(*(val.object_data_cast()),a); break; default: break; } } void Init_rv_(variant&& val) noexcept { switch (val.get_storage_type()) { case storage_type::null_val: case storage_type::empty_object_val: case storage_type::double_val: case storage_type::int64_val: case storage_type::uint64_val: case storage_type::bool_val: case storage_type::short_string_val: Init_(val); break; case storage_type::long_string_val: { new(reinterpret_cast(&data_))long_string_data(std::move(*val.string_data_cast())); new(reinterpret_cast(&val.data_))null_data(); } break; case storage_type::byte_string_val: { new(reinterpret_cast(&data_))byte_string_data(std::move(*val.byte_string_data_cast())); new(reinterpret_cast(&val.data_))null_data(); } break; case storage_type::array_val: { new(reinterpret_cast(&data_))array_data(std::move(*val.array_data_cast())); new(reinterpret_cast(&val.data_))null_data(); } break; case storage_type::object_val: { new(reinterpret_cast(&data_))object_data(std::move(*val.object_data_cast())); new(reinterpret_cast(&val.data_))null_data(); } break; default: JSONCONS_UNREACHABLE(); break; } } void Init_rv_(variant&& val, const Allocator&, std::true_type) noexcept { Init_rv_(std::forward(val)); } void Init_rv_(variant&& val, const Allocator& a, std::false_type) noexcept { switch (val.get_storage_type()) { case storage_type::null_val: case storage_type::empty_object_val: case storage_type::double_val: case storage_type::int64_val: case storage_type::uint64_val: case storage_type::bool_val: case storage_type::short_string_val: Init_(std::forward(val)); break; case storage_type::long_string_val: { if (a == val.string_data_cast()->get_allocator()) { Init_rv_(std::forward(val), a, std::true_type()); } else { Init_(val,a); } } break; case storage_type::byte_string_val: { if (a == val.byte_string_data_cast()->get_allocator()) { Init_rv_(std::forward(val), a, std::true_type()); } else { Init_(val,a); } } break; case storage_type::object_val: { if (a == val.object_data_cast()->get_allocator()) { Init_rv_(std::forward(val), a, std::true_type()); } else { Init_(val,a); } } break; case storage_type::array_val: { if (a == val.array_data_cast()->get_allocator()) { Init_rv_(std::forward(val), a, std::true_type()); } else { Init_(val,a); } } break; default: break; } } }; template class json_proxy { private: ParentT& parent_; const char_type* data_; size_t length_; json_proxy() = delete; json_proxy& operator = (const json_proxy& other) = delete; json_proxy(ParentT& parent, const char_type* data, size_t length) : parent_(parent), data_(data), length_(length) { } basic_json& evaluate() { return parent_.evaluate(string_view_type(data_,length_)); } const basic_json& evaluate() const { return parent_.evaluate(string_view_type(data_,length_)); } basic_json& evaluate_with_default() { basic_json& val = parent_.evaluate_with_default(); auto it = val.find(string_view_type(data_,length_)); if (it == val.object_range().end()) { it = val.insert_or_assign(val.object_range().begin(),string_view_type(data_,length_),object(val.object_value().get_allocator())); } return it->value(); } basic_json& evaluate(size_t index) { return evaluate().at(index); } const basic_json& evaluate(size_t index) const { return evaluate().at(index); } basic_json& evaluate(const string_view_type& index) { return evaluate().at(index); } const basic_json& evaluate(const string_view_type& index) const { return evaluate().at(index); } public: friend class basic_json; typedef json_proxy proxy_type; range object_range() { return evaluate().object_range(); } range object_range() const { return evaluate().object_range(); } range array_range() { return evaluate().array_range(); } range array_range() const { return evaluate().array_range(); } size_t size() const noexcept { return evaluate().size(); } storage_type get_storage_type() const { return evaluate().get_storage_type(); } semantic_tag get_semantic_tag() const { return evaluate().get_semantic_tag(); } size_t count(const string_view_type& name) const { return evaluate().count(name); } allocator_type get_allocator() const { return evaluate().get_allocator(); } bool contains(const string_view_type& name) const { return evaluate().contains(name); } bool is_null() const noexcept { return evaluate().is_null(); } bool empty() const { return evaluate().empty(); } size_t capacity() const { return evaluate().capacity(); } void reserve(size_t n) { evaluate().reserve(n); } void resize(size_t n) { evaluate().resize(n); } template void resize(size_t n, T val) { evaluate().resize(n,val); } template bool is(Args&&... args) const { return evaluate().template is(std::forward(args)...); } bool is_string() const noexcept { return evaluate().is_string(); } bool is_string_view() const noexcept { return evaluate().is_string_view(); } bool is_byte_string() const noexcept { return evaluate().is_byte_string(); } bool is_byte_string_view() const noexcept { return evaluate().is_byte_string_view(); } bool is_bignum() const noexcept { return evaluate().is_bignum(); } bool is_number() const noexcept { return evaluate().is_number(); } bool is_bool() const noexcept { return evaluate().is_bool(); } bool is_object() const noexcept { return evaluate().is_object(); } bool is_array() const noexcept { return evaluate().is_array(); } bool is_int64() const noexcept { return evaluate().is_int64(); } bool is_uint64() const noexcept { return evaluate().is_uint64(); } bool is_double() const noexcept { return evaluate().is_double(); } string_view_type as_string_view() const { return evaluate().as_string_view(); } byte_string_view as_byte_string_view() const { return evaluate().as_byte_string_view(); } basic_bignum as_bignum() const { return evaluate().as_bignum(); } template > string_type as_string() const { return evaluate().as_string(); } template > string_type as_string(const SAllocator& allocator) const { return evaluate().as_string(allocator); } template > basic_byte_string as_byte_string() const { return evaluate().template as_byte_string(); } template > string_type as_string(const basic_json_options& options) const { return evaluate().as_string(options); } template > string_type as_string(const basic_json_options& options, const SAllocator& allocator) const { return evaluate().as_string(options,allocator); } template T as(Args&&... args) const { return evaluate().template as(std::forward(args)...); } template typename std::enable_if::value,T>::type as(const char_allocator_type& allocator) const { return evaluate().template as(allocator); } bool as_bool() const { return evaluate().as_bool(); } double as_double() const { return evaluate().as_double(); } template T as_integer() const { return evaluate().template as_integer(); } template json_proxy& operator=(T&& val) { parent_.evaluate_with_default().insert_or_assign(string_view_type(data_,length_), std::forward(val)); return *this; } bool operator==(const basic_json& rhs) const { return evaluate() == rhs; } bool operator!=(const basic_json& rhs) const { return evaluate() != rhs; } bool operator<(const basic_json& rhs) const { return evaluate() < rhs; } bool operator<=(const basic_json& rhs) const { return !(rhs < evaluate()); } bool operator>(const basic_json& rhs) const { return !(evaluate() <= rhs); } bool operator>=(const basic_json& rhs) const { return !(evaluate() < rhs); } basic_json& operator[](size_t i) { return evaluate_with_default().at(i); } const basic_json& operator[](size_t i) const { return evaluate().at(i); } json_proxy operator[](const string_view_type& key) { return json_proxy(*this,key.data(),key.length()); } const basic_json& operator[](const string_view_type& name) const { return at(name); } basic_json& at(const string_view_type& name) { return evaluate().at(name); } const basic_json& at(const string_view_type& name) const { return evaluate().at(name); } const basic_json& at(size_t index) { return evaluate().at(index); } const basic_json& at(size_t index) const { return evaluate().at(index); } object_iterator find(const string_view_type& name) { return evaluate().find(name); } const_object_iterator find(const string_view_type& name) const { return evaluate().find(name); } template T get_with_default(const string_view_type& name, const T& default_val) const { return evaluate().template get_with_default(name,default_val); } template > T get_with_default(const string_view_type& name, const CharT* default_val) const { return evaluate().template get_with_default(name,default_val); } void shrink_to_fit() { evaluate_with_default().shrink_to_fit(); } void clear() { evaluate().clear(); } // Remove all elements from an array or object void erase(const_object_iterator pos) { evaluate().erase(pos); } // Remove a range of elements from an object void erase(const_object_iterator first, const_object_iterator last) { evaluate().erase(first, last); } // Remove a range of elements from an object void erase(const string_view_type& name) { evaluate().erase(name); } void erase(const_array_iterator pos) { evaluate().erase(pos); } // Removes the element at pos void erase(const_array_iterator first, const_array_iterator last) { evaluate().erase(first, last); } // Remove a range of elements from an array // merge void merge(const basic_json& source) { return evaluate().merge(source); } void merge(basic_json&& source) { return evaluate().merge(std::forward(source)); } void merge(object_iterator hint, const basic_json& source) { return evaluate().merge(hint, source); } void merge(object_iterator hint, basic_json&& source) { return evaluate().merge(hint, std::forward(source)); } // merge_or_update void merge_or_update(const basic_json& source) { return evaluate().merge_or_update(source); } void merge_or_update(basic_json&& source) { return evaluate().merge_or_update(std::forward(source)); } void merge_or_update(object_iterator hint, const basic_json& source) { return evaluate().merge_or_update(hint, source); } void merge_or_update(object_iterator hint, basic_json&& source) { return evaluate().merge_or_update(hint, std::forward(source)); } template std::pair insert_or_assign(const string_view_type& name, T&& val) { return evaluate().insert_or_assign(name,std::forward(val)); } // emplace template std::pair try_emplace(const string_view_type& name, Args&&... args) { return evaluate().try_emplace(name,std::forward(args)...); } template object_iterator insert_or_assign(object_iterator hint, const string_view_type& name, T&& val) { return evaluate().insert_or_assign(hint, name, std::forward(val)); } template object_iterator try_emplace(object_iterator hint, const string_view_type& name, Args&&... args) { return evaluate().try_emplace(hint, name, std::forward(args)...); } template array_iterator emplace(const_array_iterator pos, Args&&... args) { evaluate_with_default().emplace(pos, std::forward(args)...); } template basic_json& emplace_back(Args&&... args) { return evaluate_with_default().emplace_back(std::forward(args)...); } template void push_back(T&& val) { evaluate_with_default().push_back(std::forward(val)); } template array_iterator insert(const_array_iterator pos, T&& val) { return evaluate_with_default().insert(pos, std::forward(val)); } template array_iterator insert(const_array_iterator pos, InputIt first, InputIt last) { return evaluate_with_default().insert(pos, first, last); } template void insert(InputIt first, InputIt last) { evaluate_with_default().insert(first, last); } template void insert(sorted_unique_range_tag tag, InputIt first, InputIt last) { evaluate_with_default().insert(tag, first, last); } template void dump(std::basic_string& s) const { evaluate().dump(s); } template void dump(std::basic_string& s, indenting line_indent) const { evaluate().dump(s, line_indent); } template void dump(std::basic_string& s, const basic_json_options& options) const { evaluate().dump(s,options); } template void dump(std::basic_string& s, const basic_json_options& options, indenting line_indent) const { evaluate().dump(s,options,line_indent); } void dump(basic_json_content_handler& handler) const { evaluate().dump(handler); } void dump(std::basic_ostream& os) const { evaluate().dump(os); } void dump(std::basic_ostream& os, indenting line_indent) const { evaluate().dump(os, line_indent); } void dump(std::basic_ostream& os, const basic_json_options& options) const { evaluate().dump(os,options); } void dump(std::basic_ostream& os, const basic_json_options& options, indenting line_indent) const { evaluate().dump(os,options,line_indent); } #if !defined(JSONCONS_NO_DEPRECATED) bool is_datetime() const noexcept { return evaluate().is_datetime(); } bool is_epoch_time() const noexcept { return evaluate().is_epoch_time(); } template void add(T&& val) { evaluate_with_default().add(std::forward(val)); } template array_iterator add(const_array_iterator pos, T&& val) { return evaluate_with_default().add(pos, std::forward(val)); } // set template std::pair set(const string_view_type& name, T&& val) { return evaluate().set(name,std::forward(val)); } template object_iterator set(object_iterator hint, const string_view_type& name, T&& val) { return evaluate().set(hint, name, std::forward(val)); } bool has_key(const string_view_type& name) const { return evaluate().has_key(name); } bool is_integer() const noexcept { return evaluate().is_int64(); } bool is_uinteger() const noexcept { return evaluate().is_uint64(); } unsigned long long as_ulonglong() const { return evaluate().as_ulonglong(); } uint64_t as_uinteger() const { return evaluate().as_uinteger(); } void dump(std::basic_ostream& os, const basic_json_options& options, bool pprint) const { evaluate().dump(os,options,pprint); } void dump(std::basic_ostream& os, bool pprint) const { evaluate().dump(os, pprint); } string_type to_string(const char_allocator_type& allocator = char_allocator_type()) const noexcept { return evaluate().to_string(allocator); } void write(basic_json_content_handler& handler) const { evaluate().write(handler); } void write(std::basic_ostream& os) const { evaluate().write(os); } void write(std::basic_ostream& os, const basic_json_options& options) const { evaluate().write(os,options); } void write(std::basic_ostream& os, const basic_json_options& options, bool pprint) const { evaluate().write(os,options,pprint); } string_type to_string(const basic_json_options& options, char_allocator_type& allocator = char_allocator_type()) const { return evaluate().to_string(options,allocator); } range members() { return evaluate().members(); } range members() const { return evaluate().members(); } range elements() { return evaluate().elements(); } range elements() const { return evaluate().elements(); } void to_stream(basic_json_content_handler& handler) const { evaluate().to_stream(handler); } void to_stream(std::basic_ostream& os) const { evaluate().to_stream(os); } void to_stream(std::basic_ostream& os, const basic_json_options& options) const { evaluate().to_stream(os,options); } void to_stream(std::basic_ostream& os, const basic_json_options& options, bool pprint) const { evaluate().to_stream(os,options,pprint); } #endif void swap(basic_json& val) { evaluate_with_default().swap(val); } friend std::basic_ostream& operator<<(std::basic_ostream& os, const json_proxy& o) { o.dump(os); return os; } #if !defined(JSONCONS_NO_DEPRECATED) void resize_array(size_t n) { evaluate().resize_array(n); } template void resize_array(size_t n, T val) { evaluate().resize_array(n,val); } object_iterator begin_members() { return evaluate().begin_members(); } const_object_iterator begin_members() const { return evaluate().begin_members(); } object_iterator end_members() { return evaluate().end_members(); } const_object_iterator end_members() const { return evaluate().end_members(); } array_iterator begin_elements() { return evaluate().begin_elements(); } const_array_iterator begin_elements() const { return evaluate().begin_elements(); } array_iterator end_elements() { return evaluate().end_elements(); } const_array_iterator end_elements() const { return evaluate().end_elements(); } template basic_json get(const string_view_type& name, T&& default_val) const { return evaluate().get(name,std::forward(default_val)); } const basic_json& get(const string_view_type& name) const { return evaluate().get(name); } bool is_ulonglong() const noexcept { return evaluate().is_ulonglong(); } bool is_longlong() const noexcept { return evaluate().is_longlong(); } int as_int() const { return evaluate().as_int(); } unsigned int as_uint() const { return evaluate().as_uint(); } long as_long() const { return evaluate().as_long(); } unsigned long as_ulong() const { return evaluate().as_ulong(); } long long as_longlong() const { return evaluate().as_longlong(); } bool has_member(const string_type& name) const { return evaluate().has_member(name); } // Remove a range of elements from an array void remove_range(size_t from_index, size_t to_index) { evaluate().remove_range(from_index, to_index); } // Remove a range of elements from an array void remove(const string_view_type& name) { evaluate().remove(name); } void remove_member(const string_view_type& name) { evaluate().remove(name); } bool is_empty() const noexcept { return empty(); } bool is_numeric() const noexcept { return is_number(); } #endif }; static basic_json parse(std::basic_istream& is) { parse_error_handler_type err_handler; return parse(is,err_handler); } static basic_json parse(std::basic_istream& is, parse_error_handler& err_handler) { json_decoder> handler; basic_json_reader> reader(is, handler, err_handler); reader.read_next(); reader.check_done(); if (!handler.is_valid()) { JSONCONS_THROW(json_runtime_error("Failed to parse json stream")); } return handler.get_result(); } static basic_json parse(const string_view_type& s) { parse_error_handler_type err_handler; return parse(s,err_handler); } #if !defined(JSONCONS_NO_DEPRECATED) void add(size_t index, const basic_json& value) { evaluate_with_default().add(index, value); } void add(size_t index, basic_json&& value) { evaluate_with_default().add(index, std::forward(value)); } static basic_json parse(const char_type* s, size_t length) { parse_error_handler_type err_handler; return parse(s,length,err_handler); } static basic_json parse(const char_type* s, size_t length, parse_error_handler& err_handler) { return parse(string_view_type(s,length),err_handler); } #endif static basic_json parse(const string_view_type& s, parse_error_handler& err_handler) { json_decoder decoder; basic_json_parser parser(err_handler); auto result = unicons::skip_bom(s.begin(), s.end()); if (result.ec != unicons::encoding_errc()) { throw ser_error(result.ec); } size_t offset = result.it - s.begin(); parser.update(s.data()+offset,s.size()-offset); parser.parse_some(decoder); parser.finish_parse(decoder); parser.check_done(); if (!decoder.is_valid()) { JSONCONS_THROW(json_runtime_error("Failed to parse json string")); } return decoder.get_result(); } static basic_json parse(std::basic_istream& is, const basic_json_options& options) { parse_error_handler_type err_handler; return parse(is,options,err_handler); } static basic_json parse(std::basic_istream& is, const basic_json_options& options, parse_error_handler& err_handler) { json_decoder> handler; basic_json_reader> reader(is, handler, options, err_handler); reader.read_next(); reader.check_done(); if (!handler.is_valid()) { JSONCONS_THROW(json_runtime_error("Failed to parse json stream")); } return handler.get_result(); } static basic_json parse(const string_view_type& s, const basic_json_options& options) { parse_error_handler_type err_handler; return parse(s,options,err_handler); } static basic_json parse(const string_view_type& s, const basic_json_options& options, parse_error_handler& err_handler) { json_decoder decoder; basic_json_parser parser(options,err_handler); auto result = unicons::skip_bom(s.begin(), s.end()); if (result.ec != unicons::encoding_errc()) { throw ser_error(result.ec); } size_t offset = result.it - s.begin(); parser.update(s.data()+offset,s.size()-offset); parser.parse_some(decoder); parser.finish_parse(decoder); parser.check_done(); if (!decoder.is_valid()) { JSONCONS_THROW(json_runtime_error("Failed to parse json string")); } return decoder.get_result(); } static basic_json make_array() { return basic_json(array()); } static basic_json make_array(const array& a) { return basic_json(a); } static basic_json make_array(const array& a, allocator_type allocator) { return basic_json(variant(a, semantic_tag::none, allocator)); } static basic_json make_array(std::initializer_list init, const Allocator& allocator = Allocator()) { return array(std::move(init),allocator); } static basic_json make_array(size_t n, const Allocator& allocator = Allocator()) { return array(n,allocator); } template static basic_json make_array(size_t n, const T& val, const Allocator& allocator = Allocator()) { return basic_json::array(n, val,allocator); } template static typename std::enable_if::type make_array(size_t n) { return array(n); } template static typename std::enable_if::type make_array(size_t n, const T& val, const Allocator& allocator = Allocator()) { return array(n,val,allocator); } template static typename std::enable_if<(dim>1),basic_json>::type make_array(size_t n, Args... args) { const size_t dim1 = dim - 1; basic_json val = make_array(std::forward(args)...); val.resize(n); for (size_t i = 0; i < n; ++i) { val[i] = make_array(std::forward(args)...); } return val; } static const basic_json& null() { static basic_json a_null = basic_json(null_type(), semantic_tag::none); return a_null; } variant var_; basic_json(semantic_tag tag = semantic_tag::none) : var_(tag) { } explicit basic_json(const Allocator& allocator, semantic_tag tag = semantic_tag::none) : var_(object(allocator),tag) { } basic_json(const basic_json& val) : var_(val.var_) { } basic_json(const basic_json& val, const Allocator& allocator) : var_(val.var_,allocator) { } basic_json(basic_json&& other) noexcept : var_(std::move(other.var_)) { } basic_json(basic_json&& other, const Allocator&) noexcept : var_(std::move(other.var_) /*,allocator*/ ) { } basic_json(const variant& val) : var_(val) { } basic_json(variant&& other) : var_(std::forward(other)) { } basic_json(const array& val, semantic_tag tag = semantic_tag::none) : var_(val, tag) { } basic_json(array&& other, semantic_tag tag = semantic_tag::none) : var_(std::forward(other), tag) { } basic_json(const object& other, semantic_tag tag = semantic_tag::none) : var_(other, tag) { } basic_json(object&& other, semantic_tag tag = semantic_tag::none) : var_(std::forward(other), tag) { } template basic_json(const json_proxy& proxy) : var_(proxy.evaluate().var_) { } template basic_json(const json_proxy& proxy, const Allocator& allocator) : var_(proxy.evaluate().var_,allocator) { } template basic_json(const T& val) : var_(json_type_traits::to_json(val).var_) { } template basic_json(const T& val, const Allocator& allocator) : var_(json_type_traits::to_json(val,allocator).var_) { } basic_json(const char_type* s, semantic_tag tag = semantic_tag::none) : var_(s, char_traits_type::length(s), tag) { } basic_json(const char_type* s, const Allocator& allocator) : var_(s, char_traits_type::length(s), semantic_tag::none, allocator) { } #if !defined(JSONCONS_NO_DEPRECATED) basic_json(double val, uint8_t) : var_(val, semantic_tag::none) { } basic_json(double val, const floating_point_options&, semantic_tag tag = semantic_tag::none) : var_(val, tag) { } #endif basic_json(double val, semantic_tag tag) : var_(val, tag) { } template basic_json(T val, semantic_tag tag, typename std::enable_if::value && std::is_signed::value>::type* = 0) : var_(static_cast(val), tag) { } template basic_json(T val, semantic_tag tag, typename std::enable_if::value && !std::is_signed::value>::type* = 0) : var_(static_cast(val), tag) { } basic_json(const char_type *s, size_t length, semantic_tag tag = semantic_tag::none) : var_(s, length, tag) { } basic_json(const string_view_type& sv, semantic_tag tag) : var_(sv.data(), sv.length(), tag) { } basic_json(null_type val, semantic_tag tag) : var_(val, tag) { } basic_json(bool val, semantic_tag tag) : var_(val, tag) { } basic_json(const string_view_type& sv, semantic_tag tag, const Allocator& allocator) : var_(sv.data(), sv.length(), tag, allocator) { } basic_json(const char_type *s, size_t length, semantic_tag tag, const Allocator& allocator) : var_(s, length, tag, allocator) { } #if !defined(JSONCONS_NO_DEPRECATED) basic_json(const byte_string_view& bs, byte_string_chars_format encoding_hint, semantic_tag tag = semantic_tag::none) : var_(bs, tag) { switch (encoding_hint) { { case byte_string_chars_format::base16: var_ = variant(bs, semantic_tag::base16); break; case byte_string_chars_format::base64: var_ = variant(bs, semantic_tag::base64); break; case byte_string_chars_format::base64url: var_ = variant(bs, semantic_tag::base64url); break; default: break; } } } #endif explicit basic_json(const byte_string_view& bs, semantic_tag tag = semantic_tag::none) : var_(bs, tag) { } basic_json(const byte_string_view& bs, semantic_tag tag, const Allocator& allocator) : var_(bs, tag, allocator) { } explicit basic_json(const basic_bignum& bs) : var_(bs) { } explicit basic_json(const basic_bignum& bs, const Allocator& allocator) : var_(bs, byte_allocator_type(allocator)) { } #if !defined(JSONCONS_NO_DEPRECATED) template basic_json(InputIterator first, InputIterator last, const Allocator& allocator = Allocator()) : var_(first,last,allocator) { } #endif ~basic_json() { } basic_json& operator=(const basic_json& rhs) { if (this != &rhs) { var_ = rhs.var_; } return *this; } basic_json& operator=(basic_json&& rhs) noexcept { if (this !=&rhs) { var_ = std::move(rhs.var_); } return *this; } template basic_json& operator=(const T& val) { var_ = json_type_traits::to_json(val).var_; return *this; } basic_json& operator=(const char_type* s) { var_ = variant(s, char_traits_type::length(s), semantic_tag::none); return *this; } friend bool operator==(const basic_json& lhs, const basic_json& rhs) { return lhs.var_ == rhs.var_; } friend bool operator!=(const basic_json& lhs, const basic_json& rhs) { return !(lhs == rhs); } friend bool operator<(const basic_json& lhs, const basic_json& rhs) { return lhs.var_ < rhs.var_; } friend bool operator<=(const basic_json& lhs, const basic_json& rhs) { return !(rhs < lhs); } friend bool operator>(const basic_json& lhs, const basic_json& rhs) { return !(lhs <= rhs); } friend bool operator>=(const basic_json& lhs, const basic_json& rhs) { return !(lhs < rhs); } size_t size() const noexcept { switch (var_.get_storage_type()) { case storage_type::empty_object_val: return 0; case storage_type::object_val: return object_value().size(); case storage_type::array_val: return array_value().size(); default: return 0; } } basic_json& operator[](size_t i) { return at(i); } const basic_json& operator[](size_t i) const { return at(i); } json_proxy operator[](const string_view_type& name) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return json_proxy(*this, name.data(),name.length()); break; default: JSONCONS_THROW(not_an_object(name.data(),name.length())); break; } } const basic_json& operator[](const string_view_type& name) const { return at(name); } template void dump(std::basic_string& s) const { typedef std::basic_string string_type; basic_json_compressed_encoder> encoder(s); dump(encoder); } template void dump(std::basic_string& s, indenting line_indent) const { typedef std::basic_string string_type; if (line_indent == indenting::indent) { basic_json_encoder> encoder(s); dump(encoder); } else { basic_json_compressed_encoder> encoder(s); dump(encoder); } } template void dump(std::basic_string& s, const basic_json_options& options) const { typedef std::basic_string string_type; basic_json_compressed_encoder> encoder(s, options); dump(encoder); } template void dump(std::basic_string& s, const basic_json_options& options, indenting line_indent) const { typedef std::basic_string string_type; if (line_indent == indenting::indent) { basic_json_encoder> encoder(s, options); dump(encoder); } else { basic_json_compressed_encoder> encoder(s, options); dump(encoder); } } void dump(basic_json_content_handler& handler) const { dump_noflush(handler); handler.flush(); } void dump(std::basic_ostream& os) const { basic_json_compressed_encoder encoder(os); dump(encoder); } void dump(std::basic_ostream& os, indenting line_indent) const { if (line_indent == indenting::indent) { basic_json_encoder encoder(os); dump(encoder); } else { basic_json_compressed_encoder encoder(os); dump(encoder); } } void dump(std::basic_ostream& os, const basic_json_options& options) const { basic_json_compressed_encoder encoder(os, options); dump(encoder); } void dump(std::basic_ostream& os, const basic_json_options& options, indenting line_indent) const { if (line_indent == indenting::indent) { basic_json_encoder encoder(os, options); dump(encoder); } else { basic_json_compressed_encoder encoder(os, options); dump(encoder); } } string_type to_string(const char_allocator_type& allocator=char_allocator_type()) const noexcept { string_type s(allocator); basic_json_compressed_encoder> encoder(s); dump(encoder); return s; } string_type to_string(const basic_json_options& options, const char_allocator_type& allocator=char_allocator_type()) const { string_type s(allocator); basic_json_compressed_encoder> encoder(s,options); dump(encoder); return s; } #if !defined(JSONCONS_NO_DEPRECATED) void dump_fragment(basic_json_content_handler& handler) const { dump(handler); } void dump_body(basic_json_content_handler& handler) const { dump(handler); } void dump(std::basic_ostream& os, bool pprint) const { if (pprint) { basic_json_encoder encoder(os); dump(encoder); } else { basic_json_compressed_encoder encoder(os); dump(encoder); } } void dump(std::basic_ostream& os, const basic_json_options& options, bool pprint) const { if (pprint) { basic_json_encoder encoder(os, options); dump(encoder); } else { basic_json_compressed_encoder encoder(os, options); dump(encoder); } } void write_body(basic_json_content_handler& handler) const { dump(handler); } void write(basic_json_content_handler& handler) const { dump(handler); } void write(std::basic_ostream& os) const { dump(os); } void write(std::basic_ostream& os, const basic_json_options& options) const { dump(os,options); } void write(std::basic_ostream& os, const basic_json_options& options, bool pprint) const { dump(os,options,pprint); } void to_stream(basic_json_content_handler& handler) const { dump(handler); } void to_stream(std::basic_ostream& os) const { dump(os); } void to_stream(std::basic_ostream& os, const basic_json_options& options) const { dump(os,options); } void to_stream(std::basic_ostream& os, const basic_json_options& options, bool pprint) const { dump(os,options,pprint ? indenting::indent : indenting::no_indent); } #endif bool is_null() const noexcept { return var_.get_storage_type() == storage_type::null_val; } allocator_type get_allocator() const { switch (var_.get_storage_type()) { case storage_type::long_string_val: { return var_.string_data_cast()->get_allocator(); } case storage_type::byte_string_val: { return var_.byte_string_data_cast()->get_allocator(); } case storage_type::array_val: { return var_.array_data_cast()->get_allocator(); } case storage_type::object_val: { return var_.object_data_cast()->get_allocator(); } default: return allocator_type(); } } bool contains(const string_view_type& name) const { switch (var_.get_storage_type()) { case storage_type::object_val: { const_object_iterator it = object_value().find(name); return it != object_range().end(); } break; default: return false; } } size_t count(const string_view_type& name) const { switch (var_.get_storage_type()) { case storage_type::object_val: { auto it = object_value().find(name); if (it == object_range().end()) { return 0; } size_t count = 0; while (it != object_range().end()&& it->key() == name) { ++count; ++it; } return count; } break; default: return 0; } } template bool is(Args&&... args) const { return json_type_traits::is(*this,std::forward(args)...); } bool is_string() const noexcept { return (var_.get_storage_type() == storage_type::long_string_val) || (var_.get_storage_type() == storage_type::short_string_val); } bool is_string_view() const noexcept { return is_string(); } bool is_byte_string() const noexcept { return var_.get_storage_type() == storage_type::byte_string_val; } bool is_byte_string_view() const noexcept { return is_byte_string(); } bool is_bignum() const { switch (get_storage_type()) { case storage_type::short_string_val: case storage_type::long_string_val: return jsoncons::detail::is_integer(as_string_view().data(), as_string_view().length()); case storage_type::int64_val: case storage_type::uint64_val: return true; default: return false; } } bool is_bool() const noexcept { return var_.get_storage_type() == storage_type::bool_val; } bool is_object() const noexcept { return var_.get_storage_type() == storage_type::object_val || var_.get_storage_type() == storage_type::empty_object_val; } bool is_array() const noexcept { return var_.get_storage_type() == storage_type::array_val; } bool is_int64() const noexcept { return var_.get_storage_type() == storage_type::int64_val || (var_.get_storage_type() == storage_type::uint64_val&& (as_integer() <= static_cast((std::numeric_limits::max)()))); } bool is_uint64() const noexcept { return var_.get_storage_type() == storage_type::uint64_val || (var_.get_storage_type() == storage_type::int64_val&& as_integer() >= 0); } bool is_double() const noexcept { return var_.get_storage_type() == storage_type::double_val; } bool is_number() const noexcept { switch (var_.get_storage_type()) { case storage_type::int64_val: case storage_type::uint64_val: case storage_type::double_val: return true; case storage_type::short_string_val: case storage_type::long_string_val: return var_.get_semantic_tag() == semantic_tag::bigint || var_.get_semantic_tag() == semantic_tag::bigdec || var_.get_semantic_tag() == semantic_tag::bigfloat; #if !defined(JSONCONS_NO_DEPRECATED) case storage_type::array_val: return var_.get_semantic_tag() == semantic_tag::bigfloat; #endif default: return false; } } bool empty() const noexcept { switch (var_.get_storage_type()) { case storage_type::byte_string_val: return var_.byte_string_data_cast()->length() == 0; break; case storage_type::short_string_val: return var_.short_string_data_cast()->length() == 0; case storage_type::long_string_val: return var_.string_data_cast()->length() == 0; case storage_type::array_val: return array_value().size() == 0; case storage_type::empty_object_val: return true; case storage_type::object_val: return object_value().size() == 0; default: return false; } } size_t capacity() const { switch (var_.get_storage_type()) { case storage_type::array_val: return array_value().capacity(); case storage_type::object_val: return object_value().capacity(); default: return 0; } } template void create_object_implicitly() { static_assert(is_stateless::value, "Cannot create object implicitly - allocator is stateful."); var_ = variant(object(Allocator()), semantic_tag::none); } void reserve(size_t n) { switch (var_.get_storage_type()) { case storage_type::array_val: array_value().reserve(n); break; case storage_type::empty_object_val: { create_object_implicitly(); object_value().reserve(n); } break; case storage_type::object_val: { object_value().reserve(n); } break; default: break; } } void resize(size_t n) { switch (var_.get_storage_type()) { case storage_type::array_val: array_value().resize(n); break; default: break; } } template void resize(size_t n, T val) { switch (var_.get_storage_type()) { case storage_type::array_val: array_value().resize(n, val); break; default: break; } } template T as(Args&&... args) const { return json_type_traits::as(*this,std::forward(args)...); } template typename std::enable_if::value,T>::type as(const char_allocator_type& allocator) const { return json_type_traits::as(*this,allocator); } bool as_bool() const { switch (var_.get_storage_type()) { case storage_type::short_string_val: case storage_type::long_string_val: if (var_.get_semantic_tag() == semantic_tag::bigint) { return static_cast(var_.as_bignum()); } try { basic_json j = basic_json::parse(as_string_view()); return j.as_bool(); } catch (...) { JSONCONS_THROW(json_runtime_error("Not a bool")); } break; case storage_type::bool_val: return var_.bool_data_cast()->value(); case storage_type::double_val: return var_.double_data_cast()->value() != 0.0; case storage_type::int64_val: return var_.int64_data_cast()->value() != 0; case storage_type::uint64_val: return var_.uint64_data_cast()->value() != 0; default: JSONCONS_THROW(json_runtime_error("Not a bool")); } } template T as_integer() const { switch (var_.get_storage_type()) { case storage_type::short_string_val: case storage_type::long_string_val: { auto result = jsoncons::detail::to_integer(as_string_view().data(), as_string_view().length()); if (result.ec != jsoncons::detail::to_integer_errc()) { JSONCONS_THROW(json_runtime_error(make_error_code(result.ec).message())); } return result.value; } case storage_type::double_val: return static_cast(var_.double_data_cast()->value()); case storage_type::int64_val: return static_cast(var_.int64_data_cast()->value()); case storage_type::uint64_val: return static_cast(var_.uint64_data_cast()->value()); case storage_type::bool_val: return static_cast(var_.bool_data_cast()->value() ? 1 : 0); default: JSONCONS_THROW(json_runtime_error("Not an integer")); } } #if !defined(JSONCONS_NO_DEPRECATED) size_t precision() const { switch (var_.get_storage_type()) { case storage_type::double_val: return 0; default: JSONCONS_THROW(json_runtime_error("Not a double")); } } size_t decimal_places() const { switch (var_.get_storage_type()) { case storage_type::double_val: return 0; default: JSONCONS_THROW(json_runtime_error("Not a double")); } } #endif double as_double() const { switch (var_.get_storage_type()) { case storage_type::short_string_val: case storage_type::long_string_val: { jsoncons::detail::string_to_double to_double; // to_double() throws std::invalid_argument if conversion fails return to_double(as_cstring(), as_string_view().length()); } case storage_type::double_val: return var_.double_data_cast()->value(); case storage_type::int64_val: return static_cast(var_.int64_data_cast()->value()); case storage_type::uint64_val: return static_cast(var_.uint64_data_cast()->value()); #if !defined(JSONCONS_NO_DEPRECATED) case storage_type::array_val: if (get_semantic_tag() == semantic_tag::bigfloat) { jsoncons::detail::string_to_double to_double; string_type s = as_string(); return to_double(s.c_str(), s.length()); } else { JSONCONS_THROW(json_runtime_error("Not a double")); } #endif default: JSONCONS_THROW(json_runtime_error("Not a double")); } } string_view_type as_string_view() const { return var_.as_string_view(); } byte_string_view as_byte_string_view() const { return var_.as_byte_string_view(); } template > basic_byte_string as_byte_string() const { return var_.template as_byte_string(); } basic_bignum as_bignum() const { return var_.as_bignum(); } template > string_type as_string() const { return as_string(basic_json_options(),SAllocator()); } template > string_type as_string(const SAllocator& allocator) const { return as_string(basic_json_options(),allocator); } template > string_type as_string(const basic_json_options& options) const { return as_string(options,SAllocator()); } template > string_type as_string(const basic_json_options& options, const SAllocator& allocator) const { switch (var_.get_storage_type()) { case storage_type::short_string_val: case storage_type::long_string_val: { return string_type(as_string_view().data(),as_string_view().length(),allocator); } case storage_type::byte_string_val: { string_type s(allocator); byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options.byte_string_format(), byte_string_chars_format::none, byte_string_chars_format::base64url); switch (format) { case byte_string_chars_format::base64: encode_base64(var_.byte_string_data_cast()->begin(), var_.byte_string_data_cast()->end(), s); break; case byte_string_chars_format::base16: encode_base16(var_.byte_string_data_cast()->begin(), var_.byte_string_data_cast()->end(), s); break; default: encode_base64url(var_.byte_string_data_cast()->begin(), var_.byte_string_data_cast()->end(), s); break; } return s; } case storage_type::array_val: { string_type s(allocator); #if !defined(JSONCONS_NO_DEPRECATED) if (get_semantic_tag() == semantic_tag::bigfloat) { JSONCONS_ASSERT(size() == 2); int64_t exp = at(0).template as_integer(); string_type mantissa = at(1).as_string(); bignum n(mantissa); int64_t new_exp = 0; bignum five(5); if (exp > 0) { new_exp = static_cast(std::floor(exp*std::log(2)/std::log(10))); bignum five_power = power(five,(unsigned)new_exp); uint64_t binShift = exp - new_exp; n = ((n) << (unsigned)binShift)/five_power; } else { new_exp = static_cast(std::ceil(-exp*std::log(2)/std::log(10))); bignum five_power = power(five,(unsigned)new_exp); uint64_t binShift = -exp - new_exp; n = (n*five_power) >> (unsigned)binShift; } std::string str; n.dump(str); if (str[0] == '-') { s.push_back('-'); jsoncons::detail::prettify_string(str.c_str()+1, str.size()-1, -(int)new_exp, -4, 17, s); } else { jsoncons::detail::prettify_string(str.c_str(), str.size(), -(int)new_exp, -4, 17, s); } } else #endif { basic_json_compressed_encoder> encoder(s,options); dump(encoder); } return s; } default: { string_type s(allocator); basic_json_compressed_encoder> encoder(s,options); dump(encoder); return s; } } } const char_type* as_cstring() const { switch (var_.get_storage_type()) { case storage_type::short_string_val: return var_.short_string_data_cast()->c_str(); case storage_type::long_string_val: return var_.string_data_cast()->c_str(); default: JSONCONS_THROW(json_runtime_error("Not a cstring")); } } #if !defined(JSONCONS_NO_DEPRECATED) bool is_datetime() const noexcept { return var_.get_semantic_tag() == semantic_tag::datetime; } bool is_epoch_time() const noexcept { return var_.get_semantic_tag() == semantic_tag::timestamp; } bool has_key(const string_view_type& name) const { return contains(name); } bool is_integer() const noexcept { return var_.get_storage_type() == storage_type::int64_val || (var_.get_storage_type() == storage_type::uint64_val&& (as_integer() <= static_cast((std::numeric_limits::max)()))); } bool is_uinteger() const noexcept { return var_.get_storage_type() == storage_type::uint64_val || (var_.get_storage_type() == storage_type::int64_val&& as_integer() >= 0); } int64_t as_uinteger() const { return as_integer(); } size_t double_precision() const { switch (var_.get_storage_type()) { case storage_type::double_val: return 0; default: JSONCONS_THROW(json_runtime_error("Not a double")); } } #endif basic_json& at(const string_view_type& name) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: JSONCONS_THROW(key_not_found(name.data(),name.length())); case storage_type::object_val: { auto it = object_value().find(name); if (it == object_range().end()) { JSONCONS_THROW(key_not_found(name.data(),name.length())); } return it->value(); } break; default: { JSONCONS_THROW(not_an_object(name.data(),name.length())); } } } basic_json& evaluate() { return *this; } basic_json& evaluate_with_default() { return *this; } const basic_json& evaluate() const { return *this; } basic_json& evaluate(const string_view_type& name) { return at(name); } const basic_json& evaluate(const string_view_type& name) const { return at(name); } const basic_json& at(const string_view_type& name) const { switch (var_.get_storage_type()) { case storage_type::empty_object_val: JSONCONS_THROW(key_not_found(name.data(),name.length())); case storage_type::object_val: { auto it = object_value().find(name); if (it == object_range().end()) { JSONCONS_THROW(key_not_found(name.data(),name.length())); } return it->value(); } break; default: { JSONCONS_THROW(not_an_object(name.data(),name.length())); } } } basic_json& at(size_t i) { switch (var_.get_storage_type()) { case storage_type::array_val: if (i >= array_value().size()) { JSONCONS_THROW(json_runtime_error("Invalid array subscript")); } return array_value().operator[](i); case storage_type::object_val: return object_value().at(i); default: JSONCONS_THROW(json_runtime_error("Index on non-array value not supported")); } } const basic_json& at(size_t i) const { switch (var_.get_storage_type()) { case storage_type::array_val: if (i >= array_value().size()) { JSONCONS_THROW(json_runtime_error("Invalid array subscript")); } return array_value().operator[](i); case storage_type::object_val: return object_value().at(i); default: JSONCONS_THROW(json_runtime_error("Index on non-array value not supported")); } } object_iterator find(const string_view_type& name) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: return object_range().end(); case storage_type::object_val: return object_value().find(name); default: { JSONCONS_THROW(not_an_object(name.data(),name.length())); } } } const_object_iterator find(const string_view_type& name) const { switch (var_.get_storage_type()) { case storage_type::empty_object_val: return object_range().end(); case storage_type::object_val: return object_value().find(name); default: { JSONCONS_THROW(not_an_object(name.data(),name.length())); } } } template T get_with_default(const string_view_type& name, const T& default_val) const { switch (var_.get_storage_type()) { case storage_type::empty_object_val: { return default_val; } case storage_type::object_val: { const_object_iterator it = object_value().find(name); if (it != object_range().end()) { return it->value().template as(); } else { return default_val; } } default: { JSONCONS_THROW(not_an_object(name.data(),name.length())); } } } template> T get_with_default(const string_view_type& name, const CharT* default_val) const { switch (var_.get_storage_type()) { case storage_type::empty_object_val: { return T(default_val); } case storage_type::object_val: { const_object_iterator it = object_value().find(name); if (it != object_range().end()) { return it->value().template as(); } else { return T(default_val); } } default: { JSONCONS_THROW(not_an_object(name.data(),name.length())); } } } // Modifiers void shrink_to_fit() { switch (var_.get_storage_type()) { case storage_type::array_val: array_value().shrink_to_fit(); break; case storage_type::object_val: object_value().shrink_to_fit(); break; default: break; } } void clear() { switch (var_.get_storage_type()) { case storage_type::array_val: array_value().clear(); break; case storage_type::object_val: object_value().clear(); break; default: break; } } void erase(const_object_iterator pos) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: break; case storage_type::object_val: object_value().erase(pos); break; default: JSONCONS_THROW(json_runtime_error("Not an object")); break; } } void erase(const_object_iterator first, const_object_iterator last) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: break; case storage_type::object_val: object_value().erase(first, last); break; default: JSONCONS_THROW(json_runtime_error("Not an object")); break; } } void erase(const_array_iterator pos) { switch (var_.get_storage_type()) { case storage_type::array_val: array_value().erase(pos); break; default: JSONCONS_THROW(json_runtime_error("Not an array")); break; } } void erase(const_array_iterator first, const_array_iterator last) { switch (var_.get_storage_type()) { case storage_type::array_val: array_value().erase(first, last); break; default: JSONCONS_THROW(json_runtime_error("Not an array")); break; } } // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. void erase(const string_view_type& name) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: break; case storage_type::object_val: object_value().erase(name); break; default: JSONCONS_THROW(not_an_object(name.data(),name.length())); break; } } template std::pair insert_or_assign(const string_view_type& name, T&& val) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return object_value().insert_or_assign(name, std::forward(val)); default: { JSONCONS_THROW(not_an_object(name.data(),name.length())); } } } template std::pair try_emplace(const string_view_type& name, Args&&... args) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return object_value().try_emplace(name, std::forward(args)...); default: { JSONCONS_THROW(not_an_object(name.data(),name.length())); } } } // merge void merge(const basic_json& source) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return object_value().merge(source.object_value()); default: { JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); } } } void merge(basic_json&& source) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return object_value().merge(std::move(source.object_value())); default: { JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); } } } void merge(object_iterator hint, const basic_json& source) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return object_value().merge(hint, source.object_value()); default: { JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); } } } void merge(object_iterator hint, basic_json&& source) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return object_value().merge(hint, std::move(source.object_value())); default: { JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); } } } // merge_or_update void merge_or_update(const basic_json& source) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return object_value().merge_or_update(source.object_value()); default: { JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); } } } void merge_or_update(basic_json&& source) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return object_value().merge_or_update(std::move(source.object_value())); default: { JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); } } } void merge_or_update(object_iterator hint, const basic_json& source) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return object_value().merge_or_update(hint, source.object_value()); default: { JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); } } } void merge_or_update(object_iterator hint, basic_json&& source) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return object_value().merge_or_update(hint, std::move(source.object_value())); default: { JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); } } } template object_iterator insert_or_assign(object_iterator hint, const string_view_type& name, T&& val) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return object_value().insert_or_assign(hint, name, std::forward(val)); default: { JSONCONS_THROW(not_an_object(name.data(),name.length())); } } } template object_iterator try_emplace(object_iterator hint, const string_view_type& name, Args&&... args) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return object_value().try_emplace(hint, name, std::forward(args)...); default: { JSONCONS_THROW(not_an_object(name.data(),name.length())); } } } template array_iterator insert(const_array_iterator pos, T&& val) { switch (var_.get_storage_type()) { case storage_type::array_val: return array_value().insert(pos, std::forward(val)); break; default: { JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); } } } template array_iterator insert(const_array_iterator pos, InputIt first, InputIt last) { switch (var_.get_storage_type()) { case storage_type::array_val: return array_value().insert(pos, first, last); break; default: { JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); } } } template void insert(InputIt first, InputIt last) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: case storage_type::object_val: return object_value().insert(first, last, get_key_value()); break; default: { JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an object")); } } } template void insert(sorted_unique_range_tag tag, InputIt first, InputIt last) { switch (var_.get_storage_type()) { case storage_type::empty_object_val: case storage_type::object_val: return object_value().insert(tag, first, last, get_key_value()); break; default: { JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an object")); } } } template array_iterator emplace(const_array_iterator pos, Args&&... args) { switch (var_.get_storage_type()) { case storage_type::array_val: return array_value().emplace(pos, std::forward(args)...); break; default: { JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); } } } template basic_json& emplace_back(Args&&... args) { switch (var_.get_storage_type()) { case storage_type::array_val: return array_value().emplace_back(std::forward(args)...); default: { JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); } } } storage_type get_storage_type() const { return var_.get_storage_type(); } semantic_tag get_semantic_tag() const { return var_.get_semantic_tag(); } void swap(basic_json& b) { var_.swap(b.var_); } friend void swap(basic_json& a, basic_json& b) { a.swap(b); } template void push_back(T&& val) { switch (var_.get_storage_type()) { case storage_type::array_val: array_value().push_back(std::forward(val)); break; default: { JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); } } } #if !defined(JSONCONS_NO_DEPRECATED) template void add(T&& val) { push_back(std::forward(val)); } template array_iterator add(const_array_iterator pos, T&& val) { return insert(pos, std::forward(val)); } template std::pair set(const string_view_type& name, T&& val) { return insert_or_assign(name, std::forward(val)); } // set template object_iterator set(object_iterator hint, const string_view_type& name, T&& val) { return insert_or_assign(hint, name, std::forward(val)); } static basic_json parse_file(const std::basic_string& filename) { parse_error_handler_type err_handler; return parse_file(filename,err_handler); } static basic_json parse_file(const std::basic_string& filename, parse_error_handler& err_handler) { std::basic_ifstream is(filename); return parse(is,err_handler); } static basic_json parse_stream(std::basic_istream& is) { return parse(is); } static basic_json parse_stream(std::basic_istream& is, parse_error_handler& err_handler) { return parse(is,err_handler); } static basic_json parse_string(const string_type& s) { return parse(s); } static basic_json parse_string(const string_type& s, parse_error_handler& err_handler) { return parse(s,err_handler); } void resize_array(size_t n) { resize(n); } template void resize_array(size_t n, T val) { resize(n,val); } object_iterator begin_members() { return object_range().begin(); } const_object_iterator begin_members() const { return object_range().begin(); } object_iterator end_members() { return object_range().end(); } const_object_iterator end_members() const { return object_range().end(); } array_iterator begin_elements() { return array_range().begin(); } const_array_iterator begin_elements() const { return array_range().begin(); } array_iterator end_elements() { return array_range().end(); } const_array_iterator end_elements() const { return array_range().end(); } template basic_json get(const string_view_type& name, T&& default_val) const { switch (var_.get_storage_type()) { case storage_type::empty_object_val: { return basic_json(std::forward(default_val)); } case storage_type::object_val: { const_object_iterator it = object_value().find(name); if (it != object_range().end()) { return it->value(); } else { return basic_json(std::forward(default_val)); } } default: { JSONCONS_THROW(not_an_object(name.data(),name.length())); } } } const basic_json& get(const string_view_type& name) const { static const basic_json a_null = null_type(); switch (var_.get_storage_type()) { case storage_type::empty_object_val: return a_null; case storage_type::object_val: { const_object_iterator it = object_value().find(name); return it != object_range().end() ? it->value() : a_null; } default: { JSONCONS_THROW(not_an_object(name.data(),name.length())); } } } bool is_longlong() const noexcept { return var_.get_storage_type() == storage_type::int64_val; } bool is_ulonglong() const noexcept { return var_.get_storage_type() == storage_type::uint64_val; } long long as_longlong() const { return as_integer(); } unsigned long long as_ulonglong() const { return as_integer(); } int as_int() const { switch (var_.get_storage_type()) { case storage_type::double_val: return static_cast(var_.double_data_cast()->value()); case storage_type::int64_val: return static_cast(var_.int64_data_cast()->value()); case storage_type::uint64_val: return static_cast(var_.uint64_data_cast()->value()); case storage_type::bool_val: return var_.bool_data_cast()->value() ? 1 : 0; default: JSONCONS_THROW(json_runtime_error("Not an int")); } } unsigned int as_uint() const { switch (var_.get_storage_type()) { case storage_type::double_val: return static_cast(var_.double_data_cast()->value()); case storage_type::int64_val: return static_cast(var_.int64_data_cast()->value()); case storage_type::uint64_val: return static_cast(var_.uint64_data_cast()->value()); case storage_type::bool_val: return var_.bool_data_cast()->value() ? 1 : 0; default: JSONCONS_THROW(json_runtime_error("Not an unsigned int")); } } long as_long() const { switch (var_.get_storage_type()) { case storage_type::double_val: return static_cast(var_.double_data_cast()->value()); case storage_type::int64_val: return static_cast(var_.int64_data_cast()->value()); case storage_type::uint64_val: return static_cast(var_.uint64_data_cast()->value()); case storage_type::bool_val: return var_.bool_data_cast()->value() ? 1 : 0; default: JSONCONS_THROW(json_runtime_error("Not a long")); } } unsigned long as_ulong() const { switch (var_.get_storage_type()) { case storage_type::double_val: return static_cast(var_.double_data_cast()->value()); case storage_type::int64_val: return static_cast(var_.int64_data_cast()->value()); case storage_type::uint64_val: return static_cast(var_.uint64_data_cast()->value()); case storage_type::bool_val: return var_.bool_data_cast()->value() ? 1 : 0; default: JSONCONS_THROW(json_runtime_error("Not an unsigned long")); } } bool has_member(const string_type& name) const { switch (var_.get_storage_type()) { case storage_type::object_val: { const_object_iterator it = object_value().find(name); return it != object_range().end(); } break; default: return false; } } void remove_range(size_t from_index, size_t to_index) { switch (var_.get_storage_type()) { case storage_type::array_val: array_value().remove_range(from_index, to_index); break; default: break; } } // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. void remove(const string_view_type& name) { erase(name); } void remove_member(const string_view_type& name) { erase(name); } // Removes a member from an object value bool is_empty() const noexcept { return empty(); } bool is_numeric() const noexcept { return is_number(); } template static typename std::enable_if::type make_multi_array() { return make_array(); } template static typename std::enable_if::type make_multi_array(size_t n) { return make_array(n); } template static typename std::enable_if::type make_multi_array(size_t n, T val) { return make_array(n,val); } template static typename std::enable_if::type make_multi_array(size_t m, size_t n) { return make_array<2>(m, n); } template static typename std::enable_if::type make_multi_array(size_t m, size_t n, T val) { return make_array<2>(m, n, val); } template static typename std::enable_if::type make_multi_array(size_t m, size_t n, size_t k) { return make_array<3>(m, n, k); } template static typename std::enable_if::type make_multi_array(size_t m, size_t n, size_t k, T val) { return make_array<3>(m, n, k, val); } range members() { return object_range(); } range members() const { return object_range(); } range elements() { return array_range(); } range elements() const { return array_range(); } #endif range object_range() { static basic_json empty_object = object(); switch (var_.get_storage_type()) { case storage_type::empty_object_val: return range(empty_object.object_range().begin(), empty_object.object_range().end()); case storage_type::object_val: return range(object_value().begin(),object_value().end()); default: JSONCONS_THROW(json_runtime_error("Not an object")); } } range object_range() const { static const basic_json empty_object = object(); switch (var_.get_storage_type()) { case storage_type::empty_object_val: return range(empty_object.object_range().begin(), empty_object.object_range().end()); case storage_type::object_val: return range(object_value().begin(),object_value().end()); default: JSONCONS_THROW(json_runtime_error("Not an object")); } } range array_range() { switch (var_.get_storage_type()) { case storage_type::array_val: return range(array_value().begin(),array_value().end()); default: JSONCONS_THROW(json_runtime_error("Not an array")); } } range array_range() const { switch (var_.get_storage_type()) { case storage_type::array_val: return range(array_value().begin(),array_value().end()); default: JSONCONS_THROW(json_runtime_error("Not an array")); } } array& array_value() { switch (var_.get_storage_type()) { case storage_type::array_val: return var_.array_data_cast()->value(); default: JSONCONS_THROW(json_runtime_error("Bad array cast")); break; } } const array& array_value() const { switch (var_.get_storage_type()) { case storage_type::array_val: return var_.array_data_cast()->value(); default: JSONCONS_THROW(json_runtime_error("Bad array cast")); break; } } object& object_value() { switch (var_.get_storage_type()) { case storage_type::empty_object_val: create_object_implicitly(); JSONCONS_FALLTHROUGH; case storage_type::object_val: return var_.object_data_cast()->value(); default: JSONCONS_THROW(json_runtime_error("Bad object cast")); break; } } const object& object_value() const { switch (var_.get_storage_type()) { case storage_type::empty_object_val: const_cast(this)->create_object_implicitly(); // HERE JSONCONS_FALLTHROUGH; case storage_type::object_val: return var_.object_data_cast()->value(); default: JSONCONS_THROW(json_runtime_error("Bad object cast")); break; } } private: void dump_noflush(basic_json_content_handler& handler) const { switch (var_.get_storage_type()) { case storage_type::short_string_val: case storage_type::long_string_val: handler.string_value(as_string_view(), var_.get_semantic_tag()); break; case storage_type::byte_string_val: handler.byte_string_value(var_.byte_string_data_cast()->data(), var_.byte_string_data_cast()->length(), var_.get_semantic_tag()); break; case storage_type::double_val: handler.double_value(var_.double_data_cast()->value(), var_.get_semantic_tag()); break; case storage_type::int64_val: handler.int64_value(var_.int64_data_cast()->value(), var_.get_semantic_tag()); break; case storage_type::uint64_val: handler.uint64_value(var_.uint64_data_cast()->value(), var_.get_semantic_tag()); break; case storage_type::bool_val: handler.bool_value(var_.bool_data_cast()->value(), var_.get_semantic_tag()); break; case storage_type::null_val: handler.null_value(var_.get_semantic_tag()); break; case storage_type::empty_object_val: handler.begin_object(0, var_.get_semantic_tag()); handler.end_object(); break; case storage_type::object_val: { handler.begin_object(size(), var_.get_semantic_tag()); const object& o = object_value(); for (const_object_iterator it = o.begin(); it != o.end(); ++it) { handler.name(string_view_type((it->key()).data(),it->key().length())); it->value().dump_noflush(handler); } handler.end_object(); } break; case storage_type::array_val: { handler.begin_array(size(), var_.get_semantic_tag()); const array& o = array_value(); for (const_array_iterator it = o.begin(); it != o.end(); ++it) { it->dump_noflush(handler); } handler.end_array(); } break; default: break; } } friend std::basic_ostream& operator<<(std::basic_ostream& os, const basic_json& o) { o.dump(os); return os; } friend std::basic_istream& operator<<(std::basic_istream& is, basic_json& o) { json_decoder handler; basic_json_reader> reader(is, handler); reader.read_next(); reader.check_done(); if (!handler.is_valid()) { JSONCONS_THROW(json_runtime_error("Failed to parse json stream")); } o = handler.get_result(); return is; } }; template void swap(typename Json::key_value_type& a, typename Json::key_value_type& b) { a.swap(b); } template std::basic_istream& operator>>(std::basic_istream& is, Json& o) { typedef typename Json::char_type char_type; json_decoder handler; basic_json_reader> reader(is, handler); reader.read_next(); reader.check_done(); if (!handler.is_valid()) { JSONCONS_THROW(json_runtime_error("Failed to parse json stream")); } o = handler.get_result(); return is; } typedef basic_json> json; typedef basic_json> wjson; typedef basic_json> ojson; typedef basic_json> wojson; #if !defined(JSONCONS_NO_DEPRECATED) typedef basic_json> owjson; typedef json_decoder json_deserializer; typedef json_decoder wjson_deserializer; typedef json_decoder ojson_deserializer; typedef json_decoder wojson_deserializer; #endif inline namespace literals { inline jsoncons::json operator "" _json(const char* s, std::size_t n) { return jsoncons::json::parse(jsoncons::json::string_view_type(s, n)); } inline jsoncons::wjson operator "" _json(const wchar_t* s, std::size_t n) { return jsoncons::wjson::parse(jsoncons::wjson::string_view_type(s, n)); } inline jsoncons::ojson operator "" _ojson(const char* s, std::size_t n) { return jsoncons::ojson::parse(jsoncons::ojson::string_view_type(s, n)); } inline jsoncons::wojson operator "" _ojson(const wchar_t* s, std::size_t n) { return jsoncons::wojson::parse(jsoncons::wojson::string_view_type(s, n)); } } } #endif