// The MIT License (MIT) // // Copyright (c) 2013-2014 mashiro // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // clang-format off #ifndef RABBIT_HPP_INCLUDED #define RABBIT_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifndef RABBIT_NAMESPACE #define RABBIT_NAMESPACE rabbit #endif #include #include #include #include #include #include #include #include #include #include #include namespace RABBIT_NAMESPACE { #define RABBIT_TAG_DEF(name, id) \ struct name \ { \ static const rapidjson::Type native_value = id; \ static const int value = id; \ }; \ /**/ RABBIT_TAG_DEF(null_tag, rapidjson::kNullType) RABBIT_TAG_DEF(false_tag, rapidjson::kFalseType) RABBIT_TAG_DEF(true_tag, rapidjson::kTrueType) RABBIT_TAG_DEF(object_tag, rapidjson::kObjectType) RABBIT_TAG_DEF(array_tag, rapidjson::kArrayType) RABBIT_TAG_DEF(string_tag, rapidjson::kStringType) RABBIT_TAG_DEF(number_tag, rapidjson::kNumberType) #undef RABBIT_TAG_DEF class type_mismatch : public std::runtime_error { public: type_mismatch(const std::string& msg) : std::runtime_error(msg) {} }; typedef rapidjson::ParseErrorCode parse_error_code; class parse_error : public std::runtime_error { private: parse_error_code code_; public: parse_error(parse_error_code code) : std::runtime_error(rapidjson::GetParseError_En(code)) , code_(code) {} parse_error_code code() const { return code_; } }; // fwd template class basic_value_ref; template class basic_value; template class basic_object; template class basic_array; namespace details { template struct enable_if_c { typedef T type; }; template struct enable_if_c {}; template struct enable_if : enable_if_c {}; template struct disable_if : enable_if_c {}; template struct bool_ { static const bool value = C; }; typedef bool_ true_; typedef bool_ false_; template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; template struct remove_const { typedef T type; }; template struct remove_const { typedef T type; }; template > class basic_string_ref { public: typedef Char value_type; typedef std::size_t size_type; private: const value_type* data_; size_type length_; public: basic_string_ref() : data_(0) , length_(0) {} basic_string_ref(const basic_string_ref& other) : data_(other.data_) , length_(other.length_) {} basic_string_ref(const value_type* str) : data_(str) , length_(Traits::length(str)) {} basic_string_ref(const value_type* str, size_type length) : data_(str) , length_(length) {} template basic_string_ref(const std::basic_string& other) : data_(other.data()) , length_(other.length()) {} size_type size() const { return length_; } size_type length() const { return length_; } size_type max_size() const { return length_; } bool empty() const { return length_ == 0; } const value_type* data() const { return data_; } }; // type traits template struct is_tag : false_ {}; template <> struct is_tag : true_ {}; template <> struct is_tag : true_ {}; template <> struct is_tag : true_ {}; template <> struct is_tag : true_ {}; template <> struct is_tag : true_ {}; template <> struct is_tag : true_ {}; template <> struct is_tag : true_ {}; template struct is_null : false_ {}; template <> struct is_null : true_ {}; template struct is_false : false_ {}; template <> struct is_false : true_ {}; template struct is_true : false_ {}; template <> struct is_true : true_ {}; template struct is_object : false_ {}; template <> struct is_object : true_ {}; template struct is_object< basic_object > : true_ {}; template struct is_array : false_ {}; template <> struct is_array : true_ {}; template struct is_array< basic_array > : true_ {}; template struct is_string : false_ {}; template <> struct is_string : true_ {}; template struct is_string< std::basic_string > : true_ {}; template struct is_string< basic_string_ref > : true_ {}; template struct is_number : false_ {}; template <> struct is_number : true_ {}; template struct is_bool : false_ {}; template <> struct is_bool : true_ {}; template struct is_int : false_ {}; template <> struct is_int : true_ {}; template struct is_uint : false_ {}; template <> struct is_uint : true_ {}; template struct is_int64 : false_ {}; template <> struct is_int64 : true_ {}; template struct is_uint64 : false_ {}; template <> struct is_uint64 : true_ {}; template struct is_double : false_ {}; template <> struct is_double : true_ {}; template struct is_value_ref : false_ {}; template struct is_value_ref< basic_value_ref > : true_ {}; template struct is_value_ref< basic_value > : true_ {}; template struct is_value_ref< basic_object > : true_ {}; template struct is_value_ref< basic_array > : true_ {}; // type name template const char* type_name(typename enable_if< is_null >::type* = 0) { return "null"; } template const char* type_name(typename enable_if< is_false >::type* = 0) { return "false"; } template const char* type_name(typename enable_if< is_true >::type* = 0) { return "true"; } template const char* type_name(typename enable_if< is_object >::type* = 0) { return "object"; } template const char* type_name(typename enable_if< is_array >::type* = 0) { return "array"; } template const char* type_name(typename enable_if< is_string >::type* = 0) { return "string"; } template const char* type_name(typename enable_if< is_number >::type* = 0) { return "number"; } template const char* type_name(typename enable_if< is_bool >::type* = 0) { return "bool"; } template const char* type_name(typename enable_if< is_int >::type* = 0) { return "int"; } template const char* type_name(typename enable_if< is_uint >::type* = 0) { return "uint"; } template const char* type_name(typename enable_if< is_int64 >::type* = 0) { return "int64"; } template const char* type_name(typename enable_if< is_uint64 >::type* = 0) { return "uint64"; } template const char* type_name(typename enable_if< is_double >::type* = 0) { return "double"; } template const char* type_name(typename enable_if< is_value_ref >::type* = 0) { return "value_ref"; } template struct operator_arrow_proxy { mutable typename remove_const::type value_; operator_arrow_proxy(const PseudoReference& value) : value_(value) {} PseudoReference* operator->() const { return &value_; } }; template struct operator_arrow_proxy { T& value_; operator_arrow_proxy(T& value) : value_(value) {} T* operator->() const { return &value_; } }; template class transform_iterator { typedef std::iterator_traits traits_type; public: typedef transform_iterator this_type; typedef Function function_type; typedef Iterator iterator_type; typedef typename traits_type::iterator_category iterator_category; typedef typename traits_type::difference_type difference_type; typedef typename Function::result_type result_type; typedef typename remove_reference::type value_type; typedef operator_arrow_proxy operator_arrow_proxy_type; typedef operator_arrow_proxy_type pointer; typedef result_type reference; private: iterator_type it_; function_type func_; public: transform_iterator() : it_() , func_() {} explicit transform_iterator(const iterator_type& it) : it_(it) , func_() {} transform_iterator(const iterator_type& it, const function_type& func) : it_(it) , func_(func) {} template transform_iterator(const transform_iterator& other) : it_(other.base()) , func_(other.functor()) {} iterator_type& base() { return it_; } const iterator_type& base() const { return it_; } function_type& functor() { return func_; } const function_type& functor() const { return func_; } result_type dereference() const { return func_(*it_); } result_type operator*() const { return dereference(); } operator_arrow_proxy_type operator->() const { return operator_arrow_proxy_type(dereference()); } this_type& operator++() { ++it_; return *this; } this_type operator++(int) { return this_type(it_++, func_); } this_type& operator--() { --it_; return *this; } this_type operator--(int) { return this_type(it_--, func_); } this_type operator+(difference_type n) const { return this_type(it_ + n, func_); } this_type& operator+=(difference_type n) { it_ += n; return *this; } this_type operator-(difference_type n) const { return this_type(it_ - n, func_); } this_type& operator-=(difference_type n) { it_ -= n; return *this; } result_type operator[](difference_type n) const { return func_(it_[n]); } // Subtraction operator overload is required for std::distance template size_t operator-(const transform_iterator& other) const { return base() - other.base(); } template bool operator==(const transform_iterator& other) const { return base() == other.base(); } template bool operator!=(const transform_iterator& other) const { return base() != other.base(); } template bool operator<(const transform_iterator& other) const { return base() < other.base(); } template bool operator>(const transform_iterator& other) const { return base() > other.base(); } template bool operator<=(const transform_iterator& other) const { return base() <= other.base(); } template bool operator>=(const transform_iterator& other) const { return base() >= other.base(); } }; template transform_iterator make_transform_iterator(Iterator it, Function func = Function()) { return transform_iterator(it, func); } template class member_wrapper { public: typedef Member wrapped_type; typedef ValueRef value_ref_type; typedef typename ValueRef::string_type string_type; typedef typename ValueRef::allocator_type allocator_type; class proxy { wrapped_type& member_; allocator_type* alloc_; public: proxy(wrapped_type& member, allocator_type* alloc) : member_(member) , alloc_(alloc) {} string_type name() const { return value_ref_type(&(member_.name), alloc_).as_string(); } value_ref_type value() const { return value_ref_type(&(member_.value), alloc_); } }; private: allocator_type* alloc_; public: member_wrapper(allocator_type* alloc) : alloc_(alloc) {} template member_wrapper(const member_wrapper& other) : alloc_(other.get_allocator_pointer()) {} typedef proxy result_type; result_type operator()(wrapped_type& member) const { return result_type(member, alloc_); } allocator_type* get_allocator_pointer() const { return alloc_; } }; template class value_wrapper { public: typedef Value wrapped_type; typedef ValueRef value_ref_type; typedef typename ValueRef::string_type string_type; typedef typename ValueRef::allocator_type allocator_type; private: allocator_type* alloc_; public: value_wrapper(allocator_type* alloc) : alloc_(alloc) {} template value_wrapper(const value_wrapper& other) : alloc_(other.get_allocator_pointer()) {} typedef value_ref_type result_type; result_type operator()(wrapped_type& value) const { return result_type(&value, alloc_); } allocator_type* get_allocator_pointer() const { return alloc_; } }; template struct value_ref_traits; template struct const_value_ref_traits; template struct value_ref_traits { typedef Encoding encoding_type; typedef rapidjson::Type native_type; typedef rapidjson::GenericDocument native_document_type; typedef rapidjson::GenericValue native_value_type; typedef typename native_document_type::AllocatorType native_allocator_type; typedef const_value_ref_traits const_traits; template static void set(ValueRef& ref, Tag tag = Tag()) { ref.set(tag); } }; template struct const_value_ref_traits { typedef Encoding encoding_type; typedef const rapidjson::Type native_type; typedef const rapidjson::GenericDocument native_document_type; typedef const rapidjson::GenericValue native_value_type; typedef const typename native_document_type::AllocatorType native_allocator_type; typedef const_value_ref_traits const_traits; template static void set(const ValueRef& ref, Tag tag = Tag()) {} }; template class scoped_ptr { private: T* p_; private: scoped_ptr(const scoped_ptr& other); scoped_ptr& operator=(const scoped_ptr& other); public: explicit scoped_ptr(T* p = 0) : p_(p) {} ~scoped_ptr() { delete p_; } T* operator->() { return p_; } const T* operator->() const { return p_; } T& operator*() { return *p_; } const T& operator*() const { return *p_; } T* get() { return p_; } const T* get() const { return p_; } void swap(scoped_ptr& other) throw() { std::swap(p_, other.p_); } }; } // details template class basic_value_ref { public: typedef Traits traits; typedef typename Traits::const_traits const_traits; typedef typename traits::encoding_type encoding_type; typedef typename traits::native_type native_type; typedef typename traits::native_document_type native_document_type; typedef typename traits::native_value_type native_value_type; typedef typename traits::native_allocator_type native_allocator_type; typedef basic_value_ref value_ref_type; typedef const basic_value_ref const_value_ref_type; typedef typename encoding_type::Ch char_type; typedef std::basic_string string_type; typedef details::basic_string_ref string_ref_type; typedef native_allocator_type allocator_type; private: typedef details::member_wrapper< typename native_value_type::Member, value_ref_type> member_wrapper_type; typedef details::member_wrapper const_member_wrapper_type; typedef details::value_wrapper< native_value_type, value_ref_type> value_wrapper_type; typedef details::value_wrapper const_value_wrapper_type; public: typedef details::transform_iterator< member_wrapper_type, typename native_value_type::MemberIterator> member_iterator; typedef details::transform_iterator const_member_iterator; typedef details::transform_iterator< value_wrapper_type, typename native_value_type::ValueIterator> value_iterator; typedef details::transform_iterator const_value_iterator; private: native_value_type* value_; allocator_type* alloc_; public: basic_value_ref(native_value_type* value = 0, allocator_type* alloc = 0) : value_(value) , alloc_(alloc) {} template basic_value_ref(const basic_value_ref& other) : value_(other.get_native_value_pointer()) , alloc_(other.get_allocator_pointer()) {} native_value_type* get_native_value_pointer() const { return value_; } allocator_type* get_allocator_pointer() const { return alloc_; } allocator_type& get_allocator() const { return *alloc_; } void set(null_tag) { value_->SetNull(); } void set(object_tag) { value_->SetObject(); } void set(array_tag) { value_->SetArray(); } void set(bool value) { value_->SetBool(value); } void set(int value) { value_->SetInt(value); } void set(unsigned value) { value_->SetUint(value); } void set(int64_t value) { value_->SetInt64(value); } void set(uint64_t value) { value_->SetUint64(value); } void set(double value) { value_->SetDouble(value); } void set(const char_type* value) { value_->SetString(value, *alloc_); } void set(const string_type& value) { value_->SetString(value.data(), static_cast(value.length()), *alloc_); } template void set(const T& value, typename details::enable_if< details::is_value_ref >::type* = 0) { if (value.is_null()) set(null_tag()); else if (value.is_bool()) set(value.as_bool()); else if (value.is_int()) set(value.as_int()); else if (value.is_uint()) set(value.as_uint()); else if (value.is_int64()) set(value.as_int64()); else if (value.is_uint64()) set(value.as_uint64()); else if (value.is_double()) set(value.as_double()); else if (value.is_string()) set(value.as_string()); else if (value.is_array()) throw std::runtime_error("can not assign array directly. please use insert"); else if (value.is_object()) throw std::runtime_error("can not assign object directly. please use insert"); } template value_ref_type& operator=(const T& value) { set(value); return *this; } template bool operator==(const basic_value_ref& other) const { if (is_null() && other.is_null()) return true; if (is_bool() && other.is_bool() && as_bool() == other.as_bool()) return true; if (is_int() && other.is_int() && as_int() == other.as_int()) return true; if (is_uint() && other.is_uint() && as_uint() == other.as_uint()) return true; if (is_int64() && other.is_int64() && as_int64() == other.as_int64()) return true; if (is_uint64() && other.is_uint64() && as_uint64() == other.as_uint64()) return true; if (is_double() && other.is_double() && as_double() == other.as_double()) return true; if (is_string() && other.is_string() && as_string() == other.as_string()) return true; return false; } template bool operator!=(const basic_value_ref& other) const { return !(*this == other); } int which() const { return static_cast(value_->GetType()); } #define RABBIT_IS_DEF(name, base_name) \ template \ bool is(typename details::enable_if< details::is_##name >::type* = 0) const \ { \ return value_->Is##base_name(); \ } \ bool is_##name() const \ { \ return value_->Is##base_name(); \ } \ /**/ RABBIT_IS_DEF(null, Null) RABBIT_IS_DEF(false, False) RABBIT_IS_DEF(true, True) RABBIT_IS_DEF(object, Object) RABBIT_IS_DEF(array, Array) RABBIT_IS_DEF(number, Number) RABBIT_IS_DEF(bool, Bool) RABBIT_IS_DEF(int, Int) RABBIT_IS_DEF(uint, Uint) RABBIT_IS_DEF(int64, Int64) RABBIT_IS_DEF(uint64, Uint64) RABBIT_IS_DEF(double, Double) RABBIT_IS_DEF(string, String) #undef RABBIT_IS_DEF #define RABBIT_AS_DEF(result_type, name, base_name) \ template \ T as(typename details::enable_if< details::is_##name >::type* = 0) const \ { \ type_check(); \ return value_->Get##base_name(); \ } \ result_type as_##name() const \ { \ type_check(); \ return value_->Get##base_name(); \ } \ /**/ RABBIT_AS_DEF(bool, bool, Bool) RABBIT_AS_DEF(int, int, Int) RABBIT_AS_DEF(unsigned, uint, Uint) RABBIT_AS_DEF(int64_t, int64, Int64) RABBIT_AS_DEF(uint64_t, uint64, Uint64) RABBIT_AS_DEF(double, double, Double) RABBIT_AS_DEF(string_type, string, String) #undef RABBIT_AS_DEF private: struct as_t { const value_ref_type& ref_; as_t(const value_ref_type& ref) : ref_(ref) {} template operator Result() const { return ref_.as(); } }; public: as_t as() const { return as_t(*this); } bool has(const string_ref_type& name) const { type_check(); return value_->HasMember(name.data()); } template void insert(const string_ref_type& name, const T& value, typename details::disable_if< details::is_value_ref >::type* = 0) { type_check(); native_value_type v(value); value_->AddMember(rapidjson::StringRef(name.data(), name.length()), v, *alloc_); } template void insert(const string_ref_type& name, const T& value, typename details::enable_if< details::is_value_ref >::type* = 0) { type_check(); value_->AddMember(rapidjson::StringRef(name.data(), name.length()), *value.get_native_value_pointer(), *alloc_); } bool erase(const string_ref_type& name) { type_check(); return value_->RemoveMember(name.data()); } value_ref_type at(const string_ref_type& name) { type_check(); if (!has(name)) { native_value_type null; value_->AddMember(rapidjson::StringRef(name.data(), name.length()), null, *alloc_); } return value_ref_type(&((*value_)[name.data()]), alloc_); } const_value_ref_type at(const string_ref_type& name) const { type_check(); if (!has(name)) throw std::out_of_range("not found"); return const_value_ref_type(&((*value_)[name.data()]), alloc_); } value_ref_type operator[](const string_ref_type& name) { return at(name); } const_value_ref_type operator[](const string_ref_type& name) const { return at(name); } member_iterator member_begin() { type_check(); return details::make_transform_iterator(value_->MemberBegin(), member_wrapper_type(alloc_)); } member_iterator member_end() { type_check(); return details::make_transform_iterator(value_->MemberEnd(), member_wrapper_type(alloc_)); } const_member_iterator member_begin() const { type_check(); return details::make_transform_iterator(value_->MemberBegin(), const_member_wrapper_type(alloc_)); } const_member_iterator member_end() const { type_check(); return details::make_transform_iterator(value_->MemberEnd(), const_member_wrapper_type(alloc_)); } const_member_iterator member_cbegin() const { return member_begin(); } const_member_iterator member_cend() const { return member_end(); } std::size_t size() const { type_check(); return value_->Size(); } std::size_t capacity() const { type_check(); return value_->Capacity(); } bool empty() const { type_check(); return value_->Empty(); } value_ref_type at(std::size_t index) { type_check(); range_check(index); return value_ref_type(&((*value_)[index]), alloc_); } const_value_ref_type at(std::size_t index) const { type_check(); range_check(index); return const_value_ref_type(&((*value_)[index]), *alloc_); } value_ref_type operator[](std::size_t index) { return at(index); } const_value_ref_type operator[](std::size_t index) const { return at(index); } template void push_back(const T& value, typename details::disable_if< details::is_value_ref >::type* = 0) { type_check(); native_value_type v(value); value_->PushBack(v, *alloc_); } template void push_back(const T& value, typename details::enable_if< details::is_value_ref >::type* = 0) { type_check(); value_->PushBack(*value.get_native_value_pointer(), *alloc_); } void pop_back() { type_check(); value_->PopBack(); } value_iterator value_begin() { type_check(); return details::make_transform_iterator(value_->Begin(), value_wrapper_type(alloc_)); } value_iterator value_end() { type_check(); return details::make_transform_iterator(value_->End(), value_wrapper_type(alloc_)); } const_value_iterator value_begin() const { type_check(); return details::make_transform_iterator(value_->Begin(), const_value_wrapper_type(alloc_)); } const_value_iterator value_end() const { type_check(); return details::make_transform_iterator(value_->End(), const_value_wrapper_type(alloc_)); } const_value_iterator value_cbegin() const { return value_begin(); } const_value_iterator value_cend() const { return value_end(); } void swap(value_ref_type& other) throw() { std::swap(value_, other.value_); std::swap(alloc_, other.alloc_); } string_type str() const { switch (which()) { case null_tag::value: return "null"; case false_tag::value: return "false"; case true_tag::value: return "true"; case string_tag::value: return as_string(); case number_tag::value: { std::basic_stringstream ss; if (is_int()) ss << as_int(); else if (is_uint()) ss << as_uint(); else if (is_int64()) ss << as_int64(); else if (is_uint64()) ss << as_uint64(); else if (is_double()) ss << as_double(); return ss.str(); } default: { typedef rapidjson::GenericStringBuffer buffer_t; typedef rapidjson::Writer writer_t; buffer_t buffer; writer_t writer(buffer); value_->Accept(writer); return buffer.GetString(); } } } private: template void type_check() const { if (!is()) { std::stringstream ss; ss << "value is not "; ss << details::type_name(); ss << " (which is " << which() << ")"; throw type_mismatch(ss.str()); } } void range_check(std::size_t index) const { if (index >= size()) { std::stringstream ss; ss << "index (which is " << index << ") >= size() (which is " << size() << ")"; throw std::out_of_range(ss.str()); } } }; template struct basic_value_base { typedef basic_value_ref base_type; typedef typename base_type::native_value_type native_value_type; typedef typename base_type::allocator_type allocator_type; details::scoped_ptr value_impl_; details::scoped_ptr alloc_impl_; explicit basic_value_base(native_value_type* value = 0, allocator_type* alloc = 0) : value_impl_(value) , alloc_impl_(alloc) {} }; template class basic_value : private basic_value_base , public basic_value_ref { public: typedef Traits traits; typedef typename Traits::const_traits const_traits; typedef basic_value_base member_type; typedef basic_value_ref base_type; typedef typename base_type::encoding_type encoding_type; typedef typename base_type::native_type native_type; typedef typename base_type::native_document_type native_document_type; typedef typename base_type::native_value_type native_value_type; typedef typename base_type::native_allocator_type native_allocator_type; typedef typename base_type::value_ref_type value_ref_type; typedef typename base_type::const_value_ref_type const_value_ref_type; typedef typename base_type::char_type char_type; typedef typename base_type::string_type string_type; typedef typename base_type::string_ref_type string_ref_type; typedef typename base_type::allocator_type allocator_type; typedef typename base_type::member_iterator member_iterator; typedef typename base_type::const_member_iterator const_member_iterator; typedef typename base_type::value_iterator value_iterator; typedef typename base_type::const_value_iterator const_value_iterator; private: typedef DefaultTag default_tag; public: basic_value() : member_type(new native_value_type(DefaultTag::native_value), new allocator_type()) , base_type(member_type::value_impl_.get(), member_type::alloc_impl_.get()) {} basic_value(allocator_type& alloc) : member_type(new native_value_type(DefaultTag::native_value)) , base_type(member_type::value_impl_.get(), &alloc) {} template basic_value(Tag tag, typename details::enable_if< details::is_tag >::type* = 0) : member_type(new native_value_type(Tag::native_value), new allocator_type()) , base_type(member_type::value_impl_.get(), member_type::alloc_impl_.get()) {} template basic_value(Tag tag, allocator_type& alloc, typename details::enable_if< details::is_tag >::type* = 0) : member_type(new native_value_type(Tag::native_value), &alloc) , base_type(member_type::value_impl_.get(), member_type::alloc_impl_.get()) {} template basic_value(const T& value, typename details::disable_if< details::is_value_ref >::type* = 0) : member_type(new native_value_type(value), new allocator_type()) , base_type(member_type::value_impl_.get(), member_type::alloc_impl_.get()) {} template basic_value(const T& value, allocator_type& alloc, typename details::disable_if< details::is_value_ref >::type* = 0) : member_type(new native_value_type(value)) , base_type(member_type::value_impl_.get(), &alloc) {} basic_value(const basic_value& other) : member_type() , base_type(other) { if (other.is_root_value()) throw std::runtime_error("can not copy root value"); } basic_value& operator=(const basic_value& other) { if (other.is_root_value()) throw std::runtime_error("can not copy root value"); basic_value(other).swap(*this); return *this; } template basic_value(const basic_value_ref& other) : member_type() , base_type(other) { if (base_type::is_null()) traits::set(*this, default_tag()); } template basic_value& operator=(const basic_value_ref& other) { basic_value(other).swap(*this); return *this; } template basic_value& operator=(const T& value) { base_type::set(value); return *this; } void clear() { base_type::set(default_tag()); } void swap(basic_value& other) throw() { base_type::swap(other); member_type::value_impl_.swap(other.value_impl_); member_type::alloc_impl_.swap(other.alloc_impl_); } private: bool is_root_value() const { return member_type::value_impl_.get() != 0 || member_type::alloc_impl_.get() != 0; } }; template class basic_object : public basic_value { public: typedef basic_value base_type; typedef typename base_type::encoding_type encoding_type; typedef typename base_type::native_type native_type; typedef typename base_type::native_document_type native_document_type; typedef typename base_type::native_value_type native_value_type; typedef typename base_type::native_allocator_type native_allocator_type; typedef typename base_type::value_ref_type value_ref_type; typedef typename base_type::const_value_ref_type const_value_ref_type; typedef typename base_type::char_type char_type; typedef typename base_type::string_type string_type; typedef typename base_type::string_ref_type string_ref_type; typedef typename base_type::allocator_type allocator_type; typedef typename base_type::member_iterator iterator; typedef typename base_type::const_member_iterator const_iterator; public: basic_object() : base_type() {} basic_object(allocator_type& alloc) : base_type(alloc) {} basic_object(const basic_object& other) : base_type(other) {} template basic_object(const basic_value_ref& other) : base_type(other) {} iterator begin() { return base_type::member_begin(); } iterator end() { return base_type::member_end(); } const_iterator begin() const { return base_type::member_begin(); } const_iterator end() const { return base_type::member_end(); } const_iterator cbegin() const { return base_type::member_begin(); } const_iterator cend() const { return base_type::member_end(); } }; template class basic_array : public basic_value { public: typedef basic_value base_type; typedef typename base_type::encoding_type encoding_type; typedef typename base_type::native_type native_type; typedef typename base_type::native_document_type native_document_type; typedef typename base_type::native_value_type native_value_type; typedef typename base_type::native_allocator_type native_allocator_type; typedef typename base_type::value_ref_type value_ref_type; typedef typename base_type::const_value_ref_type const_value_ref_type; typedef typename base_type::char_type char_type; typedef typename base_type::string_type string_type; typedef typename base_type::string_ref_type string_ref_type; typedef typename base_type::allocator_type allocator_type; typedef typename base_type::value_iterator iterator; typedef typename base_type::const_value_iterator const_iterator; public: basic_array() : base_type() {} basic_array(allocator_type& alloc) : base_type(alloc) {} template basic_array(const basic_value_ref& other) : base_type(other) {} iterator begin() { return base_type::value_begin(); } iterator end() { return base_type::value_end(); } const_iterator begin() const { return base_type::value_begin(); } const_iterator end() const { return base_type::value_end(); } const_iterator cbegin() const { return base_type::value_begin(); } const_iterator cend() const { return base_type::value_end(); } }; template struct basic_document_base { typedef basic_value_ref base_type; typedef typename base_type::native_document_type native_document_type; details::scoped_ptr document_impl_; explicit basic_document_base(native_document_type* document = 0) : document_impl_(document) {} }; template class basic_document : private basic_document_base , public basic_value_ref { public: typedef basic_document_base member_type; typedef basic_value_ref base_type; typedef typename base_type::encoding_type encoding_type; typedef typename base_type::native_type native_type; typedef typename base_type::native_document_type native_document_type; typedef typename base_type::native_value_type native_value_type; typedef typename base_type::native_allocator_type native_allocator_type; typedef typename base_type::value_ref_type value_ref_type; typedef typename base_type::const_value_ref_type const_value_ref_type; typedef typename base_type::char_type char_type; typedef typename base_type::string_type string_type; typedef typename base_type::string_ref_type string_ref_type; typedef typename base_type::allocator_type allocator_type; private: basic_document(const basic_document&); basic_document& operator=(const basic_document&); public: basic_document() : member_type(new native_document_type()) , base_type(member_type::document_impl_.get(), &(member_type::document_impl_->GetAllocator())) {} void swap(basic_document& other) { base_type::swap(other); member_type::document_impl_.swap(other.document_impl_); } void parse(const string_ref_type& str) { parse<0>(str); } template void parse(const string_ref_type& str) { member_type::document_impl_->template Parse(str.data()); if (member_type::document_impl_->HasParseError()) throw parse_error(member_type::document_impl_->GetParseError()); } // Additional functions - not from original port. These are added with the intention of supporting schema validation void parse(const string_ref_type& str, const string_ref_type& schema) { parse<0>(str, schema); } template void parse(const string_ref_type& str, const string_ref_type& schema) { // Parse schema rapidjson::Document doc; doc.Parse(schema.data()); if(doc.HasParseError()) throw parse_error(doc.GetParseError()); // Construct schema validator rapidjson::SchemaDocument schema_document(doc); rapidjson::SchemaValidator schema_validator(schema_document); // Parse using rabbit style parse call member_type::document_impl_->template Parse(str.data()); if (member_type::document_impl_->HasParseError()) throw parse_error(member_type::document_impl_->GetParseError()); // Validate using rapidjson schema validator if(!member_type::document_impl_->Accept(schema_validator)) { if (member_type::document_impl_->HasParseError()) throw parse_error(member_type::document_impl_->GetParseError()); else throw parse_error(rapidjson::kParseErrorUnspecificSyntaxError); } } }; template void swap(basic_value_ref& a, basic_value_ref& b) { a.swap(b); } template void swap(basic_value& a, basic_value& b) { a.swap(b); } template void swap(basic_object& a, basic_object& b) { a.swap(b); } template void swap(basic_array& a, basic_array& b) { a.swap(b); } template void swap(basic_document& a, basic_document& b) { a.swap(b); } template typename basic_value_ref::string_type str(const basic_value_ref& value) { return value.str(); } template std::basic_ostream& operator<<(std::basic_ostream& os, const basic_value_ref& value) { os << str(value); return os; } typedef rapidjson::UTF8<> default_encoding; template struct types { typedef details::value_ref_traits traits; typedef details::const_value_ref_traits const_traits; typedef basic_value_ref value_ref; typedef const basic_value_ref const_value_ref; typedef basic_value value; typedef const basic_value const_value; typedef basic_object object; typedef const basic_object const_object; typedef basic_array array; typedef const basic_array const_array; typedef basic_document document; typedef const basic_document const_document; typedef typename document::allocator_type allocator; }; typedef types<>::value_ref value_ref; typedef types<>::const_value_ref const_value_ref; typedef types<>::value value; typedef types<>::const_value const_value; typedef types<>::object object; typedef types<>::const_object const_object; typedef types<>::array array; typedef types<>::const_array const_array; typedef types<>::document document; typedef types<>::const_document const_document; typedef types<>::allocator allocator; } #endif