// 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_JSON_HPP #define JSONCONS_JSON_HPP #include #include #include #include #include #include #include #include #include #include "jsoncons/json_structures.hpp" #include "jsoncons/jsoncons.hpp" #include "jsoncons/json_output_handler.hpp" #include "jsoncons/output_format.hpp" #include "jsoncons/json_serializer.hpp" #include "jsoncons/json_deserializer.hpp" #include "jsoncons/json_reader.hpp" #include "jsoncons/json_type_traits.hpp" #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wswitch" #endif namespace jsoncons { template T* create_impl(const Alloc& allocator, Args&& ... args) { typename std::allocator_traits:: template rebind_alloc alloc(allocator); T* storage = alloc.allocate(1); try { std::allocator_traits:: template rebind_traits::construct(alloc, storage, std::forward(args)...); } catch (...) { alloc.deallocate(storage,1); throw; } return storage; } template void destroy_impl(const Alloc& allocator, T* p) { typename std::allocator_traits:: template rebind_alloc alloc(allocator); std::allocator_traits:: template rebind_traits::destroy(alloc, p); alloc.deallocate(p,1); } template class serializable_any { public: typedef Alloc allocator_type; serializable_any(const Alloc& allocator = Alloc()) : impl_(nullptr) { (void)allocator; } serializable_any(const serializable_any& val) : allocator_(std::allocator_traits::select_on_container_copy_construction(val.get_allocator())) { impl_ = val.impl_ != nullptr ? val.impl_->clone(allocator_) : nullptr; } serializable_any(const serializable_any& val, const Alloc& allocator) { (void)allocator; impl_ = val.impl_ != nullptr ? val.impl_->clone(Alloc()) : nullptr; } serializable_any(serializable_any&& val) : impl_(std::move(val.impl_)) { val.impl_ = nullptr; } serializable_any(serializable_any&& val, const Alloc& allocator) : impl_(std::move(val.impl_)) { (void)allocator; val.impl_ = nullptr; } ~serializable_any() { if (impl_ != nullptr) { destroy_impl(allocator_,impl_); } } template explicit serializable_any(T val) { impl_ = create_impl::value_type>>(allocator_,val); } Alloc get_allocator() const { return allocator_; } template typename type_wrapper::reference cast() { if (typeid(*impl_) != typeid(any_handle_impl::value_type>)) { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad serializable_any cast"); } return static_cast::value_type>&>(*impl_).value_; } template typename type_wrapper::const_reference cast() const { if (typeid(*impl_) != typeid(any_handle_impl::value_type>)) { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad serializable_any cast"); } return static_cast::value_type>&>(*impl_).value_; } serializable_any& operator=(serializable_any rhs) { std::swap(impl_,rhs.impl_); return *this; } void to_stream(basic_json_output_handler& os) const { impl_->to_stream(os); } class any_handle { public: virtual ~any_handle() { } virtual any_handle* clone(const Alloc& allocator) const = 0; virtual void to_stream(basic_json_output_handler& os) const = 0; }; template class any_handle_impl : public any_handle { public: any_handle_impl(T value, const Alloc& allocator = Alloc()) : value_(value) { (void)allocator; } virtual any_handle* clone(const Alloc& allocator) const { return create_impl>(allocator, value_); } virtual void to_stream(basic_json_output_handler& os) const { serialize(os,value_); } T value_; }; Alloc allocator_; any_handle* impl_; }; template inline void serialize(basic_json_output_handler& os, const T&) { os.value(null_type()); } template class basic_parse_error_handler; enum class value_types : uint8_t { // Simple types empty_object_t, small_string_t, double_t, integer_t, uinteger_t, bool_t, null_t, // Non simple types string_t, object_t, array_t, any_t }; inline bool is_simple(value_types type) { return type < value_types::string_t; } template > class basic_json { public: typedef Alloc allocator_type; typedef CharT char_type; typedef typename std::char_traits char_traits_type; typedef typename std::allocator_traits:: template rebind_alloc string_allocator; typedef std::basic_string string_type; typedef basic_json value_type; typedef name_value_pair member_type; typedef typename std::allocator_traits:: template rebind_alloc> array_allocator; typedef typename std::allocator_traits:: template rebind_alloc object_allocator; typedef json_array,array_allocator> array; typedef json_object,object_allocator> object; typedef serializable_any any; typedef jsoncons::null_type null_type; 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; template class range { IteratorT first_; IteratorT last_; public: range(const IteratorT& first, const IteratorT& last) : first_(first), last_(last) { } public: friend class basic_json; IteratorT begin() { return first_; } IteratorT end() { return last_; } }; typedef range object_range; typedef range const_object_range; typedef range array_range; typedef range const_array_range; struct variant { struct string_data : public string_allocator { const char_type* c_str() const { return p_; } const char_type* data() const { return p_; } size_t length() const { return length_; } string_allocator get_allocator() const { return *this; } bool operator==(const string_data& rhs) const { return length() == rhs.length() ? std::char_traits::compare(data(), rhs.data(), length()) == 0 : false; } string_data(const string_allocator& allocator) : string_allocator(allocator), p_(nullptr), length_(0) { } char_type* p_; size_t length_; private: string_data(const string_data&); string_data& operator=(const string_data&); }; struct string_dataA { string_data data; char_type c[1]; }; typedef typename std::aligned_storage::type storage_type; static size_t aligned_size(size_t n) { return sizeof(storage_type) + n; } string_data* create_string_data(const char_type* s, size_t length, const string_allocator& allocator) { size_t mem_size = aligned_size(length*sizeof(char_type)); typename std::allocator_traits:: template rebind_alloc alloc(allocator); char* storage = alloc.allocate(mem_size); string_data* ps = new(storage)string_data(allocator); auto psa = reinterpret_cast(storage); ps->p_ = new(&psa->c)char_type[length + 1]; memcpy(ps->p_, s, length*sizeof(char_type)); ps->p_[length] = 0; ps->length_ = length; return ps; } void destroy_string_data(const string_allocator& allocator, string_data* p) { size_t mem_size = aligned_size(p->length_*sizeof(char_type)); typename std::allocator_traits:: template rebind_alloc alloc(allocator); alloc.deallocate(reinterpret_cast(p),mem_size); } static const size_t small_string_capacity = (sizeof(int64_t)/sizeof(char_type)) - 1; variant() : type_(value_types::empty_object_t) { } variant(const Alloc& a) : type_(value_types::object_t) { value_.object_val_ = create_impl(a, object_allocator(a)); } variant(std::initializer_list init, const Alloc& a) : type_(value_types::array_t) { value_.array_val_ = create_impl(a, std::move(init), array_allocator(a)); } explicit variant(variant&& var) : type_(value_types::null_t) { swap(var); } explicit variant(variant&& var, const Alloc& a) : type_(value_types::null_t) { swap(var); } explicit variant(const variant& var) { init_variant(var); } explicit variant(const variant& var, const Alloc& a) : type_(var.type_) { init_variant(var); } variant(const object & val) : type_(value_types::object_t) { value_.object_val_ = create_impl(val.get_allocator(), val) ; } variant(const object & val, const Alloc& a) : type_(value_types::object_t) { value_.object_val_ = create_impl(a, val, object_allocator(a)) ; } variant(object&& val) : type_(value_types::object_t) { value_.object_val_ = create_impl(val.get_allocator(), std::move(val)); } variant(object&& val, const Alloc& a) : type_(value_types::object_t) { value_.object_val_ = create_impl(a, std::move(val), object_allocator(a)); } variant(const array& val) : type_(value_types::array_t) { value_.array_val_ = create_impl(val.get_allocator(), val); } variant(const array& val, const Alloc& a) : type_(value_types::array_t) { value_.array_val_ = create_impl(a, val, array_allocator(a)); } variant(array&& val) : type_(value_types::array_t) { value_.array_val_ = create_impl(val.get_allocator(), std::move(val)); } variant(array&& val, const Alloc& a) : type_(value_types::array_t) { value_.array_val_ = create_impl(a, std::move(val), array_allocator(a)); } explicit variant(const any& val, const Alloc& a) : type_(value_types::any_t) { value_.any_val_ = create_impl(a, val); } explicit variant(null_type) : type_(value_types::null_t) { } explicit variant(bool val) : type_(value_types::bool_t) { value_.bool_val_ = val; } explicit variant(double val, uint8_t precision) : type_(value_types::double_t), length_or_precision_(precision) { value_.double_val_ = val; } explicit variant(int64_t val) : type_(value_types::integer_t) { value_.integer_val_ = val; } explicit variant(uint64_t val) : type_(value_types::uinteger_t) { value_.uinteger_val_ = val; } explicit variant(const string_type& s, const Alloc& a) { if (s.length() > variant::small_string_capacity) { type_ = value_types::string_t; //value_.string_val_ = create_impl(a, s, string_allocator(a)); value_.string_val_ = create_string_data(s.data(), s.length(), string_allocator(a)); } else { type_ = value_types::small_string_t; length_or_precision_ = static_cast(s.length()); std::memcpy(value_.small_string_val_,s.data(),s.length()*sizeof(char_type)); value_.small_string_val_[length_or_precision_] = 0; } } explicit variant(const char_type* s, const Alloc& a) { size_t length = std::char_traits::length(s); if (length > variant::small_string_capacity) { type_ = value_types::string_t; //value_.string_val_ = create_impl(a, s, string_allocator(a)); value_.string_val_ = create_string_data(s, length, string_allocator(a)); } else { type_ = value_types::small_string_t; length_or_precision_ = static_cast(length); std::memcpy(value_.small_string_val_,s,length*sizeof(char_type)); value_.small_string_val_[length_or_precision_] = 0; } } explicit variant(const char_type* s, size_t length, const Alloc& a) { if (length > variant::small_string_capacity) { type_ = value_types::string_t; //value_.string_val_ = create_impl(a, s, length, string_allocator(a)); value_.string_val_ = create_string_data(s, length, string_allocator(a)); } else { type_ = value_types::small_string_t; length_or_precision_ = static_cast(length); std::memcpy(value_.small_string_val_,s,length*sizeof(char_type)); value_.small_string_val_[length_or_precision_] = 0; } } template variant(InputIterator first, InputIterator last, const Alloc& a) : type_(value_types::array_t) { value_.array_val_ = create_impl(a, first, last, array_allocator(a)); } void init_variant(const variant& var) { type_ = var.type_; switch (type_) { case value_types::null_t: case value_types::empty_object_t: break; case value_types::double_t: length_or_precision_ = 0; value_.double_val_ = var.value_.double_val_; break; case value_types::integer_t: value_.integer_val_ = var.value_.integer_val_; break; case value_types::uinteger_t: value_.uinteger_val_ = var.value_.uinteger_val_; break; case value_types::bool_t: value_.bool_val_ = var.value_.bool_val_; break; case value_types::small_string_t: length_or_precision_ = var.length_or_precision_; std::memcpy(value_.small_string_val_,var.value_.small_string_val_,var.length_or_precision_*sizeof(char_type)); value_.small_string_val_[length_or_precision_] = 0; break; case value_types::string_t: //value_.string_val_ = create_impl(var.value_.string_val_->get_allocator(), *(var.value_.string_val_), string_allocator(var.value_.string_val_->get_allocator())); value_.string_val_ = create_string_data(var.value_.string_val_->data(), var.value_.string_val_->length(), string_allocator(var.value_.string_val_->get_allocator())); break; case value_types::array_t: value_.array_val_ = create_impl(var.value_.array_val_->get_allocator(), *(var.value_.array_val_), array_allocator(var.value_.array_val_->get_allocator())); break; case value_types::object_t: value_.object_val_ = create_impl(var.value_.object_val_->get_allocator(), *(var.value_.object_val_), object_allocator(var.value_.object_val_->get_allocator())); break; case value_types::any_t: value_.any_val_ = create_impl(var.value_.any_val_->get_allocator(), *(var.value_.any_val_)); break; default: break; } } ~variant() { destroy_variant(); } void destroy_variant() { switch (type_) { case value_types::string_t: //destroy_impl(value_.string_val_->get_allocator(), value_.string_val_); destroy_string_data(value_.string_val_->get_allocator(), value_.string_val_); break; case value_types::array_t: destroy_impl(value_.array_val_->get_allocator(), value_.array_val_); break; case value_types::object_t: destroy_impl(value_.object_val_->get_allocator(), value_.object_val_); break; case value_types::any_t: destroy_impl(value_.any_val_->get_allocator(), value_.any_val_); break; default: break; } } variant& operator=(const variant& val) { if (this != &val) { if (is_simple(type_)) { if (is_simple(val.type_)) { type_ = val.type_; length_or_precision_ = val.length_or_precision_; value_ = val.value_; } else { init_variant(val); } } else { destroy_variant(); init_variant(val); } } return *this; } variant& operator=(variant&& val) { if (this != &val) { val.swap(*this); } return *this; } void assign(const object & val) { destroy_variant(); type_ = value_types::object_t; value_.object_val_ = create_impl(val.get_allocator(), val, object_allocator(val.get_allocator())); } void assign(object && val) { switch (type_) { case value_types::object_t: value_.object_val_->swap(val); break; default: destroy_variant(); type_ = value_types::object_t; value_.object_val_ = create_impl(val.get_allocator(), std::move(val), object_allocator(val.get_allocator())); break; } } void assign(const array& val) { destroy_variant(); type_ = value_types::array_t; value_.array_val_ = create_impl(val.get_allocator(), val, array_allocator(val.get_allocator())) ; } void assign(array&& val) { switch (type_) { case value_types::array_t: value_.array_val_->swap(val); break; default: destroy_variant(); type_ = value_types::array_t; value_.array_val_ = create_impl(val.get_allocator(), std::move(val), array_allocator(val.get_allocator())); break; } } void assign(const string_type& s) { destroy_variant(); if (s.length() > variant::small_string_capacity) { type_ = value_types::string_t; //value_.string_val_ = create_impl(s.get_allocator(), s, string_allocator(s.get_allocator())); value_.string_val_ = create_string_data(s.data(), s.length(), string_allocator(s.get_allocator())); } else { type_ = value_types::small_string_t; length_or_precision_ = static_cast(s.length()); std::memcpy(value_.small_string_val_,s.data(),s.length()*sizeof(char_type)); value_.small_string_val_[length_or_precision_] = 0; } } void assign_string(const char_type* s, size_t length, const Alloc& allocator = Alloc()) { destroy_variant(); if (length > variant::small_string_capacity) { type_ = value_types::string_t; //value_.string_val_ = create_impl(allocator, s, length, string_allocator(allocator)); value_.string_val_ = create_string_data(s, length, string_allocator(allocator)); } else { type_ = value_types::small_string_t; length_or_precision_ = static_cast(length); std::memcpy(value_.small_string_val_,s,length*sizeof(char_type)); value_.small_string_val_[length_or_precision_] = 0; } } void assign(int64_t val) { destroy_variant(); type_ = value_types::integer_t; value_.integer_val_ = val; } void assign(uint64_t val) { destroy_variant(); type_ = value_types::uinteger_t; value_.uinteger_val_ = val; } void assign(double val, uint8_t precision = 0) { destroy_variant(); type_ = value_types::double_t; length_or_precision_ = precision; value_.double_val_ = val; } void assign(bool val) { destroy_variant(); type_ = value_types::bool_t; value_.bool_val_ = val; } void assign(null_type) { destroy_variant(); type_ = value_types::null_t; } void assign(const any& rhs) { destroy_variant(); type_ = value_types::any_t; value_.any_val_ = create_impl(rhs.get_allocator(), rhs); } bool operator!=(const variant& rhs) const { return !(*this == rhs); } bool operator==(const variant& rhs) const { if (is_number() & rhs.is_number()) { switch (type_) { case value_types::integer_t: switch (rhs.type_) { case value_types::integer_t: return value_.integer_val_ == rhs.value_.integer_val_; case value_types::uinteger_t: return value_.integer_val_ == rhs.value_.uinteger_val_; case value_types::double_t: return value_.integer_val_ == rhs.value_.double_val_; default: break; } break; case value_types::uinteger_t: switch (rhs.type_) { case value_types::integer_t: return value_.uinteger_val_ == rhs.value_.integer_val_; case value_types::uinteger_t: return value_.uinteger_val_ == rhs.value_.uinteger_val_; case value_types::double_t: return value_.uinteger_val_ == rhs.value_.double_val_; default: break; } break; case value_types::double_t: switch (rhs.type_) { case value_types::integer_t: return value_.double_val_ == rhs.value_.integer_val_; case value_types::uinteger_t: return value_.double_val_ == rhs.value_.uinteger_val_; case value_types::double_t: return value_.double_val_ == rhs.value_.double_val_; default: break; } break; default: break; } } switch (type_) { case value_types::bool_t: return type_ == rhs.type_ && value_.bool_val_ == rhs.value_.bool_val_; case value_types::null_t: return type_ == rhs.type_; case value_types::empty_object_t: return type_ == rhs.type_ || (rhs.type_ == value_types::object_t && rhs.empty()); case value_types::small_string_t: return type_ == rhs.type_ && length_or_precision_ == rhs.length_or_precision_ ? std::char_traits::compare(value_.small_string_val_,rhs.value_.small_string_val_,length_or_precision_) == 0 : false; case value_types::string_t: return type_ == rhs.type_ && *(value_.string_val_) == *(rhs.value_.string_val_); case value_types::array_t: return type_ == rhs.type_ && *(value_.array_val_) == *(rhs.value_.array_val_); break; case value_types::object_t: return (type_ == rhs.type_ && *(value_.object_val_) == *(rhs.value_.object_val_)) || (rhs.type_ == value_types::empty_object_t && empty()); break; case value_types::any_t: return type_ == rhs.type_; default: // throw break; } return false; } bool is_null() const JSONCONS_NOEXCEPT { return type_ == value_types::null_t; } bool is_bool() const JSONCONS_NOEXCEPT { return type_ == value_types::bool_t; } bool empty() const JSONCONS_NOEXCEPT { switch (type_) { case value_types::small_string_t: return length_or_precision_ == 0; case value_types::string_t: return value_.string_val_->length() == 0; case value_types::array_t: return value_.array_val_->size() == 0; case value_types::empty_object_t: return true; case value_types::object_t: return value_.object_val_->size() == 0; default: return false; } } bool is_string() const JSONCONS_NOEXCEPT { return (type_ == value_types::string_t) | (type_ == value_types::small_string_t); } bool is_number() const JSONCONS_NOEXCEPT { return type_ == value_types::double_t || type_ == value_types::integer_t || type_ == value_types::uinteger_t; } void swap(variant& rhs) { using std::swap; if (this == &rhs) { // same object, do nothing } else { swap(type_, rhs.type_); swap(length_or_precision_, rhs.length_or_precision_); swap(value_, rhs.value_); } } value_types type_; uint8_t length_or_precision_; union { double double_val_; int64_t integer_val_; uint64_t uinteger_val_; bool bool_val_; object* object_val_; array* array_val_; any* any_val_; string_data* string_val_; char_type small_string_val_[sizeof(int64_t)/sizeof(char_type)]; } value_; }; template class json_proxy { private: typedef json_proxy proxy_type; ParentT& parent_; const string_type& name_; json_proxy() = delete; json_proxy& operator = (const json_proxy& other) = delete; json_proxy(ParentT& parent, const string_type& name) : parent_(parent), name_(name) { } basic_json& evaluate() { return parent_.evaluate(name_); } const basic_json& evaluate() const { return parent_.evaluate(name_); } basic_json& evaluate_with_default() { basic_json& val = parent_.evaluate_with_default(); auto it = val.find(name_.data(),name_.length()); if (it == val.members().end()) { it = val.set(val.members().begin(),name_,object(val.object_value().get_allocator())); } return it->value(); } basic_json& evaluate(size_t index) { return parent_.evaluate(name_).at(index); } const basic_json& evaluate(size_t index) const { return parent_.evaluate(name_).at(index); } basic_json& evaluate(const string_type& index) { return parent_.evaluate(name_).at(index); } const basic_json& evaluate(const string_type& index) const { return parent_.evaluate(name_).at(index); } public: friend class basic_json; object_range members() { return evaluate().members(); } const_object_range members() const { return evaluate().members(); } array_range elements() { return evaluate().elements(); } const_array_range elements() const { return evaluate().elements(); } size_t size() const JSONCONS_NOEXCEPT { return evaluate().size(); } value_types type() const { return evaluate().type(); } size_t count(const string_type& name) const { return evaluate().count(name); } bool is_null() const JSONCONS_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() const { return evaluate().template is(); } bool is_string() const JSONCONS_NOEXCEPT { return evaluate().is_string(); } bool is_number() const JSONCONS_NOEXCEPT { return evaluate().is_number(); } bool is_bool() const JSONCONS_NOEXCEPT { return evaluate().is_bool(); } bool is_object() const JSONCONS_NOEXCEPT { return evaluate().is_object(); } bool is_array() const JSONCONS_NOEXCEPT { return evaluate().is_array(); } bool is_any() const JSONCONS_NOEXCEPT { return evaluate().is_any(); } bool is_integer() const JSONCONS_NOEXCEPT { return evaluate().is_integer(); } bool is_uinteger() const JSONCONS_NOEXCEPT { return evaluate().is_uinteger(); } bool is_double() const JSONCONS_NOEXCEPT { return evaluate().is_double(); } string_type as_string() const JSONCONS_NOEXCEPT { return evaluate().as_string(); } string_type as_string(const string_allocator& allocator) const JSONCONS_NOEXCEPT { return evaluate().as_string(allocator); } string_type as_string(const basic_output_format& format) const { return evaluate().as_string(format); } string_type as_string(const basic_output_format& format, const string_allocator& allocator) const { return evaluate().as_string(format,allocator); } template T as() const { return evaluate().template as(); } template typename std::enable_if::value>::type as(const string_allocator& allocator) const { return evaluate().template as(allocator); } any& any_value() { return evaluate().any_value(); } const any& any_value() const { return evaluate().any_value(); } bool as_bool() const JSONCONS_NOEXCEPT { return evaluate().as_bool(); } template std::vector as_vector() const { return evaluate().template as_vector(); } double as_double() const { return evaluate().as_double(); } int64_t as_integer() const { return evaluate().as_integer(); } unsigned long long as_ulonglong() const { return evaluate().as_ulonglong(); } uint64_t as_uinteger() const { return evaluate().as_uinteger(); } template const T& any_cast() const { return evaluate().template any_cast(); } // Returns a const reference to the custom data associated with name template T& any_cast() { return evaluate().template any_cast(); } // Returns a reference to the custom data associated with name operator basic_json&() { return evaluate(); } operator const basic_json&() const { return evaluate(); } template json_proxy& operator=(T val) { parent_.evaluate_with_default().set(name_, val); return *this; } json_proxy& operator=(const basic_json& val) { parent_.evaluate_with_default().set(name_, val); return *this; } json_proxy& operator=(basic_json&& val) { parent_.evaluate_with_default().set(name_, std::move(val)); return *this; } bool operator==(const basic_json& val) const { return evaluate() == val; } bool operator!=(const basic_json& val) const { return evaluate() != val; } 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_type& name) { return json_proxy(*this,name); } const json_proxy operator[](const string_type& name) const { return json_proxy(*this,name); } basic_json& at(const string_type& name) { return evaluate().at(name); } const basic_json& at(const string_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_type& name) { return evaluate().find(name); } const_object_iterator find(const string_type& name) const { return evaluate().find(name); } object_iterator find(const char_type* name) { return evaluate().find(name); } const_object_iterator find(const char_type* name) const { return evaluate().find(name); } object_iterator find(const char_type* name, size_t length) { return evaluate().find(name,length); } const_object_iterator find(const char_type* name, size_t length) const { return evaluate().find(name,length); } template basic_json get(const string_type& name, T&& default_val) const { return evaluate().get(name,std::forward(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(object_iterator first, object_iterator last) { evaluate().erase(first, last); } // Remove a range of elements from an object void erase(array_iterator first, array_iterator last) { evaluate().erase(first, last); } void erase(const string_type& name) { evaluate().erase(name); } // Remove a member from an object void set(const string_type& name, const basic_json& value) { evaluate().set(name,value); } void set(string_type&& name, const basic_json& value) { evaluate().set(std::move(name),value); } void set(const string_type& name, basic_json&& value) { evaluate().set(name,std::move(value)); } void set(string_type&& name, basic_json&& value) { evaluate().set(std::move(name),std::move(value)); } object_iterator set(object_iterator hint, const string_type& name, const basic_json& value) { return evaluate().set(hint, name,value); } object_iterator set(object_iterator hint, string_type&& name, const basic_json& value) { return evaluate().set(hint, std::move(name),value); } object_iterator set(object_iterator hint, const string_type& name, basic_json&& value) { return evaluate().set(hint, name,std::move(value)); } object_iterator set(object_iterator hint, string_type&& name, basic_json&& value) { return evaluate().set(hint, std::move(name),std::move(value)); } void add(basic_json&& value) { evaluate_with_default().add(std::move(value)); } void add(const basic_json& value) { evaluate_with_default().add(value); } array_iterator add(const_array_iterator pos, const basic_json& value) { return evaluate_with_default().add(pos, value); } array_iterator add(const_array_iterator pos, basic_json&& value) { return evaluate_with_default().add(pos, std::move(value)); } string_type to_string(const string_allocator& allocator = string_allocator()) const JSONCONS_NOEXCEPT { return evaluate().to_string(allocator); } string_type to_string(const basic_output_format& format, string_allocator& allocator = string_allocator()) const { return evaluate().to_string(format,allocator); } void to_stream(std::basic_ostream& os) const { evaluate().to_stream(os); } void to_stream(std::basic_ostream& os, const basic_output_format& format) const { evaluate().to_stream(os,format); } void to_stream(std::basic_ostream& os, const basic_output_format& format, bool indenting) const { evaluate().to_stream(os,format,indenting); } void swap(basic_json& val) { evaluate_with_default().swap(val); } friend std::basic_ostream& operator<<(std::basic_ostream& os, const json_proxy& o) { o.to_stream(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(); } const basic_json& get(const string_type& name) const { return evaluate().get(name); } bool is_ulonglong() const JSONCONS_NOEXCEPT { return evaluate().is_ulonglong(); } bool is_longlong() const JSONCONS_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(); } 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::move(value)); } 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_type& name) { evaluate().remove(name); } void remove_member(const string_type& name) { evaluate().remove(name); } bool is_empty() const JSONCONS_NOEXCEPT { return empty(); } bool is_numeric() const JSONCONS_NOEXCEPT { return is_number(); } #endif }; static basic_json parse_stream(std::basic_istream& is); static basic_json parse_stream(std::basic_istream& is, basic_parse_error_handler& err_handler); static basic_json parse(const string_type& s) { basic_json_deserializer> handler; basic_json_parser parser(handler); parser.begin_parse(); parser.parse(s.data(),0,s.length()); parser.end_parse(); parser.check_done(s.data(),parser.index(),s.length()); if (!handler.is_valid()) { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json string"); } return handler.get_result(); } static basic_json parse(const string_type& s, basic_parse_error_handler& err_handler) { basic_json_deserializer> handler; basic_json_parser parser(handler,err_handler); parser.begin_parse(); parser.parse(s.data(),0,s.length()); parser.end_parse(); parser.check_done(s.data(),parser.index(),s.length()); if (!handler.is_valid()) { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json string"); } return handler.get_result(); } static basic_json parse_file(const std::string& s); static basic_json parse_file(const std::string& s, basic_parse_error_handler& err_handler); static basic_json make_array() { return basic_json::array(); } static basic_json make_array(size_t n, const array_allocator& allocator = array_allocator()) { return basic_json::array(n,allocator); } template static basic_json make_array(size_t n, const T& val, const array_allocator& allocator = array_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 Alloc& allocator = Alloc()) { 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(args...); val.resize(n); for (size_t i = 0; i < n; ++i) { val[i] = make_array(args...); } return val; } variant var_; basic_json() : var_() { } basic_json(const Alloc& allocator) : var_(allocator) { } basic_json(std::initializer_list init, const Alloc& allocator = Alloc()) : var_(std::move(init), allocator) { } basic_json(const basic_json& val) : var_(val.var_) { } basic_json(const basic_json& val, const Alloc& allocator) : var_(val.var_,allocator) { } basic_json(basic_json&& other) : var_(std::move(other.var_)) { } basic_json(basic_json&& other, const Alloc& allocator) : var_(std::move(other.var_),allocator) { } basic_json(const array& val) : var_(val) { } basic_json(array&& other) : var_(std::move(other)) { } basic_json(const object& other) : var_(other) { } basic_json(object&& other) : var_(std::move(other)) { } template basic_json(const json_proxy& proxy, const Alloc& allocator = Alloc()) : var_(proxy.evaluate().var_,allocator) { } template basic_json(T val) : var_(null_type()) { json_type_traits::assign(*this,val); } basic_json(double val, uint8_t precision) : var_(val,precision) { } template basic_json(T val, const Alloc& allocator) : var_(allocator) { json_type_traits::assign(*this,val); } basic_json(const char_type *s, size_t length, const Alloc& allocator = Alloc()) : var_(s, length, allocator) { } template basic_json(InputIterator first, InputIterator last, const Alloc& allocator = Alloc()) : var_(first,last,allocator) { } ~basic_json() { } basic_json& operator=(const basic_json& rhs) { var_ = rhs.var_; return *this; } basic_json& operator=(basic_json&& rhs) { if (this != &rhs) { var_ = std::move(rhs.var_); } return *this; } basic_json& operator=(std::initializer_list init) { basic_json val(init); swap(val); return *this; } template basic_json& operator=(T val) { json_type_traits::assign(*this,val); return *this; } bool operator!=(const basic_json& rhs) const; bool operator==(const basic_json& rhs) const; size_t size() const JSONCONS_NOEXCEPT { switch (var_.type_) { case value_types::empty_object_t: return 0; case value_types::object_t: return var_.value_.object_val_->size(); case value_types::array_t: return var_.value_.array_val_->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_type& name) { switch (var_.type_) { case value_types::empty_object_t: create_object_implicitly(); case value_types::object_t: return json_proxy>(*this, name); break; default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an object"); break; } } const basic_json& operator[](const string_type& name) const { return at(name); } string_type to_string(const string_allocator& allocator=string_allocator()) const JSONCONS_NOEXCEPT { string_type s(allocator); std::basic_ostringstream os(s); { basic_json_serializer serializer(os); to_stream(serializer); } return os.str(); } string_type to_string(const basic_output_format& format, const string_allocator& allocator=string_allocator()) const { string_type s(allocator); std::basic_ostringstream os(s); { basic_json_serializer serializer(os, format); to_stream(serializer); } return os.str(); } void to_stream(basic_json_output_handler& handler) const { switch (var_.type_) { case value_types::small_string_t: handler.value(var_.value_.small_string_val_,var_.length_or_precision_); break; case value_types::string_t: handler.value(var_.value_.string_val_->data(),var_.value_.string_val_->length()); break; case value_types::double_t: handler.value(var_.value_.double_val_, var_.length_or_precision_); break; case value_types::integer_t: handler.value(var_.value_.integer_val_); break; case value_types::uinteger_t: handler.value(var_.value_.uinteger_val_); break; case value_types::bool_t: handler.value(var_.value_.bool_val_); break; case value_types::null_t: handler.value(null_type()); break; case value_types::empty_object_t: handler.begin_object(); handler.end_object(); break; case value_types::object_t: { handler.begin_object(); object* o = var_.value_.object_val_; for (const_object_iterator it = o->begin(); it != o->end(); ++it) { handler.name((it->name()).data(),it->name().length()); it->value().to_stream(handler); } handler.end_object(); } break; case value_types::array_t: { handler.begin_array(); array *o = var_.value_.array_val_; for (const_array_iterator it = o->begin(); it != o->end(); ++it) { it->to_stream(handler); } handler.end_array(); } break; case value_types::any_t: var_.value_.any_val_->to_stream(handler); break; default: break; } } void to_stream(std::basic_ostream& os) const { basic_json_serializer serializer(os); to_stream(serializer); } void to_stream(std::basic_ostream& os, const basic_output_format& format) const { basic_json_serializer serializer(os, format); to_stream(serializer); } void to_stream(std::basic_ostream& os, const basic_output_format& format, bool indenting) const { basic_json_serializer serializer(os, format, indenting); to_stream(serializer); } bool is_null() const JSONCONS_NOEXCEPT { return var_.is_null(); } size_t count(const string_type& name) const { switch (var_.type_) { case value_types::object_t: { auto it = var_.value_.object_val_->find(name.data(),name.length()); if (it == members().end()) { return 0; } size_t count = 0; while (it != members().end() && it->name() == name) { ++count; ++it; } return count; } break; default: return 0; } } template bool is() const { return json_type_traits::is(*this); } bool is_string() const JSONCONS_NOEXCEPT { return var_.is_string(); } bool is_bool() const JSONCONS_NOEXCEPT { return var_.is_bool(); } bool is_object() const JSONCONS_NOEXCEPT { return var_.type_ == value_types::object_t || var_.type_ == value_types::empty_object_t; } bool is_array() const JSONCONS_NOEXCEPT { return var_.type_ == value_types::array_t; } bool is_any() const JSONCONS_NOEXCEPT { return var_.type_ == value_types::any_t; } bool is_integer() const JSONCONS_NOEXCEPT { return var_.type_ == value_types::integer_t || (var_.type_ == value_types::uinteger_t && (as_uinteger() <= static_cast(std::numeric_limits::max JSONCONS_NO_MACRO_EXP()))); } bool is_uinteger() const JSONCONS_NOEXCEPT { return var_.type_ == value_types::uinteger_t || (var_.type_ == value_types::integer_t && as_integer() >= 0); } bool is_double() const JSONCONS_NOEXCEPT { return var_.type_ == value_types::double_t; } bool is_number() const JSONCONS_NOEXCEPT { return var_.is_number(); } bool empty() const JSONCONS_NOEXCEPT { return var_.empty(); } size_t capacity() const { switch (var_.type_) { case value_types::array_t: return var_.value_.array_val_->capacity(); case value_types::object_t: return var_.value_.object_val_->capacity(); default: return 0; } } template::value >::type* = nullptr> void create_object_implicitly() { var_.type_ = value_types::object_t; var_.value_.object_val_ = create_impl(Alloc(),object_allocator(Alloc())); } template::value >::type* = nullptr> void create_object_implicitly() const { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Cannot create_impl object implicitly - allocator is not default constructible."); } void reserve(size_t n) { switch (var_.type_) { case value_types::array_t: var_.value_.array_val_->reserve(n); break; case value_types::empty_object_t: { create_object_implicitly(); var_.value_.object_val_->reserve(n); } break; case value_types::object_t: { var_.value_.object_val_->reserve(n); } break; default: break; } } void resize(size_t n) { switch (var_.type_) { case value_types::array_t: var_.value_.array_val_->resize(n); break; default: break; } } template void resize(size_t n, T val) { switch (var_.type_) { case value_types::array_t: var_.value_.array_val_->resize(n, val); break; default: break; } } template T as() const { return json_type_traits::as(*this); } template typename std::enable_if::value>::type as(const string_allocator& allocator) const { return json_type_traits::as(*this,allocator); } bool as_bool() const JSONCONS_NOEXCEPT { switch (var_.type_) { case value_types::null_t: case value_types::empty_object_t: return false; case value_types::bool_t: return var_.value_.bool_val_; case value_types::double_t: return var_.value_.double_val_ != 0.0; case value_types::integer_t: return var_.value_.integer_val_ != 0; case value_types::uinteger_t: return var_.value_.uinteger_val_ != 0; case value_types::small_string_t: return var_.length_or_precision_ != 0; case value_types::string_t: return var_.value_.string_val_->length() != 0; case value_types::array_t: return var_.value_.array_val_->size() != 0; case value_types::object_t: return var_.value_.object_val_->size() != 0; case value_types::any_t: return true; default: return false; } } int64_t as_integer() const { switch (var_.type_) { case value_types::double_t: return static_cast(var_.value_.double_val_); case value_types::integer_t: return static_cast(var_.value_.integer_val_); case value_types::uinteger_t: return static_cast(var_.value_.uinteger_val_); case value_types::bool_t: return var_.value_.bool_val_ ? 1 : 0; default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an integer"); } } uint64_t as_uinteger() const { switch (var_.type_) { case value_types::double_t: return static_cast(var_.value_.double_val_); case value_types::integer_t: return static_cast(var_.value_.integer_val_); case value_types::uinteger_t: return static_cast(var_.value_.uinteger_val_); case value_types::bool_t: return var_.value_.bool_val_ ? 1 : 0; default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an unsigned integer"); } } double as_double() const { switch (var_.type_) { case value_types::double_t: return var_.value_.double_val_; case value_types::integer_t: return static_cast(var_.value_.integer_val_); case value_types::uinteger_t: return static_cast(var_.value_.uinteger_val_); case value_types::null_t: return std::numeric_limits::quiet_NaN(); default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not a double"); } } string_type as_string() const JSONCONS_NOEXCEPT { switch (var_.type_) { case value_types::small_string_t: return string_type(var_.value_.small_string_val_,var_.length_or_precision_); case value_types::string_t: return string_type(var_.value_.string_val_->data(),var_.value_.string_val_->length(),var_.value_.string_val_->get_allocator()); default: return to_string(); } } string_type as_string(const string_allocator& allocator) const JSONCONS_NOEXCEPT { switch (var_.type_) { case value_types::small_string_t: return string_type(var_.value_.small_string_val_,var_.length_or_precision_,allocator); case value_types::string_t: return string_type(var_.value_.string_val_->data(),var_.value_.string_val_->length(),allocator); default: return to_string(allocator); } } string_type as_string(const basic_output_format& format) const { switch (var_.type_) { case value_types::small_string_t: return string_type(var_.value_.small_string_val_,var_.length_or_precision_); case value_types::string_t: return string_type(var_.value_.string_val_->data(),var_.value_.string_val_->length(),var_.value_.string_val_->get_allocator()); default: return to_string(format); } } string_type as_string(const basic_output_format& format, const string_allocator& allocator) const { switch (var_.type_) { case value_types::small_string_t: return string_type(var_.value_.small_string_val_,var_.length_or_precision_,allocator); case value_types::string_t: return string_type(var_.value_.string_val_->data(),var_.value_.string_val_->length(),allocator); default: return to_string(format,allocator); } } const char_type* as_cstring() const { switch (var_.type_) { case value_types::small_string_t: return var_.value_.small_string_val_; case value_types::string_t: return var_.value_.string_val_->c_str(); default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not a cstring"); } } any& any_value(); const any& any_value() const; basic_json& at(const string_type& name) { switch (var_.type_) { case value_types::empty_object_t: JSONCONS_THROW_EXCEPTION_1(std::out_of_range,"%s not found", name); case value_types::object_t: { auto it = var_.value_.object_val_->find(name.data(),name.length()); if (it == members().end()) { JSONCONS_THROW_EXCEPTION_1(std::out_of_range, "%s not found", name); } return it->value(); } break; default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); } } } basic_json& evaluate() { return *this; } basic_json& evaluate_with_default() { return *this; } const basic_json& evaluate() const { return *this; } basic_json& evaluate(size_t i) { return at(i); } const basic_json& evaluate(size_t i) const { return at(i); } basic_json& evaluate(const string_type& name) { return at(name); } const basic_json& evaluate(const string_type& name) const { return at(name); } const basic_json& at(const string_type& name) const { switch (var_.type_) { case value_types::empty_object_t: JSONCONS_THROW_EXCEPTION_1(std::out_of_range,"%s not found", name); case value_types::object_t: { auto it = var_.value_.object_val_->find(name.data(),name.length()); if (it == members().end()) { JSONCONS_THROW_EXCEPTION_1(std::out_of_range, "%s not found", name); } return it->value(); } break; default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); } } } basic_json& at(size_t i) { switch (var_.type_) { case value_types::array_t: if (i >= var_.value_.array_val_->size()) { JSONCONS_THROW_EXCEPTION(std::out_of_range,"Invalid array subscript"); } return var_.value_.array_val_->operator[](i); default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Index on non-array value not supported"); } } const basic_json& at(size_t i) const { switch (var_.type_) { case value_types::array_t: if (i >= var_.value_.array_val_->size()) { JSONCONS_THROW_EXCEPTION(std::out_of_range,"Invalid array subscript"); } return var_.value_.array_val_->operator[](i); default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Index on non-array value not supported"); } } object_iterator find(const string_type& name) { switch (var_.type_) { case value_types::empty_object_t: return members().end(); case value_types::object_t: return var_.value_.object_val_->find(name.data(),name.length()); default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); } } } const_object_iterator find(const string_type& name) const { switch (var_.type_) { case value_types::empty_object_t: return members().end(); case value_types::object_t: return var_.value_.object_val_->find(name.data(),name.length()); default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); } } } object_iterator find(const char_type* name) { switch (var_.type_) { case value_types::empty_object_t: return members().end(); case value_types::object_t: return var_.value_.object_val_->find(name, std::char_traits::length(name)); default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); } } } const_object_iterator find(const char_type* name) const { switch (var_.type_) { case value_types::empty_object_t: return members().end(); case value_types::object_t: return var_.value_.object_val_->find(name, std::char_traits::length(name)); default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); } } } object_iterator find(const char_type* name, size_t length) { switch (var_.type_) { case value_types::empty_object_t: return members().end(); case value_types::object_t: return var_.value_.object_val_->find(name, length); default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); } } } const_object_iterator find(const char_type* name, size_t length) const { switch (var_.type_) { case value_types::empty_object_t: return members().end(); case value_types::object_t: return var_.value_.object_val_->find(name, length); default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); } } } template basic_json get(const string_type& name, T&& default_val) const { switch (var_.type_) { case value_types::empty_object_t: { return basic_json(std::forward(default_val)); } case value_types::object_t: { const_object_iterator it = var_.value_.object_val_->find(name.data(),name.length()); if (it != members().end()) { return it->value(); } else { return basic_json(std::forward(default_val)); } } default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); } } } // Modifiers void shrink_to_fit() { switch (var_.type_) { case value_types::array_t: var_.value_.array_val_->shrink_to_fit(); break; case value_types::object_t: var_.value_.object_val_->shrink_to_fit(); break; default: break; } } void clear() { switch (var_.type_) { case value_types::array_t: var_.value_.array_val_->clear(); break; case value_types::object_t: var_.value_.object_val_->clear(); break; default: break; } } void erase(object_iterator first, object_iterator last) { switch (var_.type_) { case value_types::empty_object_t: break; case value_types::object_t: var_.value_.object_val_->erase(first, last); break; default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an object"); break; } } void erase(array_iterator first, array_iterator last) { switch (var_.type_) { case value_types::array_t: var_.value_.array_val_->erase(first, last); break; default: JSONCONS_THROW_EXCEPTION(std::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_type& name) { switch (var_.type_) { case value_types::empty_object_t: break; case value_types::object_t: var_.value_.object_val_->erase(name.data(),name.length()); break; default: JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object", name); break; } } void set(const string_type& name, const basic_json& value) { switch (var_.type_) { case value_types::empty_object_t: create_object_implicitly(); case value_types::object_t: var_.value_.object_val_->set(name, value); break; default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object", name); } } } void set(string_type&& name, const basic_json& value){ switch (var_.type_){ case value_types::empty_object_t: create_object_implicitly(); case value_types::object_t: var_.value_.object_val_->set(std::move(name),value); break; default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); } } } void set(const string_type& name, basic_json&& value){ switch (var_.type_){ case value_types::empty_object_t: create_object_implicitly(); case value_types::object_t: var_.value_.object_val_->set(name,std::move(value)); break; default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); } } } void set(string_type&& name, basic_json&& value) { switch (var_.type_) { case value_types::empty_object_t: create_object_implicitly(); case value_types::object_t: var_.value_.object_val_->set(std::move(name),std::move(value)); break; default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); } } } object_iterator set(object_iterator hint, const string_type& name, const basic_json& value) { switch (var_.type_) { case value_types::empty_object_t: create_object_implicitly(); case value_types::object_t: return var_.value_.object_val_->set(hint, name, value); break; default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object", name); } } } object_iterator set(object_iterator hint, string_type&& name, const basic_json& value){ switch (var_.type_){ case value_types::empty_object_t: create_object_implicitly(); case value_types::object_t: return var_.value_.object_val_->set(hint, std::move(name),value); break; default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); } } } object_iterator set(object_iterator hint, const string_type& name, basic_json&& value){ switch (var_.type_){ case value_types::empty_object_t: create_object_implicitly(); case value_types::object_t: return var_.value_.object_val_->set(hint, name,std::move(value)); break; default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); } } } object_iterator set(object_iterator hint, string_type&& name, basic_json&& value){ switch (var_.type_){ case value_types::empty_object_t: create_object_implicitly(); case value_types::object_t: return var_.value_.object_val_->set(hint, std::move(name),std::move(value)); break; default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); } } } void add(const basic_json& value) { switch (var_.type_) { case value_types::array_t: var_.value_.array_val_->push_back(value); break; default: { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); } } } void add(basic_json&& value){ switch (var_.type_){ case value_types::array_t: var_.value_.array_val_->push_back(std::move(value)); break; default: { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); } } } array_iterator add(const_array_iterator pos, const basic_json& value) { switch (var_.type_) { case value_types::array_t: return var_.value_.array_val_->add(pos, value); break; default: { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); } } } array_iterator add(const_array_iterator pos, basic_json&& value){ switch (var_.type_){ case value_types::array_t: return var_.value_.array_val_->add(pos, std::move(value)); break; default: { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); } } } value_types type() const { return var_.type_; } uint8_t length_or_precision() const { return var_.length_or_precision_; } void swap(basic_json& b) { var_.swap(b.var_); } template std::vector as_vector() const { std::vector v(size()); for (size_t i = 0; i < v.size(); ++i) { v[i] = json_type_traits::as(at(i)); } return v; } friend void swap(basic_json& a, basic_json& b) { a.swap(b); } void assign_any(const typename basic_json::any& rhs) { var_.assign(rhs); } void assign_string(const string_type& rhs) { var_.assign(rhs); } void assign_string(const char_type* rhs, size_t length) { var_.assign_string(rhs,length); } void assign_bool(bool rhs) { var_.assign(rhs); } void assign_object(const object & rhs) { var_.assign(rhs); } void assign_array(const array& rhs) { var_.assign(rhs); } void assign_null() { var_.assign(null_type()); } template const T& any_cast() const { if (var_.type_ != value_types::any_t) { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad any cast"); } return var_.value_.any_val_->template cast(); } template T& any_cast() { if (var_.type_ != value_types::any_t) { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad any cast"); } return var_.value_.any_val_->template cast(); } void assign_integer(int64_t rhs) { var_.assign(rhs); } void assign_uinteger(uint64_t rhs) { var_.assign(rhs); } void assign_double(double rhs, uint8_t precision = 0) { var_.assign(rhs,precision); } static basic_json make_2d_array(size_t m, size_t n); template static basic_json make_2d_array(size_t m, size_t n, T val); static basic_json make_3d_array(size_t m, size_t n, size_t k); template static basic_json make_3d_array(size_t m, size_t n, size_t k, T val); #if !defined(JSONCONS_NO_DEPRECATED) typedef any json_any_type; static basic_json parse(std::basic_istream& is) { return parse_stream(is); } static basic_json parse(std::basic_istream& is, basic_parse_error_handler& err_handler) { return parse_stream(is,err_handler); } static basic_json parse_string(const string_type& s) { return parse(s); } static basic_json parse_string(const string_type& s, basic_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 members().begin(); } const_object_iterator begin_members() const { return members().begin(); } object_iterator end_members() { return members().end(); } const_object_iterator end_members() const { return members().end(); } array_iterator begin_elements() { return elements().begin(); } const_array_iterator begin_elements() const { return elements().begin(); } array_iterator end_elements() { return elements().end(); } const_array_iterator end_elements() const { return elements().end(); } const basic_json& get(const string_type& name) const { static const basic_json a_null = null_type(); switch (var_.type_) { case value_types::empty_object_t: return a_null; case value_types::object_t: { const_object_iterator it = var_.value_.object_val_->find(name.data(),name.length()); return it != members().end() ? it->value() : a_null; } default: { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); } } } bool is_longlong() const JSONCONS_NOEXCEPT { return var_.type_ == value_types::integer_t; } bool is_ulonglong() const JSONCONS_NOEXCEPT { return var_.type_ == value_types::uinteger_t; } long long as_longlong() const { return as_integer(); } unsigned long long as_ulonglong() const { return as_uinteger(); } int as_int() const { switch (var_.type_) { case value_types::double_t: return static_cast(var_.value_.double_val_); case value_types::integer_t: return static_cast(var_.value_.integer_val_); case value_types::uinteger_t: return static_cast(var_.value_.uinteger_val_); case value_types::bool_t: return var_.value_.bool_val_ ? 1 : 0; default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an int"); } } unsigned int as_uint() const { switch (var_.type_) { case value_types::double_t: return static_cast(var_.value_.double_val_); case value_types::integer_t: return static_cast(var_.value_.integer_val_); case value_types::uinteger_t: return static_cast(var_.value_.uinteger_val_); case value_types::bool_t: return var_.value_.bool_val_ ? 1 : 0; default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an unsigned int"); } } long as_long() const { switch (var_.type_) { case value_types::double_t: return static_cast(var_.value_.double_val_); case value_types::integer_t: return static_cast(var_.value_.integer_val_); case value_types::uinteger_t: return static_cast(var_.value_.uinteger_val_); case value_types::bool_t: return var_.value_.bool_val_ ? 1 : 0; default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not a long"); } } unsigned long as_ulong() const { switch (var_.type_) { case value_types::double_t: return static_cast(var_.value_.double_val_); case value_types::integer_t: return static_cast(var_.value_.integer_val_); case value_types::uinteger_t: return static_cast(var_.value_.uinteger_val_); case value_types::bool_t: return var_.value_.bool_val_ ? 1 : 0; default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an unsigned long"); } } void add(size_t index, const basic_json& value) { switch (var_.type_) { case value_types::array_t: var_.value_.array_val_->add(index, value); break; default: { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); } } } void add(size_t index, basic_json&& value){ switch (var_.type_){ case value_types::array_t: var_.value_.array_val_->add(index, std::move(value)); break; default: { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); } } } bool has_member(const string_type& name) const { switch (var_.type_) { case value_types::object_t: { const_object_iterator it = var_.value_.object_val_->find(name.data(),name.length()); return it != members().end(); } break; default: return false; } } void remove_range(size_t from_index, size_t to_index) { switch (var_.type_) { case value_types::array_t: var_.value_.array_val_->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_type& name) { erase(name.data(),name.length()); } void remove_member(const string_type& name) { erase(name.data(),name.length()); } // Removes a member from an object value bool is_empty() const JSONCONS_NOEXCEPT { return empty(); } bool is_numeric() const JSONCONS_NOEXCEPT { return is_number(); } void assign_longlong(long long rhs) { var_.assign(rhs); } void assign_ulonglong(unsigned long long rhs) { var_.assign(rhs); } 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); } #endif object_range members() { switch (var_.type_) { case value_types::empty_object_t: return object_range(object_iterator(true),object_iterator(true)); case value_types::object_t: return object_range(object_value().begin(),object_value().end()); default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an object"); } } const_object_range members() const { switch (var_.type_) { case value_types::empty_object_t: return const_object_range(const_object_iterator(true),const_object_iterator(true)); case value_types::object_t: return const_object_range(object_value().begin(),object_value().end()); default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an object"); } } array_range elements() { switch (var_.type_) { case value_types::array_t: return array_range(array_value().begin(),array_value().end()); default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an array"); } } const_array_range elements() const { switch (var_.type_) { case value_types::array_t: return const_array_range(array_value().begin(),array_value().end()); default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an array"); } } array& array_value() { switch (var_.type_) { case value_types::array_t: return *(var_.value_.array_val_); default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad array cast"); break; } } const array& array_value() const { switch (var_.type_) { case value_types::array_t: return *(var_.value_.array_val_); default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad array cast"); break; } } object& object_value() { switch (var_.type_) { case value_types::empty_object_t: create_object_implicitly(); case value_types::object_t: return *(var_.value_.object_val_); default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad object cast"); break; } } const object& object_value() const { switch (var_.type_) { case value_types::empty_object_t: const_cast(this)->create_object_implicitly(); // HERE case value_types::object_t: return *(var_.value_.object_val_); default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad object cast"); break; } } private: friend std::basic_ostream& operator<<(std::basic_ostream& os, const basic_json& o) { o.to_stream(os); return os; } friend std::basic_istream& operator<<(std::basic_istream& is, basic_json& o) { basic_json_deserializer> handler; basic_json_reader reader(is, handler); reader.read_next(); reader.check_done(); if (!handler.is_valid()) { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json stream"); } o = handler.get_result(); return is; } }; template void swap(typename JsonT::member_type& a, typename JsonT::member_type& b) { a.swap(b); } template bool basic_json::operator!=(const basic_json& rhs) const { return !(*this == rhs); } template bool basic_json::operator==(const basic_json& rhs) const { return var_ == rhs.var_; } template basic_json basic_json::make_2d_array(size_t m, size_t n) { basic_json a = basic_json::array(); a.resize(m); for (size_t i = 0; i < a.size(); ++i) { a[i] = basic_json::make_array(n); } return a; } template template basic_json basic_json::make_2d_array(size_t m, size_t n, T val) { basic_json v; v = val; basic_json a = make_array(m); for (size_t i = 0; i < a.size(); ++i) { a[i] = basic_json::make_array(n, v); } return a; } template basic_json basic_json::make_3d_array(size_t m, size_t n, size_t k) { basic_json a = basic_json::array(); a.resize(m); for (size_t i = 0; i < a.size(); ++i) { a[i] = basic_json::make_2d_array(n, k); } return a; } template template basic_json basic_json::make_3d_array(size_t m, size_t n, size_t k, T val) { basic_json v; v = val; basic_json a = make_array(m); for (size_t i = 0; i < a.size(); ++i) { a[i] = basic_json::make_2d_array(n, k, v); } return a; } template basic_json basic_json::parse_stream(std::basic_istream& is) { basic_json_deserializer> handler; basic_json_reader reader(is, handler); reader.read_next(); reader.check_done(); if (!handler.is_valid()) { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json stream"); } return handler.get_result(); } template basic_json basic_json::parse_stream(std::basic_istream& is, basic_parse_error_handler& err_handler) { basic_json_deserializer> handler; basic_json_reader reader(is, handler, err_handler); reader.read_next(); reader.check_done(); if (!handler.is_valid()) { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json stream"); } return handler.get_result(); } template basic_json basic_json::parse_file(const std::string& filename) { FILE* fp; #if defined(JSONCONS_HAS_FOPEN_S) errno_t err = fopen_s(&fp, filename.c_str(), "rb"); if (err != 0) { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Cannot open file %s", filename); } #else fp = std::fopen(filename.c_str(), "rb"); if (fp == nullptr) { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Cannot open file %s", filename); } #endif basic_json_deserializer> handler; try { // obtain file size: std::fseek (fp , 0 , SEEK_END); long size = std::ftell (fp); std::rewind(fp); if (size > 0) { std::vector buffer(size); // copy the file into the buffer: size_t result = std::fread (buffer.data(),1,size,fp); if (result != static_cast(size)) { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Error reading file %s", filename); } basic_json_parser parser(handler); parser.begin_parse(); parser.parse(buffer.data(),0,buffer.size()); parser.end_parse(); parser.check_done(buffer.data(),parser.index(),buffer.size()); } std::fclose (fp); } catch (...) { std::fclose (fp); throw; } if (!handler.is_valid()) { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json file"); } return handler.get_result(); } template basic_json basic_json::parse_file(const std::string& filename, basic_parse_error_handler& err_handler) { FILE* fp; #if !defined(JSONCONS_HAS_FOPEN_S) fp = std::fopen(filename.c_str(), "rb"); if (fp == nullptr) { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Cannot open file %s", filename); } #else errno_t err = fopen_s(&fp, filename.c_str(), "rb"); if (err != 0) { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Cannot open file %s", filename); } #endif basic_json_deserializer> handler; try { // obtain file size: std::fseek (fp , 0 , SEEK_END); long size = std::ftell (fp); std::rewind(fp); if (size > 0) { std::vector buffer(size); // copy the file into the buffer: size_t result = std::fread (buffer.data(),1,size,fp); if (result != static_cast(size)) { JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Error reading file %s", filename); } basic_json_parser parser(handler,err_handler); parser.begin_parse(); parser.parse(buffer.data(),0,buffer.size()); parser.end_parse(); parser.check_done(buffer.data(),parser.index(),buffer.size()); } std::fclose (fp); } catch (...) { std::fclose (fp); throw; } if (!handler.is_valid()) { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json file"); } return handler.get_result(); } template typename basic_json::any& basic_json::any_value() { switch (var_.type_) { case value_types::any_t: { return *var_.value_.any_val_; } default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an any value"); } } template const typename basic_json::any& basic_json::any_value() const { switch (var_.type_) { case value_types::any_t: { return *var_.value_.any_val_; } default: JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an any value"); } } template std::basic_istream& operator>>(std::basic_istream& is, JsonT& o) { basic_json_deserializer handler; basic_json_reader reader(is, handler); reader.read_next(); reader.check_done(); if (!handler.is_valid()) { JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json stream"); } o = handler.get_result(); return is; } template class json_printable { public: typedef typename JsonT::char_type char_type; json_printable(const JsonT& o, bool is_pretty_print) : o_(&o), is_pretty_print_(is_pretty_print) { } json_printable(const JsonT& o, bool is_pretty_print, const basic_output_format& format) : o_(&o), is_pretty_print_(is_pretty_print), format_(format) { ; } void to_stream(std::basic_ostream& os) const { o_->to_stream(os, format_, is_pretty_print_); } friend std::basic_ostream& operator<<(std::basic_ostream& os, const json_printable& o) { o.to_stream(os); return os; } const JsonT *o_; bool is_pretty_print_; basic_output_format format_; private: json_printable(); }; template json_printable print(const JsonT& val) { return json_printable(val,false); } template json_printable print(const JsonT& val, const basic_output_format& format) { return json_printable(val, false, format); } template json_printable pretty_print(const JsonT& val) { return json_printable(val,true); } template json_printable pretty_print(const JsonT& val, const basic_output_format& format) { return json_printable(val, true, format); } typedef basic_json> json; typedef basic_json> wjson; typedef basic_json_deserializer json_deserializer; typedef basic_json_deserializer wjson_deserializer; } #if defined(__GNUC__) #pragma GCC diagnostic pop #endif #endif