Merge branch 'master' into issue158_parsestdstring
This commit is contained in:
commit
5fc59cb6fa
@ -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).
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ struct GenericStringRef {
|
|||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
explicit GenericStringRef(const CharType* str)
|
explicit GenericStringRef(const CharType* str)
|
||||||
: s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); }
|
: s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); }
|
||||||
|
|
||||||
//! Create constant string reference from pointer and length
|
//! Create constant string reference from pointer and length
|
||||||
#ifndef __clang__ // -Wdocumentation
|
#ifndef __clang__ // -Wdocumentation
|
||||||
@ -309,7 +309,7 @@ struct GenericStringRef {
|
|||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
GenericStringRef(const CharType* str, SizeType len)
|
GenericStringRef(const CharType* str, SizeType len)
|
||||||
: s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); }
|
: s(str), length(len) { RAPIDJSON_ASSERT(s != 0); }
|
||||||
|
|
||||||
//! implicit conversion to plain CharType pointer
|
//! implicit conversion to plain CharType pointer
|
||||||
operator const Ch *() const { return s; }
|
operator const Ch *() const { return s; }
|
||||||
@ -395,6 +395,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
|
||||||
|
|
||||||
@ -422,17 +543,21 @@ 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.
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Default constructor creates a null value.
|
//! Default constructor creates a null value.
|
||||||
GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {}
|
GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; }
|
||||||
|
|
||||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
//! Move constructor in C++11
|
//! Move constructor in C++11
|
||||||
GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) {
|
GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) {
|
||||||
rhs.flags_ = kNullFlag; // give up contents
|
rhs.data_.f.flags = kNullFlag; // give up contents
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -457,13 +582,13 @@ public:
|
|||||||
\param type Type of the value.
|
\param type Type of the value.
|
||||||
\note Default content for number is zero.
|
\note Default content for number is zero.
|
||||||
*/
|
*/
|
||||||
explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() {
|
explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {
|
||||||
static const unsigned defaultFlags[7] = {
|
static const uint16_t defaultFlags[7] = {
|
||||||
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
|
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
|
||||||
kNumberAnyFlag
|
kNumberAnyFlag
|
||||||
};
|
};
|
||||||
RAPIDJSON_ASSERT(type <= kNumberType);
|
RAPIDJSON_ASSERT(type <= kNumberType);
|
||||||
flags_ = defaultFlags[type];
|
data_.f.flags = defaultFlags[type];
|
||||||
|
|
||||||
// Use ShortString to store empty string.
|
// Use ShortString to store empty string.
|
||||||
if (type == kStringType)
|
if (type == kStringType)
|
||||||
@ -492,92 +617,118 @@ public:
|
|||||||
#else
|
#else
|
||||||
explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
|
explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
|
||||||
#endif
|
#endif
|
||||||
: data_(), flags_(b ? kTrueFlag : kFalseFlag) {
|
: data_() {
|
||||||
// safe-guard against failing SFINAE
|
// safe-guard against failing SFINAE
|
||||||
RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
|
RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
|
||||||
|
data_.f.flags = b ? kTrueFlag : kFalseFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Constructor for int value.
|
//! Constructor for int value.
|
||||||
explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) {
|
explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() {
|
||||||
data_.n.i64 = i;
|
data_.n.i64 = i;
|
||||||
if (i >= 0)
|
data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag;
|
||||||
flags_ |= kUintFlag | kUint64Flag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Constructor for unsigned value.
|
//! Constructor for unsigned value.
|
||||||
explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) {
|
explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() {
|
||||||
data_.n.u64 = u;
|
data_.n.u64 = u;
|
||||||
if (!(u & 0x80000000))
|
data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag);
|
||||||
flags_ |= kIntFlag | kInt64Flag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Constructor for int64_t value.
|
//! Constructor for int64_t value.
|
||||||
explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt64Flag) {
|
explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() {
|
||||||
data_.n.i64 = i64;
|
data_.n.i64 = i64;
|
||||||
|
data_.f.flags = kNumberInt64Flag;
|
||||||
if (i64 >= 0) {
|
if (i64 >= 0) {
|
||||||
flags_ |= kNumberUint64Flag;
|
data_.f.flags |= kNumberUint64Flag;
|
||||||
if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
|
if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
|
||||||
flags_ |= kUintFlag;
|
data_.f.flags |= kUintFlag;
|
||||||
if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
|
if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
|
||||||
flags_ |= kIntFlag;
|
data_.f.flags |= kIntFlag;
|
||||||
}
|
}
|
||||||
else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
|
else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
|
||||||
flags_ |= kIntFlag;
|
data_.f.flags |= kIntFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Constructor for uint64_t value.
|
//! Constructor for uint64_t value.
|
||||||
explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) {
|
explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() {
|
||||||
data_.n.u64 = u64;
|
data_.n.u64 = u64;
|
||||||
|
data_.f.flags = kNumberUint64Flag;
|
||||||
if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
|
if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
|
||||||
flags_ |= kInt64Flag;
|
data_.f.flags |= kInt64Flag;
|
||||||
if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
|
if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
|
||||||
flags_ |= kUintFlag;
|
data_.f.flags |= kUintFlag;
|
||||||
if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
|
if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
|
||||||
flags_ |= kIntFlag;
|
data_.f.flags |= kIntFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Constructor for double value.
|
//! Constructor for double value.
|
||||||
explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; }
|
explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }
|
||||||
|
|
||||||
//! Constructor for constant string (i.e. do not make a copy of string)
|
//! Constructor for constant string (i.e. do not make a copy of string)
|
||||||
GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(StringRef(s, length)); }
|
GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
|
||||||
|
|
||||||
//! Constructor for constant string (i.e. do not make a copy of string)
|
//! Constructor for constant string (i.e. do not make a copy of string)
|
||||||
explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(s); }
|
explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); }
|
||||||
|
|
||||||
//! Constructor for copy-string (i.e. do make a copy of string)
|
//! Constructor for copy-string (i.e. do make a copy of string)
|
||||||
GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); }
|
GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); }
|
||||||
|
|
||||||
//! Constructor for copy-string (i.e. do make a copy of string)
|
//! Constructor for copy-string (i.e. do make a copy of string)
|
||||||
GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
|
GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
|
||||||
|
|
||||||
#if RAPIDJSON_HAS_STDSTRING
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
//! Constructor for copy-string from a string object (i.e. do make a copy of string)
|
//! Constructor for copy-string from a string object (i.e. do make a copy of string)
|
||||||
/*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
|
/*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
|
||||||
*/
|
*/
|
||||||
GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_(), flags_() { 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.
|
||||||
*/
|
*/
|
||||||
~GenericValue() {
|
~GenericValue() {
|
||||||
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
|
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
|
||||||
switch(flags_) {
|
switch(data_.f.flags) {
|
||||||
case kArrayFlag:
|
case kArrayFlag:
|
||||||
for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
|
{
|
||||||
v->~GenericValue();
|
GenericValue* e = GetElementsPointer();
|
||||||
Allocator::Free(data_.a.elements);
|
for (GenericValue* v = e; v != e + data_.a.size; ++v)
|
||||||
|
v->~GenericValue();
|
||||||
|
Allocator::Free(e);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kObjectFlag:
|
case kObjectFlag:
|
||||||
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
|
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
|
||||||
m->~Member();
|
m->~Member();
|
||||||
Allocator::Free(data_.o.members);
|
Allocator::Free(GetMembersPointer());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kCopyStringFlag:
|
case kCopyStringFlag:
|
||||||
Allocator::Free(const_cast<Ch*>(data_.s.str));
|
Allocator::Free(const_cast<Ch*>(GetStringPointer()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -775,20 +926,20 @@ public:
|
|||||||
//!@name Type
|
//!@name Type
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
Type GetType() const { return static_cast<Type>(flags_ & kTypeMask); }
|
Type GetType() const { return static_cast<Type>(data_.f.flags & kTypeMask); }
|
||||||
bool IsNull() const { return flags_ == kNullFlag; }
|
bool IsNull() const { return data_.f.flags == kNullFlag; }
|
||||||
bool IsFalse() const { return flags_ == kFalseFlag; }
|
bool IsFalse() const { return data_.f.flags == kFalseFlag; }
|
||||||
bool IsTrue() const { return flags_ == kTrueFlag; }
|
bool IsTrue() const { return data_.f.flags == kTrueFlag; }
|
||||||
bool IsBool() const { return (flags_ & kBoolFlag) != 0; }
|
bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; }
|
||||||
bool IsObject() const { return flags_ == kObjectFlag; }
|
bool IsObject() const { return data_.f.flags == kObjectFlag; }
|
||||||
bool IsArray() const { return flags_ == kArrayFlag; }
|
bool IsArray() const { return data_.f.flags == kArrayFlag; }
|
||||||
bool IsNumber() const { return (flags_ & kNumberFlag) != 0; }
|
bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; }
|
||||||
bool IsInt() const { return (flags_ & kIntFlag) != 0; }
|
bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; }
|
||||||
bool IsUint() const { return (flags_ & kUintFlag) != 0; }
|
bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; }
|
||||||
bool IsInt64() const { return (flags_ & kInt64Flag) != 0; }
|
bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; }
|
||||||
bool IsUint64() const { return (flags_ & kUint64Flag) != 0; }
|
bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; }
|
||||||
bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }
|
bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; }
|
||||||
bool IsString() const { return (flags_ & kStringFlag) != 0; }
|
bool IsString() const { return (data_.f.flags & kStringFlag) != 0; }
|
||||||
|
|
||||||
// Checks whether a number can be losslessly converted to a double.
|
// Checks whether a number can be losslessly converted to a double.
|
||||||
bool IsLosslessDouble() const {
|
bool IsLosslessDouble() const {
|
||||||
@ -808,7 +959,7 @@ public:
|
|||||||
|
|
||||||
// Checks whether a number is a float (possible lossy).
|
// Checks whether a number is a float (possible lossy).
|
||||||
bool IsFloat() const {
|
bool IsFloat() const {
|
||||||
if ((flags_ & kDoubleFlag) == 0)
|
if ((data_.f.flags & kDoubleFlag) == 0)
|
||||||
return false;
|
return false;
|
||||||
double d = GetDouble();
|
double d = GetDouble();
|
||||||
return d >= -3.4028234e38 && d <= 3.4028234e38;
|
return d >= -3.4028234e38 && d <= 3.4028234e38;
|
||||||
@ -833,7 +984,7 @@ public:
|
|||||||
//!@name Bool
|
//!@name Bool
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; }
|
bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; }
|
||||||
//!< Set boolean value
|
//!< Set boolean value
|
||||||
/*! \post IsBool() == true */
|
/*! \post IsBool() == true */
|
||||||
GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
|
GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
|
||||||
@ -907,16 +1058,16 @@ public:
|
|||||||
|
|
||||||
//! Const member iterator
|
//! Const member iterator
|
||||||
/*! \pre IsObject() == true */
|
/*! \pre IsObject() == true */
|
||||||
ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); }
|
ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); }
|
||||||
//! Const \em past-the-end member iterator
|
//! Const \em past-the-end member iterator
|
||||||
/*! \pre IsObject() == true */
|
/*! \pre IsObject() == true */
|
||||||
ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); }
|
ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); }
|
||||||
//! Member iterator
|
//! Member iterator
|
||||||
/*! \pre IsObject() == true */
|
/*! \pre IsObject() == true */
|
||||||
MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); }
|
MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); }
|
||||||
//! \em Past-the-end member iterator
|
//! \em Past-the-end member iterator
|
||||||
/*! \pre IsObject() == true */
|
/*! \pre IsObject() == true */
|
||||||
MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); }
|
MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
|
||||||
|
|
||||||
//! Check whether a member exists in the object.
|
//! Check whether a member exists in the object.
|
||||||
/*!
|
/*!
|
||||||
@ -1022,20 +1173,21 @@ 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;
|
||||||
o.members = reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member)));
|
SetMembersPointer(reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member))));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SizeType oldCapacity = o.capacity;
|
SizeType oldCapacity = o.capacity;
|
||||||
o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
|
o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
|
||||||
o.members = reinterpret_cast<Member*>(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member)));
|
SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
o.members[o.size].name.RawAssign(name);
|
Member* members = GetMembersPointer();
|
||||||
o.members[o.size].value.RawAssign(value);
|
members[o.size].name.RawAssign(name);
|
||||||
|
members[o.size].value.RawAssign(value);
|
||||||
o.size++;
|
o.size++;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -1214,18 +1366,14 @@ public:
|
|||||||
MemberIterator RemoveMember(MemberIterator m) {
|
MemberIterator RemoveMember(MemberIterator m) {
|
||||||
RAPIDJSON_ASSERT(IsObject());
|
RAPIDJSON_ASSERT(IsObject());
|
||||||
RAPIDJSON_ASSERT(data_.o.size > 0);
|
RAPIDJSON_ASSERT(data_.o.size > 0);
|
||||||
RAPIDJSON_ASSERT(data_.o.members != 0);
|
RAPIDJSON_ASSERT(GetMembersPointer() != 0);
|
||||||
RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
|
RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
|
||||||
|
|
||||||
MemberIterator last(data_.o.members + (data_.o.size - 1));
|
MemberIterator last(GetMembersPointer() + (data_.o.size - 1));
|
||||||
if (data_.o.size > 1 && m != last) {
|
if (data_.o.size > 1 && m != last)
|
||||||
// Move the last one to this place
|
*m = *last; // Move the last one to this place
|
||||||
*m = *last;
|
else
|
||||||
}
|
m->~Member(); // Only one left, just destroy
|
||||||
else {
|
|
||||||
// Only one left, just destroy
|
|
||||||
m->~Member();
|
|
||||||
}
|
|
||||||
--data_.o.size;
|
--data_.o.size;
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
@ -1255,7 +1403,7 @@ public:
|
|||||||
MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
|
MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
|
||||||
RAPIDJSON_ASSERT(IsObject());
|
RAPIDJSON_ASSERT(IsObject());
|
||||||
RAPIDJSON_ASSERT(data_.o.size > 0);
|
RAPIDJSON_ASSERT(data_.o.size > 0);
|
||||||
RAPIDJSON_ASSERT(data_.o.members != 0);
|
RAPIDJSON_ASSERT(GetMembersPointer() != 0);
|
||||||
RAPIDJSON_ASSERT(first >= MemberBegin());
|
RAPIDJSON_ASSERT(first >= MemberBegin());
|
||||||
RAPIDJSON_ASSERT(first <= last);
|
RAPIDJSON_ASSERT(first <= last);
|
||||||
RAPIDJSON_ASSERT(last <= MemberEnd());
|
RAPIDJSON_ASSERT(last <= MemberEnd());
|
||||||
@ -1293,6 +1441,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
|
||||||
@ -1300,7 +1451,7 @@ public:
|
|||||||
|
|
||||||
//! Set this value as an empty array.
|
//! Set this value as an empty array.
|
||||||
/*! \post IsArray == true */
|
/*! \post IsArray == true */
|
||||||
GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
|
GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
|
||||||
|
|
||||||
//! Get the number of elements in array.
|
//! Get the number of elements in array.
|
||||||
SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
|
SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
|
||||||
@ -1317,8 +1468,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
void Clear() {
|
void Clear() {
|
||||||
RAPIDJSON_ASSERT(IsArray());
|
RAPIDJSON_ASSERT(IsArray());
|
||||||
for (SizeType i = 0; i < data_.a.size; ++i)
|
GenericValue* e = GetElementsPointer();
|
||||||
data_.a.elements[i].~GenericValue();
|
for (GenericValue* v = e; v != e + data_.a.size; ++v)
|
||||||
|
v->~GenericValue();
|
||||||
data_.a.size = 0;
|
data_.a.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1330,16 +1482,16 @@ public:
|
|||||||
GenericValue& operator[](SizeType index) {
|
GenericValue& operator[](SizeType index) {
|
||||||
RAPIDJSON_ASSERT(IsArray());
|
RAPIDJSON_ASSERT(IsArray());
|
||||||
RAPIDJSON_ASSERT(index < data_.a.size);
|
RAPIDJSON_ASSERT(index < data_.a.size);
|
||||||
return data_.a.elements[index];
|
return GetElementsPointer()[index];
|
||||||
}
|
}
|
||||||
const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
|
const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
|
||||||
|
|
||||||
//! Element iterator
|
//! Element iterator
|
||||||
/*! \pre IsArray() == true */
|
/*! \pre IsArray() == true */
|
||||||
ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; }
|
ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); }
|
||||||
//! \em Past-the-end element iterator
|
//! \em Past-the-end element iterator
|
||||||
/*! \pre IsArray() == true */
|
/*! \pre IsArray() == true */
|
||||||
ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; }
|
ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; }
|
||||||
//! Constant element iterator
|
//! Constant element iterator
|
||||||
/*! \pre IsArray() == true */
|
/*! \pre IsArray() == true */
|
||||||
ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
|
ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
|
||||||
@ -1356,7 +1508,7 @@ public:
|
|||||||
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
|
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
|
||||||
RAPIDJSON_ASSERT(IsArray());
|
RAPIDJSON_ASSERT(IsArray());
|
||||||
if (newCapacity > data_.a.capacity) {
|
if (newCapacity > data_.a.capacity) {
|
||||||
data_.a.elements = static_cast<GenericValue*>(allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)));
|
SetElementsPointer(reinterpret_cast<GenericValue*>(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue))));
|
||||||
data_.a.capacity = newCapacity;
|
data_.a.capacity = newCapacity;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
@ -1376,7 +1528,7 @@ public:
|
|||||||
RAPIDJSON_ASSERT(IsArray());
|
RAPIDJSON_ASSERT(IsArray());
|
||||||
if (data_.a.size >= data_.a.capacity)
|
if (data_.a.size >= data_.a.capacity)
|
||||||
Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);
|
Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);
|
||||||
data_.a.elements[data_.a.size++].RawAssign(value);
|
GetElementsPointer()[data_.a.size++].RawAssign(value);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1430,7 +1582,7 @@ public:
|
|||||||
GenericValue& PopBack() {
|
GenericValue& PopBack() {
|
||||||
RAPIDJSON_ASSERT(IsArray());
|
RAPIDJSON_ASSERT(IsArray());
|
||||||
RAPIDJSON_ASSERT(!Empty());
|
RAPIDJSON_ASSERT(!Empty());
|
||||||
data_.a.elements[--data_.a.size].~GenericValue();
|
GetElementsPointer()[--data_.a.size].~GenericValue();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1456,7 +1608,7 @@ public:
|
|||||||
ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
|
ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
|
||||||
RAPIDJSON_ASSERT(IsArray());
|
RAPIDJSON_ASSERT(IsArray());
|
||||||
RAPIDJSON_ASSERT(data_.a.size > 0);
|
RAPIDJSON_ASSERT(data_.a.size > 0);
|
||||||
RAPIDJSON_ASSERT(data_.a.elements != 0);
|
RAPIDJSON_ASSERT(GetElementsPointer() != 0);
|
||||||
RAPIDJSON_ASSERT(first >= Begin());
|
RAPIDJSON_ASSERT(first >= Begin());
|
||||||
RAPIDJSON_ASSERT(first <= last);
|
RAPIDJSON_ASSERT(first <= last);
|
||||||
RAPIDJSON_ASSERT(last <= End());
|
RAPIDJSON_ASSERT(last <= End());
|
||||||
@ -1468,26 +1620,29 @@ 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
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; }
|
int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; }
|
||||||
unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; }
|
unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; }
|
||||||
int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }
|
int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; }
|
||||||
uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; }
|
uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; }
|
||||||
|
|
||||||
//! Get the value as double type.
|
//! Get the value as double type.
|
||||||
/*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless.
|
/*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless.
|
||||||
*/
|
*/
|
||||||
double GetDouble() const {
|
double GetDouble() const {
|
||||||
RAPIDJSON_ASSERT(IsNumber());
|
RAPIDJSON_ASSERT(IsNumber());
|
||||||
if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
|
if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
|
||||||
if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double
|
if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double
|
||||||
if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
|
if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
|
||||||
if ((flags_ & kInt64Flag) != 0) return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
|
if ((data_.f.flags & kInt64Flag) != 0) return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
|
||||||
RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
|
RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Get the value as float type.
|
//! Get the value as float type.
|
||||||
@ -1510,12 +1665,12 @@ public:
|
|||||||
//!@name String
|
//!@name String
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? data_.ss.str : data_.s.str); }
|
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }
|
||||||
|
|
||||||
//! Get the length of string.
|
//! Get the length of string.
|
||||||
/*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
|
/*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
|
||||||
*/
|
*/
|
||||||
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
|
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
|
||||||
|
|
||||||
//! Set this value as a string without copying source string.
|
//! Set this value as a string without copying source string.
|
||||||
/*! This version has better performance with supplied length, and also support string containing null character.
|
/*! This version has better performance with supplied length, and also support string containing null character.
|
||||||
@ -1565,6 +1720,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.
|
||||||
@ -1584,7 +1763,7 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
|
for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
|
||||||
RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.
|
RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.
|
||||||
if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0)))
|
if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0)))
|
||||||
return false;
|
return false;
|
||||||
if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler)))
|
if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler)))
|
||||||
return false;
|
return false;
|
||||||
@ -1594,13 +1773,13 @@ public:
|
|||||||
case kArrayType:
|
case kArrayType:
|
||||||
if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
|
if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
|
||||||
return false;
|
return false;
|
||||||
for (const GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
|
for (const GenericValue* v = Begin(); v != End(); ++v)
|
||||||
if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
|
if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
|
||||||
return false;
|
return false;
|
||||||
return handler.EndArray(data_.a.size);
|
return handler.EndArray(data_.a.size);
|
||||||
|
|
||||||
case kStringType:
|
case kStringType:
|
||||||
return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0);
|
return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
RAPIDJSON_ASSERT(GetType() == kNumberType);
|
RAPIDJSON_ASSERT(GetType() == kNumberType);
|
||||||
@ -1617,16 +1796,16 @@ private:
|
|||||||
template <typename, typename, typename> friend class GenericDocument;
|
template <typename, typename, typename> friend class GenericDocument;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
kBoolFlag = 0x100,
|
kBoolFlag = 0x0008,
|
||||||
kNumberFlag = 0x200,
|
kNumberFlag = 0x0010,
|
||||||
kIntFlag = 0x400,
|
kIntFlag = 0x0020,
|
||||||
kUintFlag = 0x800,
|
kUintFlag = 0x0040,
|
||||||
kInt64Flag = 0x1000,
|
kInt64Flag = 0x0080,
|
||||||
kUint64Flag = 0x2000,
|
kUint64Flag = 0x0100,
|
||||||
kDoubleFlag = 0x4000,
|
kDoubleFlag = 0x0200,
|
||||||
kStringFlag = 0x100000,
|
kStringFlag = 0x0400,
|
||||||
kCopyFlag = 0x200000,
|
kCopyFlag = 0x0800,
|
||||||
kInlineStrFlag = 0x400000,
|
kInlineStrFlag = 0x1000,
|
||||||
|
|
||||||
// Initial flags of different types.
|
// Initial flags of different types.
|
||||||
kNullFlag = kNullType,
|
kNullFlag = kNullType,
|
||||||
@ -1644,16 +1823,27 @@ private:
|
|||||||
kObjectFlag = kObjectType,
|
kObjectFlag = kObjectType,
|
||||||
kArrayFlag = kArrayType,
|
kArrayFlag = kArrayType,
|
||||||
|
|
||||||
kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler
|
kTypeMask = 0x07
|
||||||
};
|
};
|
||||||
|
|
||||||
static const SizeType kDefaultArrayCapacity = 16;
|
static const SizeType kDefaultArrayCapacity = 16;
|
||||||
static const SizeType kDefaultObjectCapacity = 16;
|
static const SizeType kDefaultObjectCapacity = 16;
|
||||||
|
|
||||||
|
struct Flag {
|
||||||
|
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||||
|
char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer
|
||||||
|
#elif RAPIDJSON_64BIT
|
||||||
|
char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes
|
||||||
|
#else
|
||||||
|
char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes
|
||||||
|
#endif
|
||||||
|
uint16_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
struct String {
|
struct String {
|
||||||
const Ch* str;
|
|
||||||
SizeType length;
|
SizeType length;
|
||||||
unsigned hashcode; //!< reserved
|
SizeType hashcode; //!< reserved
|
||||||
|
const Ch* str;
|
||||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||||
|
|
||||||
// implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars
|
// implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars
|
||||||
@ -1662,10 +1852,10 @@ private:
|
|||||||
// to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as
|
// to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as
|
||||||
// the string terminator as well. For getting the string length back from that value just use
|
// the string terminator as well. For getting the string length back from that value just use
|
||||||
// "MaxSize - str[LenPos]".
|
// "MaxSize - str[LenPos]".
|
||||||
// This allows to store 11-chars strings in 32-bit mode and 15-chars strings in 64-bit mode
|
// This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode,
|
||||||
// inline (for `UTF8`-encoded strings).
|
// 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings).
|
||||||
struct ShortString {
|
struct ShortString {
|
||||||
enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
|
enum { MaxChars = sizeof(static_cast<Flag*>(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
|
||||||
Ch str[MaxChars];
|
Ch str[MaxChars];
|
||||||
|
|
||||||
inline static bool Usable(SizeType len) { return (MaxSize >= len); }
|
inline static bool Usable(SizeType len) { return (MaxSize >= len); }
|
||||||
@ -1699,69 +1889,79 @@ private:
|
|||||||
double d;
|
double d;
|
||||||
}; // 8 bytes
|
}; // 8 bytes
|
||||||
|
|
||||||
struct Object {
|
struct ObjectData {
|
||||||
Member* members;
|
|
||||||
SizeType size;
|
SizeType size;
|
||||||
SizeType capacity;
|
SizeType capacity;
|
||||||
|
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 {
|
||||||
GenericValue* elements;
|
|
||||||
SizeType size;
|
SizeType size;
|
||||||
SizeType capacity;
|
SizeType capacity;
|
||||||
|
GenericValue* elements;
|
||||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||||
|
|
||||||
union Data {
|
union Data {
|
||||||
String s;
|
String s;
|
||||||
ShortString ss;
|
ShortString ss;
|
||||||
Number n;
|
Number n;
|
||||||
Object o;
|
ObjectData o;
|
||||||
Array a;
|
ArrayData a;
|
||||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
Flag f;
|
||||||
|
}; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||||
|
|
||||||
|
RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }
|
||||||
|
RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
|
||||||
|
RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
|
||||||
|
RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); }
|
||||||
|
RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
|
||||||
|
RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
|
||||||
|
|
||||||
// Initialize this value as array with initial data, without calling destructor.
|
// Initialize this value as array with initial data, without calling destructor.
|
||||||
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
|
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
|
||||||
flags_ = kArrayFlag;
|
data_.f.flags = kArrayFlag;
|
||||||
if (count) {
|
if (count) {
|
||||||
data_.a.elements = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
|
GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
|
||||||
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
|
SetElementsPointer(e);
|
||||||
|
std::memcpy(e, values, count * sizeof(GenericValue));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
data_.a.elements = NULL;
|
SetElementsPointer(0);
|
||||||
data_.a.size = data_.a.capacity = count;
|
data_.a.size = data_.a.capacity = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Initialize this value as object with initial data, without calling destructor.
|
//! Initialize this value as object with initial data, without calling destructor.
|
||||||
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
|
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
|
||||||
flags_ = kObjectFlag;
|
data_.f.flags = kObjectFlag;
|
||||||
if (count) {
|
if (count) {
|
||||||
data_.o.members = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
|
Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
|
||||||
std::memcpy(data_.o.members, members, count * sizeof(Member));
|
SetMembersPointer(m);
|
||||||
|
std::memcpy(m, members, count * sizeof(Member));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
data_.o.members = NULL;
|
SetMembersPointer(0);
|
||||||
data_.o.size = data_.o.capacity = count;
|
data_.o.size = data_.o.capacity = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Initialize this value as constant string, without calling destructor.
|
//! Initialize this value as constant string, without calling destructor.
|
||||||
void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
|
void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
|
||||||
flags_ = kConstStringFlag;
|
data_.f.flags = kConstStringFlag;
|
||||||
data_.s.str = s;
|
SetStringPointer(s);
|
||||||
data_.s.length = s.length;
|
data_.s.length = s.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Initialize this value as copy string with initial data, without calling destructor.
|
//! Initialize this value as copy string with initial data, without calling destructor.
|
||||||
void SetStringRaw(StringRefType s, Allocator& allocator) {
|
void SetStringRaw(StringRefType s, Allocator& allocator) {
|
||||||
Ch* str = NULL;
|
Ch* str = 0;
|
||||||
if(ShortString::Usable(s.length)) {
|
if (ShortString::Usable(s.length)) {
|
||||||
flags_ = kShortStringFlag;
|
data_.f.flags = kShortStringFlag;
|
||||||
data_.ss.SetLength(s.length);
|
data_.ss.SetLength(s.length);
|
||||||
str = data_.ss.str;
|
str = data_.ss.str;
|
||||||
} else {
|
} else {
|
||||||
flags_ = kCopyStringFlag;
|
data_.f.flags = kCopyStringFlag;
|
||||||
data_.s.length = s.length;
|
data_.s.length = s.length;
|
||||||
str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch)));
|
str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch)));
|
||||||
data_.s.str = str;
|
SetStringPointer(str);
|
||||||
}
|
}
|
||||||
std::memcpy(str, s, s.length * sizeof(Ch));
|
std::memcpy(str, s, s.length * sizeof(Ch));
|
||||||
str[s.length] = '\0';
|
str[s.length] = '\0';
|
||||||
@ -1770,8 +1970,8 @@ private:
|
|||||||
//! Assignment without calling destructor
|
//! Assignment without calling destructor
|
||||||
void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
|
void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
|
||||||
data_ = rhs.data_;
|
data_ = rhs.data_;
|
||||||
flags_ = rhs.flags_;
|
// data_.f.flags = rhs.data_.f.flags;
|
||||||
rhs.flags_ = kNullFlag;
|
rhs.data_.f.flags = kNullFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename SourceAllocator>
|
template <typename SourceAllocator>
|
||||||
@ -1791,7 +1991,6 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Data data_;
|
Data data_;
|
||||||
unsigned flags_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! GenericValue with UTF8 encoding
|
//! GenericValue with UTF8 encoding
|
||||||
@ -2196,20 +2395,159 @@ GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,Sourc
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kStringType:
|
case kStringType:
|
||||||
if (rhs.flags_ == kConstStringFlag) {
|
if (rhs.data_.f.flags == kConstStringFlag) {
|
||||||
flags_ = rhs.flags_;
|
data_.f.flags = rhs.data_.f.flags;
|
||||||
data_ = *reinterpret_cast<const Data*>(&rhs.data_);
|
data_ = *reinterpret_cast<const Data*>(&rhs.data_);
|
||||||
} else {
|
} else {
|
||||||
SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
|
SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
flags_ = rhs.flags_;
|
data_.f.flags = rhs.data_.f.flags;
|
||||||
data_ = *reinterpret_cast<const Data*>(&rhs.data_);
|
data_ = *reinterpret_cast<const Data*>(&rhs.data_);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! 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
|
||||||
|
@ -265,7 +265,8 @@
|
|||||||
\param x pointer to align
|
\param x pointer to align
|
||||||
|
|
||||||
Some machines require strict data alignment. Currently the default uses 4 bytes
|
Some machines require strict data alignment. Currently the default uses 4 bytes
|
||||||
alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.
|
alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
|
||||||
|
User can customize by defining the RAPIDJSON_ALIGN function macro.
|
||||||
*/
|
*/
|
||||||
#ifndef RAPIDJSON_ALIGN
|
#ifndef RAPIDJSON_ALIGN
|
||||||
#if RAPIDJSON_64BIT == 1
|
#if RAPIDJSON_64BIT == 1
|
||||||
@ -288,6 +289,36 @@
|
|||||||
#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
|
#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||||
|
|
||||||
|
//! Use only lower 48-bit address for some pointers.
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
|
||||||
|
This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.
|
||||||
|
The higher 16-bit can be used for storing other data.
|
||||||
|
\c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||||
|
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
|
||||||
|
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0
|
||||||
|
#endif
|
||||||
|
#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||||
|
|
||||||
|
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1
|
||||||
|
#if RAPIDJSON_64BIT != 1
|
||||||
|
#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
|
||||||
|
#endif
|
||||||
|
#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
|
||||||
|
#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
|
||||||
|
#define RAPIDJSON_GETPOINTER(type, p) (p)
|
||||||
|
#endif
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
|
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
|
||||||
|
|
||||||
@ -530,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
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -23,6 +23,18 @@ RAPIDJSON_DIAG_OFF(c++98-compat)
|
|||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
TEST(Value, Size) {
|
||||||
|
if (sizeof(SizeType) == 4) {
|
||||||
|
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||||
|
EXPECT_EQ(16, sizeof(Value));
|
||||||
|
#elif RAPIDJSON_64BIT
|
||||||
|
EXPECT_EQ(24, sizeof(Value));
|
||||||
|
#else
|
||||||
|
EXPECT_EQ(16, sizeof(Value));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Value, DefaultConstructor) {
|
TEST(Value, DefaultConstructor) {
|
||||||
Value x;
|
Value x;
|
||||||
EXPECT_EQ(kNullType, x.GetType());
|
EXPECT_EQ(kNullType, x.GetType());
|
||||||
@ -335,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) {
|
||||||
@ -414,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) {
|
||||||
@ -453,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) {
|
||||||
@ -505,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) {
|
||||||
@ -547,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) {
|
||||||
@ -577,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) {
|
||||||
@ -604,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) {
|
||||||
@ -724,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";
|
||||||
@ -759,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
|
||||||
}
|
}
|
||||||
@ -769,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;
|
||||||
@ -834,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;
|
||||||
@ -853,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;
|
||||||
@ -939,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
|
||||||
@ -962,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);
|
||||||
@ -1215,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);
|
||||||
|
|
||||||
@ -1238,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;
|
||||||
@ -1245,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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user