mirror of
				https://github.com/Tencent/rapidjson.git
				synced 2025-10-29 20:59:48 +01:00 
			
		
		
		
	Resolve conflicts
This commit is contained in:
		| @@ -2,17 +2,17 @@ | |||||||
|  |  | ||||||
| ## Status: experimental, shall be included in v1.1 | ## Status: experimental, shall be included in v1.1 | ||||||
|  |  | ||||||
| JSON Schema is a draft standard for describing format of JSON. The schema itself is also a JSON. By validating a JSON with JSON Schema, your code can safely access the DOM without manually checking types, or whether a key exists, etc. It can also ensure that the serialized JSON conform to a specified schema. | JSON Schema is a draft standard for describing the format of JSON data. The schema itself is also JSON data. By validating a JSON structure with JSON Schema, your code can safely access the DOM without manually checking types, or whether a key exists, etc. It can also ensure that the serialized JSON conform to a specified schema. | ||||||
|  |  | ||||||
| RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http://json-schema.org/documentation.html). If you do not familiar with JSON Schema, you may refer to [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/). | RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http://json-schema.org/documentation.html). If you are not familiar with JSON Schema, you may refer to [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/). | ||||||
|  |  | ||||||
| [TOC] | [TOC] | ||||||
|  |  | ||||||
| ## Basic Usage | ## Basic Usage | ||||||
|  |  | ||||||
| First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into `SchemaDocument`. | First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into a `SchemaDocument`. | ||||||
|  |  | ||||||
| Secondly, construct a `SchemaValidator` with the `SchedmaDocument`. It is similar to a `Writer` in the sense of handling SAX events. So, you can use `document.Accept(validator)` to validate a document, and then check the validity. | Secondly, construct a `SchemaValidator` with the `SchemaDocument`. It is similar to a `Writer` in the sense of handling SAX events. So, you can use `document.Accept(validator)` to validate a document, and then check the validity. | ||||||
|  |  | ||||||
| ~~~cpp | ~~~cpp | ||||||
| #include "rapidjson/schema.h" | #include "rapidjson/schema.h" | ||||||
| @@ -54,7 +54,7 @@ Some notes: | |||||||
|  |  | ||||||
| ## Validation during parsing/serialization | ## Validation during parsing/serialization | ||||||
|  |  | ||||||
| Differ to most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files. | Unlike most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files. | ||||||
|  |  | ||||||
| ### DOM parsing | ### DOM parsing | ||||||
|  |  | ||||||
| @@ -111,7 +111,7 @@ if (!reader.Parse(stream, validator)) { | |||||||
| } | } | ||||||
| ~~~ | ~~~ | ||||||
|  |  | ||||||
| This is exactly the method used in [schemavalidator](example/schemavalidator/schemavalidator.cpp) example. The distinct advantage is low memory usage, no matter how big the JSON was (the memory usage depends on the complexity of the schema). | This is exactly the method used in the [schemavalidator](example/schemavalidator/schemavalidator.cpp) example. The distinct advantage is low memory usage, no matter how big the JSON was (the memory usage depends on the complexity of the schema). | ||||||
|  |  | ||||||
| If you need to handle the SAX events further, then you need to use the template class `GenericSchemaValidator` to set the output handler of the validator: | If you need to handle the SAX events further, then you need to use the template class `GenericSchemaValidator` to set the output handler of the validator: | ||||||
|  |  | ||||||
| @@ -213,7 +213,7 @@ For C++11 compiler, it is also possible to use the `std::regex` by defining `RAP | |||||||
|  |  | ||||||
| ## Performance | ## Performance | ||||||
|  |  | ||||||
| Most C++ JSON libraries have not yet supporting JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js. | Most C++ JSON libraries do not yet support JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js. | ||||||
|  |  | ||||||
| That benchmark runs validations on [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite), in which some test suites and tests are excluded. We made the same benchmarking procedure in [`schematest.cpp`](test/perftest/schematest.cpp). | That benchmark runs validations on [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite), in which some test suites and tests are excluded. We made the same benchmarking procedure in [`schematest.cpp`](test/perftest/schematest.cpp). | ||||||
|  |  | ||||||
|   | |||||||
| @@ -393,6 +393,127 @@ template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {}; | |||||||
|  |  | ||||||
| } // namespace internal | } // namespace internal | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // TypeHelper | ||||||
|  |  | ||||||
|  | namespace internal { | ||||||
|  |  | ||||||
|  | template <typename ValueType, typename T> | ||||||
|  | struct TypeHelper {}; | ||||||
|  |  | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, bool> { | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsBool(); } | ||||||
|  |     static bool Get(const ValueType& v) { return v.GetBool(); } | ||||||
|  |     static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } | ||||||
|  |     static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, int> { | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsInt(); } | ||||||
|  |     static int Get(const ValueType& v) { return v.GetInt(); } | ||||||
|  |     static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } | ||||||
|  |     static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, unsigned> { | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsUint(); } | ||||||
|  |     static unsigned Get(const ValueType& v) { return v.GetUint(); } | ||||||
|  |     static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } | ||||||
|  |     static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, int64_t> { | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsInt64(); } | ||||||
|  |     static int64_t Get(const ValueType& v) { return v.GetInt64(); } | ||||||
|  |     static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } | ||||||
|  |     static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, uint64_t> { | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsUint64(); } | ||||||
|  |     static uint64_t Get(const ValueType& v) { return v.GetUint64(); } | ||||||
|  |     static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } | ||||||
|  |     static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, double> { | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsDouble(); } | ||||||
|  |     static double Get(const ValueType& v) { return v.GetDouble(); } | ||||||
|  |     static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } | ||||||
|  |     static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, float> { | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsFloat(); } | ||||||
|  |     static float Get(const ValueType& v) { return v.GetFloat(); } | ||||||
|  |     static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } | ||||||
|  |     static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, const typename ValueType::Ch*> { | ||||||
|  |     typedef const typename ValueType::Ch* StringType; | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsString(); } | ||||||
|  |     static StringType Get(const ValueType& v) { return v.GetString(); } | ||||||
|  |     static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } | ||||||
|  |     static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_STDSTRING | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > { | ||||||
|  |     typedef std::basic_string<typename ValueType::Ch> StringType; | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsString(); } | ||||||
|  |     static StringType Get(const ValueType& v) { return v.GetString(); } | ||||||
|  |     static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, typename ValueType::Array> { | ||||||
|  |     typedef typename ValueType::Array ArrayType; | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsArray(); } | ||||||
|  |     static ArrayType Get(ValueType& v) { return v.GetArray(); } | ||||||
|  |     static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } | ||||||
|  |     static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, typename ValueType::ConstArray> { | ||||||
|  |     typedef typename ValueType::ConstArray ArrayType; | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsArray(); } | ||||||
|  |     static ArrayType Get(const ValueType& v) { return v.GetArray(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, typename ValueType::Object> { | ||||||
|  |     typedef typename ValueType::Object ObjectType; | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsObject(); } | ||||||
|  |     static ObjectType Get(ValueType& v) { return v.GetObject(); } | ||||||
|  |     static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } | ||||||
|  |     static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename ValueType>  | ||||||
|  | struct TypeHelper<ValueType, typename ValueType::ConstObject> { | ||||||
|  |     typedef typename ValueType::ConstObject ObjectType; | ||||||
|  |     static bool Is(const ValueType& v) { return v.IsObject(); } | ||||||
|  |     static ObjectType Get(const ValueType& v) { return v.GetObject(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace internal | ||||||
|  |  | ||||||
|  | // Forward declarations | ||||||
|  | template <bool, typename> class GenericArray; | ||||||
|  | template <bool, typename> class GenericObject; | ||||||
|  |  | ||||||
| /////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||||||
| // GenericValue | // GenericValue | ||||||
|  |  | ||||||
| @@ -420,6 +541,10 @@ public: | |||||||
|     typedef GenericValue* ValueIterator;            //!< Value iterator for iterating in array. |     typedef GenericValue* ValueIterator;            //!< Value iterator for iterating in array. | ||||||
|     typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. |     typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. | ||||||
|     typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of itself. |     typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of itself. | ||||||
|  |     typedef GenericArray<false, ValueType> Array; | ||||||
|  |     typedef GenericArray<true, ValueType> ConstArray; | ||||||
|  |     typedef GenericObject<false, ValueType> Object; | ||||||
|  |     typedef GenericObject<true, ValueType> ConstObject; | ||||||
|  |  | ||||||
|     //!@name Constructors and destructor. |     //!@name Constructors and destructor. | ||||||
|     //@{ |     //@{ | ||||||
| @@ -557,6 +682,28 @@ public: | |||||||
|     GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } |     GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |     //! Constructor for Array. | ||||||
|  |     /*! | ||||||
|  |         \param a An array obtained by \c GetArray(). | ||||||
|  |         \note \c Array is always pass-by-value. | ||||||
|  |         \note the source array is moved into this value and the sourec array becomes empty. | ||||||
|  |     */ | ||||||
|  |     GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { | ||||||
|  |         a.value_.data_ = Data(); | ||||||
|  |         a.value_.data_.f.flags = kArrayFlag; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //! Constructor for Object. | ||||||
|  |     /*! | ||||||
|  |         \param o An object obtained by \c GetObject(). | ||||||
|  |         \note \c Object is always pass-by-value. | ||||||
|  |         \note the source object is moved into this value and the sourec object becomes empty. | ||||||
|  |     */ | ||||||
|  |     GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { | ||||||
|  |         o.value_.data_ = Data(); | ||||||
|  |         o.value_.data_.f.flags = kObjectFlag; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     //! Destructor. |     //! Destructor. | ||||||
|     /*! Need to destruct elements of array, members of object, or copy-string. |     /*! Need to destruct elements of array, members of object, or copy-string. | ||||||
|     */ |     */ | ||||||
| @@ -1024,7 +1171,7 @@ public: | |||||||
|         RAPIDJSON_ASSERT(IsObject()); |         RAPIDJSON_ASSERT(IsObject()); | ||||||
|         RAPIDJSON_ASSERT(name.IsString()); |         RAPIDJSON_ASSERT(name.IsString()); | ||||||
|  |  | ||||||
|         Object& o = data_.o; |         ObjectData& o = data_.o; | ||||||
|         if (o.size >= o.capacity) { |         if (o.size >= o.capacity) { | ||||||
|             if (o.capacity == 0) { |             if (o.capacity == 0) { | ||||||
|                 o.capacity = kDefaultObjectCapacity; |                 o.capacity = kDefaultObjectCapacity; | ||||||
| @@ -1292,6 +1439,9 @@ public: | |||||||
|             return false; |             return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } | ||||||
|  |     ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } | ||||||
|  |  | ||||||
|     //@} |     //@} | ||||||
|  |  | ||||||
|     //!@name Array |     //!@name Array | ||||||
| @@ -1468,6 +1618,9 @@ public: | |||||||
|         return pos; |         return pos; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } | ||||||
|  |     ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } | ||||||
|  |  | ||||||
|     //@} |     //@} | ||||||
|  |  | ||||||
|     //!@name Number |     //!@name Number | ||||||
| @@ -1565,6 +1718,30 @@ public: | |||||||
|  |  | ||||||
|     //@} |     //@} | ||||||
|  |  | ||||||
|  |     //!@name Array | ||||||
|  |     //@{ | ||||||
|  |  | ||||||
|  |     //! Templated version for checking whether this value is type T. | ||||||
|  |     /*! | ||||||
|  |         \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string<Ch> | ||||||
|  |     */ | ||||||
|  |     template <typename T> | ||||||
|  |     bool Is() const { return internal::TypeHelper<ValueType, T>::Is(*this); } | ||||||
|  |  | ||||||
|  |     template <typename T> | ||||||
|  |     T Get() const { return internal::TypeHelper<ValueType, T>::Get(*this); } | ||||||
|  |  | ||||||
|  |     template <typename T> | ||||||
|  |     T Get() { return internal::TypeHelper<ValueType, T>::Get(*this); } | ||||||
|  |  | ||||||
|  |     template<typename T> | ||||||
|  |     ValueType& Set(const T& data) { return internal::TypeHelper<ValueType, T>::Set(*this, data); } | ||||||
|  |  | ||||||
|  |     template<typename T> | ||||||
|  |     ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper<ValueType, T>::Set(*this, data, allocator); } | ||||||
|  |  | ||||||
|  |     //@} | ||||||
|  |  | ||||||
|     //! Generate events of this value to a Handler. |     //! Generate events of this value to a Handler. | ||||||
|     /*! This function adopts the GoF visitor pattern. |     /*! This function adopts the GoF visitor pattern. | ||||||
|         Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. |         Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. | ||||||
| @@ -1710,13 +1887,13 @@ private: | |||||||
|         double d; |         double d; | ||||||
|     };  // 8 bytes |     };  // 8 bytes | ||||||
|  |  | ||||||
|     struct Object { |     struct ObjectData { | ||||||
|         SizeType size; |         SizeType size; | ||||||
|         SizeType capacity; |         SizeType capacity; | ||||||
|         Member* members; |         Member* members; | ||||||
|     };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode |     };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode | ||||||
|  |  | ||||||
|     struct Array { |     struct ArrayData { | ||||||
|         SizeType size; |         SizeType size; | ||||||
|         SizeType capacity; |         SizeType capacity; | ||||||
|         GenericValue* elements; |         GenericValue* elements; | ||||||
| @@ -1726,8 +1903,8 @@ private: | |||||||
|         String s; |         String s; | ||||||
|         ShortString ss; |         ShortString ss; | ||||||
|         Number n; |         Number n; | ||||||
|         Object o; |         ObjectData o; | ||||||
|         Array a; |         ArrayData a; | ||||||
|         Flag f; |         Flag f; | ||||||
|     };  // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION |     };  // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION | ||||||
|  |  | ||||||
| @@ -2194,6 +2371,145 @@ GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,Sourc | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //! Helper class for accessing Value of array type. | ||||||
|  | /*! | ||||||
|  |     Instance of this helper class is obtained by \c GenericValue::GetArray(). | ||||||
|  |     In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. | ||||||
|  | */ | ||||||
|  | template <bool Const, typename ValueT> | ||||||
|  | class GenericArray { | ||||||
|  | public: | ||||||
|  |     typedef GenericArray<true, ValueT> ConstArray; | ||||||
|  |     typedef GenericArray<false, ValueT> Array; | ||||||
|  |     typedef ValueT PlainType; | ||||||
|  |     typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType; | ||||||
|  |     typedef ValueType* ValueIterator;  // This may be const or non-const iterator | ||||||
|  |     typedef const ValueT* ConstValueIterator; | ||||||
|  |     typedef typename ValueType::AllocatorType AllocatorType; | ||||||
|  |     typedef typename ValueType::StringRefType StringRefType; | ||||||
|  |  | ||||||
|  |     template <typename, typename> | ||||||
|  |     friend class GenericValue; | ||||||
|  |  | ||||||
|  |     GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} | ||||||
|  |     GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } | ||||||
|  |     ~GenericArray() {} | ||||||
|  |  | ||||||
|  |     SizeType Size() const { return value_.Size(); } | ||||||
|  |     SizeType Capacity() const { return value_.Capacity(); } | ||||||
|  |     bool Empty() const { return value_.Empty(); } | ||||||
|  |     void Clear() const { value_.Clear(); } | ||||||
|  |     ValueType& operator[](SizeType index) const {  return value_[index]; } | ||||||
|  |     ValueIterator Begin() const { return value_.Begin(); } | ||||||
|  |     ValueIterator End() const { return value_.End(); } | ||||||
|  |     GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } | ||||||
|  |     GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } | ||||||
|  | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||||
|  |     GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } | ||||||
|  | #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||||
|  |     GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } | ||||||
|  |     template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } | ||||||
|  |     GenericArray PopBack() const { value_.PopBack(); return *this; } | ||||||
|  |     ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } | ||||||
|  |     ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_CXX11_RANGE_FOR | ||||||
|  |     ValueIterator begin() const { return value_.Begin(); } | ||||||
|  |     ValueIterator end() const { return value_.End(); } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     GenericArray(); | ||||||
|  |     GenericArray(ValueType& value) : value_(value) {} | ||||||
|  |     ValueType& value_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //! Helper class for accessing Value of array type. | ||||||
|  | /*! | ||||||
|  |     Instance of this helper class is obtained by \c GenericValue::GetArray(). | ||||||
|  |     In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. | ||||||
|  | */ | ||||||
|  | template <bool Const, typename ValueT> | ||||||
|  | class GenericObject { | ||||||
|  | public: | ||||||
|  |     typedef GenericObject<true, ValueT> ConstObject; | ||||||
|  |     typedef GenericObject<false, ValueT> Object; | ||||||
|  |     typedef ValueT PlainType; | ||||||
|  |     typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType; | ||||||
|  |     typedef GenericMemberIterator<Const, typename ValueT::EncodingType, typename ValueT::AllocatorType> MemberIterator;  // This may be const or non-const iterator | ||||||
|  |     typedef GenericMemberIterator<true, typename ValueT::EncodingType, typename ValueT::AllocatorType> ConstMemberIterator; | ||||||
|  |     typedef typename ValueType::AllocatorType AllocatorType; | ||||||
|  |     typedef typename ValueType::StringRefType StringRefType; | ||||||
|  |     typedef typename ValueType::EncodingType EncodingType; | ||||||
|  |     typedef typename ValueType::Ch Ch; | ||||||
|  |  | ||||||
|  |     template <typename, typename> | ||||||
|  |     friend class GenericValue; | ||||||
|  |  | ||||||
|  |     GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} | ||||||
|  |     GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } | ||||||
|  |     ~GenericObject() {} | ||||||
|  |  | ||||||
|  |     SizeType MemberCount() const { return value_.MemberCount(); } | ||||||
|  |     bool ObjectEmpty() const { return value_.ObjectEmpty(); } | ||||||
|  |     template <typename T> ValueType& operator[](T* name) const { return value_[name]; } | ||||||
|  |     template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; } | ||||||
|  | #if RAPIDJSON_HAS_STDSTRING | ||||||
|  |     ValueType& operator[](const std::basic_string<Ch>& name) const { return value_[name]; } | ||||||
|  | #endif | ||||||
|  |     MemberIterator MemberBegin() const { return value_.MemberBegin(); } | ||||||
|  |     MemberIterator MemberEnd() const { return value_.MemberEnd(); } | ||||||
|  |     bool HasMember(const Ch* name) const { return value_.HasMember(name); } | ||||||
|  | #if RAPIDJSON_HAS_STDSTRING | ||||||
|  |     bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); } | ||||||
|  | #endif | ||||||
|  |     template <typename SourceAllocator> bool HasMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.HasMember(name); } | ||||||
|  |     MemberIterator FindMember(const Ch* name) const { value_.FindMember(name); } | ||||||
|  |     template <typename SourceAllocator> MemberIterator FindMember(const GenericValue<EncodingType, SourceAllocator>& name) const { value_.FindMember(name); } | ||||||
|  | #if RAPIDJSON_HAS_STDSTRING | ||||||
|  |     MemberIterator FindMember(const std::basic_string<Ch>& name) const { return value_.FindMember(name); } | ||||||
|  | #endif | ||||||
|  |     GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||||
|  |     GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||||
|  | #if RAPIDJSON_HAS_STDSTRING | ||||||
|  |     GenericObject AddMember(ValueType& name, std::basic_string<Ch>& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||||
|  | #endif | ||||||
|  |     template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||||
|  | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||||
|  |     GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||||
|  |     GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||||
|  |     GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||||
|  |     GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||||
|  | #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||||
|  |     GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||||
|  |     GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||||
|  |     template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||||
|  |     void RemoveAllMembers() { return value_.RemoveAllMembers(); } | ||||||
|  |     bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } | ||||||
|  | #if RAPIDJSON_HAS_STDSTRING | ||||||
|  |     bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.RemoveMember(name); } | ||||||
|  | #endif | ||||||
|  |     template <typename SourceAllocator> bool RemoveMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.RemoveMember(name); } | ||||||
|  |     MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } | ||||||
|  |     MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } | ||||||
|  |     MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } | ||||||
|  |     bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } | ||||||
|  | #if RAPIDJSON_HAS_STDSTRING | ||||||
|  |     bool EraseMember(const std::basic_string<Ch>& name) const { return EraseMember(ValueType(StringRef(name))); } | ||||||
|  | #endif | ||||||
|  |     template <typename SourceAllocator> bool EraseMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.EraseMember(name); } | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_CXX11_RANGE_FOR | ||||||
|  |     MemberIterator begin() const { return value_.MemberBegin(); } | ||||||
|  |     MemberIterator end() const { return value_.MemberEnd(); } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     GenericObject(); | ||||||
|  |     GenericObject(ValueType& value) : value_(value) {} | ||||||
|  |     ValueType& value_; | ||||||
|  | }; | ||||||
|  |  | ||||||
| RAPIDJSON_NAMESPACE_END | RAPIDJSON_NAMESPACE_END | ||||||
|  |  | ||||||
| #ifdef _MSC_VER | #ifdef _MSC_VER | ||||||
|   | |||||||
| @@ -561,6 +561,17 @@ RAPIDJSON_NAMESPACE_END | |||||||
| #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 | #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR | ||||||
|  | #if defined(__clang__) | ||||||
|  | #define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) | ||||||
|  | #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ | ||||||
|  |       (defined(_MSC_VER) && _MSC_VER >= 1600) | ||||||
|  | #define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 | ||||||
|  | #else | ||||||
|  | #define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 | ||||||
|  | #endif | ||||||
|  | #endif // RAPIDJSON_HAS_CXX11_RANGE_FOR | ||||||
|  |  | ||||||
| //!@endcond | //!@endcond | ||||||
|  |  | ||||||
| /////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||||||
|   | |||||||
| @@ -347,6 +347,12 @@ TEST(Value, True) { | |||||||
|     Value z; |     Value z; | ||||||
|     z.SetBool(true); |     z.SetBool(true); | ||||||
|     EXPECT_TRUE(z.IsTrue()); |     EXPECT_TRUE(z.IsTrue()); | ||||||
|  |  | ||||||
|  |     // Templated functions | ||||||
|  |     EXPECT_TRUE(z.Is<bool>()); | ||||||
|  |     EXPECT_TRUE(z.Get<bool>()); | ||||||
|  |     EXPECT_FALSE(z.Set<bool>(false).Get<bool>()); | ||||||
|  |     EXPECT_TRUE(z.Set(true).Get<bool>()); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST(Value, False) { | TEST(Value, False) { | ||||||
| @@ -426,6 +432,12 @@ TEST(Value, Int) { | |||||||
|     // operator=(int) |     // operator=(int) | ||||||
|     z = 5678; |     z = 5678; | ||||||
|     EXPECT_EQ(5678, z.GetInt()); |     EXPECT_EQ(5678, z.GetInt()); | ||||||
|  |  | ||||||
|  |     // Templated functions | ||||||
|  |     EXPECT_TRUE(z.Is<int>()); | ||||||
|  |     EXPECT_EQ(5678, z.Get<int>()); | ||||||
|  |     EXPECT_EQ(5679, z.Set(5679).Get<int>()); | ||||||
|  |     EXPECT_EQ(5680, z.Set<int>(5680).Get<int>()); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST(Value, Uint) { | TEST(Value, Uint) { | ||||||
| @@ -465,6 +477,12 @@ TEST(Value, Uint) { | |||||||
|     EXPECT_EQ(2147483648u, z.GetUint()); |     EXPECT_EQ(2147483648u, z.GetUint()); | ||||||
|     EXPECT_FALSE(z.IsInt()); |     EXPECT_FALSE(z.IsInt()); | ||||||
|     EXPECT_TRUE(z.IsInt64());   // Issue 41: Incorrect parsing of unsigned int number types |     EXPECT_TRUE(z.IsInt64());   // Issue 41: Incorrect parsing of unsigned int number types | ||||||
|  |  | ||||||
|  |     // Templated functions | ||||||
|  |     EXPECT_TRUE(z.Is<unsigned>()); | ||||||
|  |     EXPECT_EQ(2147483648u, z.Get<unsigned>()); | ||||||
|  |     EXPECT_EQ(2147483649u, z.Set(2147483649u).Get<unsigned>()); | ||||||
|  |     EXPECT_EQ(2147483650u, z.Set<unsigned>(2147483650u).Get<unsigned>()); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST(Value, Int64) { | TEST(Value, Int64) { | ||||||
| @@ -517,8 +535,15 @@ TEST(Value, Int64) { | |||||||
|     EXPECT_FALSE(z.IsInt()); |     EXPECT_FALSE(z.IsInt()); | ||||||
|     EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0); |     EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0); | ||||||
|  |  | ||||||
|     z.SetInt64(static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 00000000))); |     int64_t i = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 00000000)); | ||||||
|  |     z.SetInt64(i); | ||||||
|     EXPECT_DOUBLE_EQ(-9223372036854775808.0, z.GetDouble()); |     EXPECT_DOUBLE_EQ(-9223372036854775808.0, z.GetDouble()); | ||||||
|  |  | ||||||
|  |     // Templated functions | ||||||
|  |     EXPECT_TRUE(z.Is<int64_t>()); | ||||||
|  |     EXPECT_EQ(i, z.Get<int64_t>()); | ||||||
|  |     EXPECT_EQ(i - 1, z.Set(i - 1).Get<int64_t>()); | ||||||
|  |     EXPECT_EQ(i - 2, z.Set<int64_t>(i - 2).Get<int64_t>()); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST(Value, Uint64) { | TEST(Value, Uint64) { | ||||||
| @@ -559,10 +584,17 @@ TEST(Value, Uint64) { | |||||||
|     EXPECT_FALSE(z.IsUint()); |     EXPECT_FALSE(z.IsUint()); | ||||||
|     EXPECT_TRUE(z.IsInt64()); |     EXPECT_TRUE(z.IsInt64()); | ||||||
|  |  | ||||||
|     z.SetUint64(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000));    // 2^63 cannot cast as int64 |     uint64_t u = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); | ||||||
|  |     z.SetUint64(u);    // 2^63 cannot cast as int64 | ||||||
|     EXPECT_FALSE(z.IsInt64()); |     EXPECT_FALSE(z.IsInt64()); | ||||||
|     EXPECT_EQ(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000), z.GetUint64()); // Issue 48 |     EXPECT_EQ(u, z.GetUint64()); // Issue 48 | ||||||
|     EXPECT_DOUBLE_EQ(9223372036854775808.0, z.GetDouble()); |     EXPECT_DOUBLE_EQ(9223372036854775808.0, z.GetDouble()); | ||||||
|  |  | ||||||
|  |     // Templated functions | ||||||
|  |     EXPECT_TRUE(z.Is<uint64_t>()); | ||||||
|  |     EXPECT_EQ(u, z.Get<uint64_t>()); | ||||||
|  |     EXPECT_EQ(u + 1, z.Set(u + 1).Get<uint64_t>()); | ||||||
|  |     EXPECT_EQ(u + 2, z.Set<uint64_t>(u + 2).Get<uint64_t>()); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST(Value, Double) { | TEST(Value, Double) { | ||||||
| @@ -589,6 +621,12 @@ TEST(Value, Double) { | |||||||
|  |  | ||||||
|     z = 56.78; |     z = 56.78; | ||||||
|     EXPECT_NEAR(56.78, z.GetDouble(), 0.0); |     EXPECT_NEAR(56.78, z.GetDouble(), 0.0); | ||||||
|  |  | ||||||
|  |     // Templated functions | ||||||
|  |     EXPECT_TRUE(z.Is<double>()); | ||||||
|  |     EXPECT_EQ(56.78, z.Get<double>()); | ||||||
|  |     EXPECT_EQ(57.78, z.Set(57.78).Get<double>()); | ||||||
|  |     EXPECT_EQ(58.78, z.Set<double>(58.78).Get<double>()); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST(Value, Float) { | TEST(Value, Float) { | ||||||
| @@ -616,6 +654,12 @@ TEST(Value, Float) { | |||||||
|  |  | ||||||
|     z = 56.78f; |     z = 56.78f; | ||||||
|     EXPECT_NEAR(56.78f, z.GetFloat(), 0.0f); |     EXPECT_NEAR(56.78f, z.GetFloat(), 0.0f); | ||||||
|  |  | ||||||
|  |     // Templated functions | ||||||
|  |     EXPECT_TRUE(z.Is<float>()); | ||||||
|  |     EXPECT_EQ(56.78f, z.Get<float>()); | ||||||
|  |     EXPECT_EQ(57.78f, z.Set(57.78f).Get<float>()); | ||||||
|  |     EXPECT_EQ(58.78f, z.Set<float>(58.78f).Get<float>()); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST(Value, IsLosslessDouble) { | TEST(Value, IsLosslessDouble) { | ||||||
| @@ -736,6 +780,11 @@ TEST(Value, String) { | |||||||
|     EXPECT_STREQ("World", w.GetString()); |     EXPECT_STREQ("World", w.GetString()); | ||||||
|     EXPECT_EQ(5u, w.GetStringLength()); |     EXPECT_EQ(5u, w.GetStringLength()); | ||||||
|  |  | ||||||
|  |     // templated functions | ||||||
|  |     EXPECT_TRUE(z.Is<const char*>()); | ||||||
|  |     EXPECT_STREQ(cstr, z.Get<const char*>()); | ||||||
|  |     EXPECT_STREQ("Apple", z.Set<const char*>("Apple").Get<const char*>()); | ||||||
|  |  | ||||||
| #if RAPIDJSON_HAS_STDSTRING | #if RAPIDJSON_HAS_STDSTRING | ||||||
|     { |     { | ||||||
|         std::string str = "Hello World"; |         std::string str = "Hello World"; | ||||||
| @@ -771,6 +820,14 @@ TEST(Value, String) { | |||||||
|         vs1 = StringRef(str); |         vs1 = StringRef(str); | ||||||
|         TestEqual(str, vs1); |         TestEqual(str, vs1); | ||||||
|         TestEqual(vs0, vs1); |         TestEqual(vs0, vs1); | ||||||
|  |  | ||||||
|  |         // Templated function. | ||||||
|  |         EXPECT_TRUE(vs0.Is<std::string>()); | ||||||
|  |         EXPECT_EQ(str, vs0.Get<std::string>()); | ||||||
|  |         vs0.Set<std::string>(std::string("Apple"), allocator); | ||||||
|  |         EXPECT_EQ(std::string("Apple"), vs0.Get<std::string>()); | ||||||
|  |         vs0.Set(std::string("Orange"), allocator); | ||||||
|  |         EXPECT_EQ(std::string("Orange"), vs0.Get<std::string>()); | ||||||
|     } |     } | ||||||
| #endif // RAPIDJSON_HAS_STDSTRING | #endif // RAPIDJSON_HAS_STDSTRING | ||||||
| } | } | ||||||
| @@ -781,25 +838,9 @@ TEST(Value, SetStringNullException) { | |||||||
|     EXPECT_THROW(v.SetString(0, 0), AssertException); |     EXPECT_THROW(v.SetString(0, 0), AssertException); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST(Value, Array) { | template <typename T, typename Allocator> | ||||||
|     Value x(kArrayType); | static void TestArray(T& x, Allocator& allocator) { | ||||||
|     const Value& y = x; |     const T& y = x; | ||||||
|     Value::AllocatorType allocator; |  | ||||||
|  |  | ||||||
|     EXPECT_EQ(kArrayType, x.GetType()); |  | ||||||
|     EXPECT_TRUE(x.IsArray()); |  | ||||||
|     EXPECT_TRUE(x.Empty()); |  | ||||||
|     EXPECT_EQ(0u, x.Size()); |  | ||||||
|     EXPECT_TRUE(y.IsArray()); |  | ||||||
|     EXPECT_TRUE(y.Empty()); |  | ||||||
|     EXPECT_EQ(0u, y.Size()); |  | ||||||
|  |  | ||||||
|     EXPECT_FALSE(x.IsNull()); |  | ||||||
|     EXPECT_FALSE(x.IsBool()); |  | ||||||
|     EXPECT_FALSE(x.IsFalse()); |  | ||||||
|     EXPECT_FALSE(x.IsTrue()); |  | ||||||
|     EXPECT_FALSE(x.IsString()); |  | ||||||
|     EXPECT_FALSE(x.IsObject()); |  | ||||||
|  |  | ||||||
|     // PushBack() |     // PushBack() | ||||||
|     Value v; |     Value v; | ||||||
| @@ -846,7 +887,7 @@ TEST(Value, Array) { | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
|     // iterator |     // iterator | ||||||
|     Value::ValueIterator itr = x.Begin(); |     typename T::ValueIterator itr = x.Begin(); | ||||||
|     EXPECT_TRUE(itr != x.End()); |     EXPECT_TRUE(itr != x.End()); | ||||||
|     EXPECT_TRUE(itr->IsNull()); |     EXPECT_TRUE(itr->IsNull()); | ||||||
|     ++itr; |     ++itr; | ||||||
| @@ -865,7 +906,7 @@ TEST(Value, Array) { | |||||||
|     EXPECT_STREQ("foo", itr->GetString()); |     EXPECT_STREQ("foo", itr->GetString()); | ||||||
|  |  | ||||||
|     // const iterator |     // const iterator | ||||||
|     Value::ConstValueIterator citr = y.Begin(); |     typename T::ConstValueIterator citr = y.Begin(); | ||||||
|     EXPECT_TRUE(citr != y.End()); |     EXPECT_TRUE(citr != y.End()); | ||||||
|     EXPECT_TRUE(citr->IsNull()); |     EXPECT_TRUE(citr->IsNull()); | ||||||
|     ++citr; |     ++citr; | ||||||
| @@ -951,6 +992,29 @@ TEST(Value, Array) { | |||||||
|                 EXPECT_EQ(i + removeCount, x[static_cast<SizeType>(i)][0].GetUint()); |                 EXPECT_EQ(i + removeCount, x[static_cast<SizeType>(i)][0].GetUint()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST(Value, Array) { | ||||||
|  |     Value x(kArrayType); | ||||||
|  |     const Value& y = x; | ||||||
|  |     Value::AllocatorType allocator; | ||||||
|  |  | ||||||
|  |     EXPECT_EQ(kArrayType, x.GetType()); | ||||||
|  |     EXPECT_TRUE(x.IsArray()); | ||||||
|  |     EXPECT_TRUE(x.Empty()); | ||||||
|  |     EXPECT_EQ(0u, x.Size()); | ||||||
|  |     EXPECT_TRUE(y.IsArray()); | ||||||
|  |     EXPECT_TRUE(y.Empty()); | ||||||
|  |     EXPECT_EQ(0u, y.Size()); | ||||||
|  |  | ||||||
|  |     EXPECT_FALSE(x.IsNull()); | ||||||
|  |     EXPECT_FALSE(x.IsBool()); | ||||||
|  |     EXPECT_FALSE(x.IsFalse()); | ||||||
|  |     EXPECT_FALSE(x.IsTrue()); | ||||||
|  |     EXPECT_FALSE(x.IsString()); | ||||||
|  |     EXPECT_FALSE(x.IsObject()); | ||||||
|  |  | ||||||
|  |     TestArray(x, allocator); | ||||||
|  |  | ||||||
|     // Working in gcc without C++11, but VS2013 cannot compile. To be diagnosed. |     // Working in gcc without C++11, but VS2013 cannot compile. To be diagnosed. | ||||||
|     // http://en.wikipedia.org/wiki/Erase-remove_idiom |     // http://en.wikipedia.org/wiki/Erase-remove_idiom | ||||||
| @@ -974,19 +1038,96 @@ TEST(Value, Array) { | |||||||
|     EXPECT_TRUE(z.Empty()); |     EXPECT_TRUE(z.Empty()); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST(Value, Object) { | TEST(Value, ArrayHelper) { | ||||||
|     Value x(kObjectType); |  | ||||||
|     const Value& y = x; // const version |  | ||||||
|     Value::AllocatorType allocator; |     Value::AllocatorType allocator; | ||||||
|  |     { | ||||||
|  |         Value x(kArrayType); | ||||||
|  |         Value::Array a = x.GetArray(); | ||||||
|  |         TestArray(a, allocator); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     EXPECT_EQ(kObjectType, x.GetType()); |     { | ||||||
|     EXPECT_TRUE(x.IsObject()); |         Value x(kArrayType); | ||||||
|     EXPECT_TRUE(x.ObjectEmpty()); |         Value::Array a = x.GetArray(); | ||||||
|     EXPECT_EQ(0u, x.MemberCount()); |         a.PushBack(1, allocator); | ||||||
|     EXPECT_EQ(kObjectType, y.GetType()); |  | ||||||
|     EXPECT_TRUE(y.IsObject()); |         Value::Array a2(a); // copy constructor | ||||||
|     EXPECT_TRUE(y.ObjectEmpty()); |         EXPECT_EQ(1, a2.Size()); | ||||||
|     EXPECT_EQ(0u, y.MemberCount()); |  | ||||||
|  |         Value::Array a3 = a; | ||||||
|  |         EXPECT_EQ(1, a3.Size()); | ||||||
|  |  | ||||||
|  |         Value::ConstArray y = static_cast<const Value&>(x).GetArray(); | ||||||
|  |         (void)y; | ||||||
|  |         // y.PushBack(1, allocator); // should not compile | ||||||
|  |  | ||||||
|  |         // Templated functions | ||||||
|  |         x.Clear(); | ||||||
|  |         EXPECT_TRUE(x.Is<Value::Array>()); | ||||||
|  |         EXPECT_TRUE(x.Is<Value::ConstArray>()); | ||||||
|  |         a.PushBack(1, allocator); | ||||||
|  |         EXPECT_EQ(1, x.Get<Value::Array>()[0].GetInt()); | ||||||
|  |         EXPECT_EQ(1, x.Get<Value::ConstArray>()[0].GetInt()); | ||||||
|  |  | ||||||
|  |         Value x2; | ||||||
|  |         x2.Set<Value::Array>(a); | ||||||
|  |         EXPECT_TRUE(x.IsArray());   // IsArray() is invariant after moving. | ||||||
|  |         EXPECT_EQ(1, x2.Get<Value::Array>()[0].GetInt()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |         Value y(kArrayType); | ||||||
|  |         y.PushBack(123, allocator); | ||||||
|  |  | ||||||
|  |         Value x(y.GetArray());      // Construct value form array. | ||||||
|  |         EXPECT_TRUE(x.IsArray()); | ||||||
|  |         EXPECT_EQ(123, x[0].GetInt()); | ||||||
|  |         EXPECT_TRUE(y.IsArray());   // Invariant | ||||||
|  |         EXPECT_TRUE(y.Empty()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |         Value x(kArrayType); | ||||||
|  |         Value y(kArrayType); | ||||||
|  |         y.PushBack(123, allocator); | ||||||
|  |         x.PushBack(y.GetArray(), allocator);    // Implicit constructor to convert Array to GenericValue | ||||||
|  |  | ||||||
|  |         EXPECT_EQ(1, x.Size()); | ||||||
|  |         EXPECT_EQ(123, x[0][0].GetInt()); | ||||||
|  |         EXPECT_TRUE(y.IsArray()); | ||||||
|  |         EXPECT_TRUE(y.Empty()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_CXX11_RANGE_FOR | ||||||
|  | TEST(Value, ArrayHelperRangeFor) { | ||||||
|  |     Value::AllocatorType allocator; | ||||||
|  |     Value x(kArrayType); | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < 10; i++) | ||||||
|  |         x.PushBack(i, allocator); | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |         int i = 0; | ||||||
|  |         for (auto& v : x.GetArray()) | ||||||
|  |             EXPECT_EQ(i++, v.GetInt()); | ||||||
|  |         EXPECT_EQ(i, 10); | ||||||
|  |     } | ||||||
|  |     { | ||||||
|  |         int i = 0; | ||||||
|  |         for (const auto& v : const_cast<const Value&>(x).GetArray()) | ||||||
|  |             EXPECT_EQ(i++, v.GetInt()); | ||||||
|  |         EXPECT_EQ(i, 10); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Array a = x.GetArray(); | ||||||
|  |     // Array ca = const_cast<const Value&>(x).GetArray(); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | template <typename T, typename Allocator> | ||||||
|  | static void TestObject(T& x, Allocator& allocator) { | ||||||
|  |     const T& y = x; // const version | ||||||
|  |  | ||||||
|     // AddMember() |     // AddMember() | ||||||
|     x.AddMember("A", "Apple", allocator); |     x.AddMember("A", "Apple", allocator); | ||||||
| @@ -1227,7 +1368,7 @@ TEST(Value, Object) { | |||||||
|     const unsigned n = 10; |     const unsigned n = 10; | ||||||
|     for (unsigned first = 0; first < n; first++) { |     for (unsigned first = 0; first < n; first++) { | ||||||
|         for (unsigned last = first; last <= n; last++) { |         for (unsigned last = first; last <= n; last++) { | ||||||
|             Value(kObjectType).Swap(x); |             x.RemoveAllMembers(); | ||||||
|             for (unsigned i = 0; i < n; i++) |             for (unsigned i = 0; i < n; i++) | ||||||
|                 x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator); |                 x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator); | ||||||
|  |  | ||||||
| @@ -1250,6 +1391,23 @@ TEST(Value, Object) { | |||||||
|     x.RemoveAllMembers(); |     x.RemoveAllMembers(); | ||||||
|     EXPECT_TRUE(x.ObjectEmpty()); |     EXPECT_TRUE(x.ObjectEmpty()); | ||||||
|     EXPECT_EQ(0u, x.MemberCount()); |     EXPECT_EQ(0u, x.MemberCount()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST(Value, Object) { | ||||||
|  |     Value x(kObjectType); | ||||||
|  |     const Value& y = x; // const version | ||||||
|  |     Value::AllocatorType allocator; | ||||||
|  |  | ||||||
|  |     EXPECT_EQ(kObjectType, x.GetType()); | ||||||
|  |     EXPECT_TRUE(x.IsObject()); | ||||||
|  |     EXPECT_TRUE(x.ObjectEmpty()); | ||||||
|  |     EXPECT_EQ(0u, x.MemberCount()); | ||||||
|  |     EXPECT_EQ(kObjectType, y.GetType()); | ||||||
|  |     EXPECT_TRUE(y.IsObject()); | ||||||
|  |     EXPECT_TRUE(y.ObjectEmpty()); | ||||||
|  |     EXPECT_EQ(0u, y.MemberCount()); | ||||||
|  |  | ||||||
|  |     TestObject(x, allocator); | ||||||
|  |  | ||||||
|     // SetObject() |     // SetObject() | ||||||
|     Value z; |     Value z; | ||||||
| @@ -1257,6 +1415,100 @@ TEST(Value, Object) { | |||||||
|     EXPECT_TRUE(z.IsObject()); |     EXPECT_TRUE(z.IsObject()); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | TEST(Value, ObjectHelper) { | ||||||
|  |     Value::AllocatorType allocator; | ||||||
|  |     { | ||||||
|  |         Value x(kObjectType); | ||||||
|  |         Value::Object o = x.GetObject(); | ||||||
|  |         TestObject(o, allocator); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |         Value x(kObjectType); | ||||||
|  |         Value::Object o = x.GetObject(); | ||||||
|  |         o.AddMember("1", 1, allocator); | ||||||
|  |  | ||||||
|  |         Value::Object o2(o); // copy constructor | ||||||
|  |         EXPECT_EQ(1, o2.MemberCount()); | ||||||
|  |  | ||||||
|  |         Value::Object o3 = o; | ||||||
|  |         EXPECT_EQ(1, o3.MemberCount()); | ||||||
|  |  | ||||||
|  |         Value::ConstObject y = static_cast<const Value&>(x).GetObject(); | ||||||
|  |         (void)y; | ||||||
|  |         // y.AddMember("1", 1, allocator); // should not compile | ||||||
|  |  | ||||||
|  |         // Templated functions | ||||||
|  |         x.RemoveAllMembers(); | ||||||
|  |         EXPECT_TRUE(x.Is<Value::Object>()); | ||||||
|  |         EXPECT_TRUE(x.Is<Value::ConstObject>()); | ||||||
|  |         o.AddMember("1", 1, allocator); | ||||||
|  |         EXPECT_EQ(1, x.Get<Value::Object>()["1"].GetInt()); | ||||||
|  |         EXPECT_EQ(1, x.Get<Value::ConstObject>()["1"].GetInt()); | ||||||
|  |  | ||||||
|  |         Value x2; | ||||||
|  |         x2.Set<Value::Object>(o); | ||||||
|  |         EXPECT_TRUE(x.IsObject());   // IsObject() is invariant after moving | ||||||
|  |         EXPECT_EQ(1, x2.Get<Value::Object>()["1"].GetInt()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |         Value x(kObjectType); | ||||||
|  |         x.AddMember("a", "apple", allocator); | ||||||
|  |         Value y(x.GetObject()); | ||||||
|  |         EXPECT_STREQ("apple", y["a"].GetString()); | ||||||
|  |         EXPECT_TRUE(x.IsObject());  // Invariant | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     { | ||||||
|  |         Value x(kObjectType); | ||||||
|  |         x.AddMember("a", "apple", allocator); | ||||||
|  |         Value y(kObjectType); | ||||||
|  |         y.AddMember("fruits", x.GetObject(), allocator); | ||||||
|  |         EXPECT_STREQ("apple", y["fruits"]["a"].GetString()); | ||||||
|  |         EXPECT_TRUE(x.IsObject());  // Invariant | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #if RAPIDJSON_HAS_CXX11_RANGE_FOR | ||||||
|  | TEST(Value, ObjectHelperRangeFor) { | ||||||
|  |     Value::AllocatorType allocator; | ||||||
|  |     Value x(kObjectType); | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < 10; i++) { | ||||||
|  |         char name[10]; | ||||||
|  |         Value n(name, static_cast<SizeType>(sprintf(name, "%d", i)), allocator); | ||||||
|  |         x.AddMember(n, i, allocator); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |         int i = 0; | ||||||
|  |         for (auto& m : x.GetObject()) { | ||||||
|  |             char name[10]; | ||||||
|  |             sprintf(name, "%d", i); | ||||||
|  |             EXPECT_STREQ(name, m.name.GetString()); | ||||||
|  |             EXPECT_EQ(i, m.value.GetInt()); | ||||||
|  |             i++; | ||||||
|  |         } | ||||||
|  |         EXPECT_EQ(i, 10); | ||||||
|  |     } | ||||||
|  |     { | ||||||
|  |         int i = 0; | ||||||
|  |         for (const auto& m : const_cast<const Value&>(x).GetObject()) { | ||||||
|  |             char name[10]; | ||||||
|  |             sprintf(name, "%d", i); | ||||||
|  |             EXPECT_STREQ(name, m.name.GetString()); | ||||||
|  |             EXPECT_EQ(i, m.value.GetInt()); | ||||||
|  |             i++; | ||||||
|  |         } | ||||||
|  |         EXPECT_EQ(i, 10); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Object a = x.GetObject(); | ||||||
|  |     // Object ca = const_cast<const Value&>(x).GetObject(); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| TEST(Value, EraseMember_String) { | TEST(Value, EraseMember_String) { | ||||||
|     Value::AllocatorType allocator; |     Value::AllocatorType allocator; | ||||||
|     Value x(kObjectType); |     Value x(kObjectType); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Milo Yip
					Milo Yip