Merge master and implement kParseFullPrecision
This commit is contained in:
commit
881c91d696
@ -1993,7 +1993,9 @@ INCLUDE_FILE_PATTERNS =
|
|||||||
|
|
||||||
PREDEFINED = \
|
PREDEFINED = \
|
||||||
RAPIDJSON_DOXYGEN_RUNNING \
|
RAPIDJSON_DOXYGEN_RUNNING \
|
||||||
RAPIDJSON_DISABLEIF_RETURN(cond,returntype)=returntype
|
RAPIDJSON_REMOVEFPTR_(x)=x \
|
||||||
|
RAPIDJSON_ENABLEIF_RETURN(cond,returntype)="RAPIDJSON_REMOVEFPTR_ returntype" \
|
||||||
|
RAPIDJSON_DISABLEIF_RETURN(cond,returntype)="RAPIDJSON_REMOVEFPTR_ returntype"
|
||||||
|
|
||||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||||
# tag can be used to specify a list of macro names that should be expanded. The
|
# tag can be used to specify a list of macro names that should be expanded. The
|
||||||
@ -2002,7 +2004,8 @@ PREDEFINED = \
|
|||||||
# definition found in the source code.
|
# definition found in the source code.
|
||||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||||
|
|
||||||
EXPAND_AS_DEFINED =
|
EXPAND_AS_DEFINED = \
|
||||||
|
RAPIDJSON_NOEXCEPT
|
||||||
|
|
||||||
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
|
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
|
||||||
# remove all references to function-like macros that are alone on a line, have
|
# remove all references to function-like macros that are alone on a line, have
|
||||||
|
@ -31,6 +31,7 @@ struct CapitalizeFilter {
|
|||||||
return out_.String(&buffer_.front(), length, true); // true = output handler need to copy the string
|
return out_.String(&buffer_.front(), length, true); // true = output handler need to copy the string
|
||||||
}
|
}
|
||||||
bool StartObject() { return out_.StartObject(); }
|
bool StartObject() { return out_.StartObject(); }
|
||||||
|
bool Key(const char* str, SizeType length, bool copy) { return String(str, length, copy); }
|
||||||
bool EndObject(SizeType memberCount) { return out_.EndObject(memberCount); }
|
bool EndObject(SizeType memberCount) { return out_.EndObject(memberCount); }
|
||||||
bool StartArray() { return out_.StartArray(); }
|
bool StartArray() { return out_.StartArray(); }
|
||||||
bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); }
|
bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); }
|
||||||
|
@ -17,6 +17,10 @@ struct MyHandler {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool StartObject() { cout << "StartObject()" << endl; return true; }
|
bool StartObject() { cout << "StartObject()" << endl; return true; }
|
||||||
|
bool Key(const char* str, SizeType length, bool copy) {
|
||||||
|
cout << "Key(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; }
|
bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; }
|
||||||
bool StartArray() { cout << "StartArray()" << endl; return true; }
|
bool StartArray() { cout << "StartArray()" << endl; return true; }
|
||||||
bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; }
|
bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; }
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
/*! \file document.h */
|
/*! \file document.h */
|
||||||
|
|
||||||
#include "reader.h"
|
#include "reader.h"
|
||||||
|
#include "internal/meta.h"
|
||||||
#include "internal/strfunc.h"
|
#include "internal/strfunc.h"
|
||||||
#include <new> // placement new
|
#include <new> // placement new
|
||||||
|
|
||||||
@ -38,15 +39,17 @@ RAPIDJSON_DIAG_OFF(effc++)
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// RAPIDJSON_HAS_STDSTRING
|
// RAPIDJSON_HAS_STDSTRING
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_HAS_STDSTRING
|
||||||
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||||
#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
|
#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
|
||||||
#endif
|
#endif
|
||||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
|
||||||
/*! \def RAPIDJSON_HAS_STDSTRING
|
/*! \def RAPIDJSON_HAS_STDSTRING
|
||||||
\ingroup RAPIDJSON_CONFIG
|
\ingroup RAPIDJSON_CONFIG
|
||||||
\brief Enable RapidJSON support for \c std::string
|
\brief Enable RapidJSON support for \c std::string
|
||||||
|
|
||||||
By defining this preprocessor symbol, several convenience functions for using
|
By defining this preprocessor symbol to \c 1, several convenience functions for using
|
||||||
\ref rapidjson::GenericValue with \c std::string are enabled, especially
|
\ref rapidjson::GenericValue with \c std::string are enabled, especially
|
||||||
for construction and comparison.
|
for construction and comparison.
|
||||||
|
|
||||||
@ -56,7 +59,6 @@ RAPIDJSON_DIAG_OFF(effc++)
|
|||||||
#endif // RAPIDJSON_HAS_STDSTRING
|
#endif // RAPIDJSON_HAS_STDSTRING
|
||||||
|
|
||||||
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
|
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
|
||||||
#include "internal/meta.h"
|
|
||||||
#include <iterator> // std::iterator, std::random_access_iterator_tag
|
#include <iterator> // std::iterator, std::random_access_iterator_tag
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -277,7 +279,7 @@ struct GenericStringRef {
|
|||||||
GenericValue instead.
|
GenericValue instead.
|
||||||
*/
|
*/
|
||||||
template<SizeType N>
|
template<SizeType N>
|
||||||
GenericStringRef(const CharType (&str)[N])
|
GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
|
||||||
: s(str), length(N-1) {}
|
: s(str), length(N-1) {}
|
||||||
|
|
||||||
//! Explicitly create string reference from \c const character pointer
|
//! Explicitly create string reference from \c const character pointer
|
||||||
@ -300,7 +302,7 @@ struct GenericStringRef {
|
|||||||
GenericValue instead.
|
GenericValue instead.
|
||||||
*/
|
*/
|
||||||
explicit GenericStringRef(const CharType* str)
|
explicit GenericStringRef(const CharType* str)
|
||||||
: s(str), length(internal::StrLen(str)){}
|
: s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); }
|
||||||
|
|
||||||
//! Create constant string reference from pointer and length
|
//! Create constant string reference from pointer and length
|
||||||
/*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
|
/*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
|
||||||
@ -363,7 +365,7 @@ inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length)
|
|||||||
return GenericStringRef<CharType>(str, SizeType(length));
|
return GenericStringRef<CharType>(str, SizeType(length));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
//! Mark a string object as constant string
|
//! Mark a string object as constant string
|
||||||
/*! Mark a string object (e.g. \c std::string) as a "string literal".
|
/*! Mark a string object (e.g. \c std::string) as a "string literal".
|
||||||
This function can be used to avoid copying a string to be referenced as a
|
This function can be used to avoid copying a string to be referenced as a
|
||||||
@ -382,6 +384,22 @@ inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& s
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// GenericValue type traits
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
template <typename T, typename Encoding = void, typename Allocator = void>
|
||||||
|
struct IsGenericValueImpl : FalseType {};
|
||||||
|
|
||||||
|
// select candidates according to nested encoding and allocator types
|
||||||
|
template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type>
|
||||||
|
: IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {};
|
||||||
|
|
||||||
|
// helper to match arbitrary GenericValue instantiations, including derived classes
|
||||||
|
template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// GenericValue
|
// GenericValue
|
||||||
|
|
||||||
@ -414,7 +432,14 @@ public:
|
|||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Default constructor creates a null value.
|
//! Default constructor creates a null value.
|
||||||
GenericValue() : data_(), flags_(kNullFlag) {}
|
GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
//! Move constructor in C++11
|
||||||
|
GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) {
|
||||||
|
rhs.flags_ = kNullFlag; // give up contents
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! Copy constructor is not permitted.
|
//! Copy constructor is not permitted.
|
||||||
@ -427,7 +452,7 @@ 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.
|
||||||
*/
|
*/
|
||||||
GenericValue(Type type) : data_(), flags_() {
|
GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() {
|
||||||
static const unsigned defaultFlags[7] = {
|
static const unsigned defaultFlags[7] = {
|
||||||
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag,
|
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag,
|
||||||
kNumberAnyFlag
|
kNumberAnyFlag
|
||||||
@ -444,7 +469,7 @@ public:
|
|||||||
\see CopyFrom()
|
\see CopyFrom()
|
||||||
*/
|
*/
|
||||||
template< typename SourceAllocator >
|
template< typename SourceAllocator >
|
||||||
GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator & allocator);
|
GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
|
||||||
|
|
||||||
//! Constructor for boolean value.
|
//! Constructor for boolean value.
|
||||||
/*! \param b Boolean value
|
/*! \param b Boolean value
|
||||||
@ -454,28 +479,31 @@ public:
|
|||||||
*/
|
*/
|
||||||
#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
|
#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
|
||||||
template <typename T>
|
template <typename T>
|
||||||
explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>)))
|
explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>))) RAPIDJSON_NOEXCEPT
|
||||||
#else
|
#else
|
||||||
explicit GenericValue(bool b)
|
explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
|
||||||
#endif
|
#endif
|
||||||
: data_(), flags_(b ? kTrueFlag : kFalseFlag) {}
|
: data_(), flags_(b ? kTrueFlag : kFalseFlag) {
|
||||||
|
// safe-guard against failing SFINAE
|
||||||
|
RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
|
||||||
|
}
|
||||||
|
|
||||||
//! Constructor for int value.
|
//! Constructor for int value.
|
||||||
explicit GenericValue(int i) : data_(), flags_(kNumberIntFlag) {
|
explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) {
|
||||||
data_.n.i64 = i;
|
data_.n.i64 = i;
|
||||||
if (i >= 0)
|
if (i >= 0)
|
||||||
flags_ |= kUintFlag | kUint64Flag;
|
flags_ |= kUintFlag | kUint64Flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Constructor for unsigned value.
|
//! Constructor for unsigned value.
|
||||||
explicit GenericValue(unsigned u) : data_(), flags_(kNumberUintFlag) {
|
explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) {
|
||||||
data_.n.u64 = u;
|
data_.n.u64 = u;
|
||||||
if (!(u & 0x80000000))
|
if (!(u & 0x80000000))
|
||||||
flags_ |= kIntFlag | kInt64Flag;
|
flags_ |= kIntFlag | kInt64Flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Constructor for int64_t value.
|
//! Constructor for int64_t value.
|
||||||
explicit GenericValue(int64_t i64) : data_(), flags_(kNumberInt64Flag) {
|
explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt64Flag) {
|
||||||
data_.n.i64 = i64;
|
data_.n.i64 = i64;
|
||||||
if (i64 >= 0) {
|
if (i64 >= 0) {
|
||||||
flags_ |= kNumberUint64Flag;
|
flags_ |= kNumberUint64Flag;
|
||||||
@ -489,7 +517,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Constructor for uint64_t value.
|
//! Constructor for uint64_t value.
|
||||||
explicit GenericValue(uint64_t u64) : data_(), flags_(kNumberUint64Flag) {
|
explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) {
|
||||||
data_.n.u64 = u64;
|
data_.n.u64 = u64;
|
||||||
if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
|
if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
|
||||||
flags_ |= kInt64Flag;
|
flags_ |= kInt64Flag;
|
||||||
@ -500,13 +528,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Constructor for double value.
|
//! Constructor for double value.
|
||||||
explicit GenericValue(double d) : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; }
|
explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; }
|
||||||
|
|
||||||
//! 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) : data_(), flags_() { SetStringRaw(StringRef(s, length)); }
|
GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { 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) : data_(), flags_() { SetStringRaw(s); }
|
explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { 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_(), flags_() { SetStringRaw(StringRef(s, length), allocator); }
|
||||||
@ -514,7 +542,7 @@ public:
|
|||||||
//! 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_(), flags_() { SetStringRaw(StringRef(s), allocator); }
|
||||||
|
|
||||||
#ifdef 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.
|
||||||
*/
|
*/
|
||||||
@ -557,19 +585,26 @@ public:
|
|||||||
//! Assignment with move semantics.
|
//! Assignment with move semantics.
|
||||||
/*! \param rhs Source of the assignment. It will become a null value after assignment.
|
/*! \param rhs Source of the assignment. It will become a null value after assignment.
|
||||||
*/
|
*/
|
||||||
GenericValue& operator=(GenericValue& rhs) {
|
GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
|
||||||
RAPIDJSON_ASSERT(this != &rhs);
|
RAPIDJSON_ASSERT(this != &rhs);
|
||||||
this->~GenericValue();
|
this->~GenericValue();
|
||||||
RawAssign(rhs);
|
RawAssign(rhs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
//! Move assignment in C++11
|
||||||
|
GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {
|
||||||
|
return *this = rhs.Move();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//! Assignment of constant string reference (no copy)
|
//! Assignment of constant string reference (no copy)
|
||||||
/*! \param str Constant string reference to be assigned
|
/*! \param str Constant string reference to be assigned
|
||||||
\note This overload is needed to avoid clashes with the generic primitive type assignment overload below.
|
\note This overload is needed to avoid clashes with the generic primitive type assignment overload below.
|
||||||
\see GenericStringRef, operator=(T)
|
\see GenericStringRef, operator=(T)
|
||||||
*/
|
*/
|
||||||
GenericValue& operator=(StringRefType str) {
|
GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {
|
||||||
GenericValue s(str);
|
GenericValue s(str);
|
||||||
return *this = s;
|
return *this = s;
|
||||||
}
|
}
|
||||||
@ -587,7 +622,7 @@ public:
|
|||||||
use \ref SetBool() instead.
|
use \ref SetBool() instead.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,GenericValue&)
|
RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
|
||||||
operator=(T value) {
|
operator=(T value) {
|
||||||
GenericValue v(value);
|
GenericValue v(value);
|
||||||
return *this = v;
|
return *this = v;
|
||||||
@ -600,10 +635,10 @@ public:
|
|||||||
\param allocator Allocator to use for copying
|
\param allocator Allocator to use for copying
|
||||||
*/
|
*/
|
||||||
template <typename SourceAllocator>
|
template <typename SourceAllocator>
|
||||||
GenericValue& CopyFrom(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator) {
|
GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
|
||||||
RAPIDJSON_ASSERT((void*)this != (void const*)&rhs);
|
RAPIDJSON_ASSERT((void*)this != (void const*)&rhs);
|
||||||
this->~GenericValue();
|
this->~GenericValue();
|
||||||
new (this) GenericValue(rhs,allocator);
|
new (this) GenericValue(rhs, allocator);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,7 +647,7 @@ public:
|
|||||||
\param other Another value.
|
\param other Another value.
|
||||||
\note Constant complexity.
|
\note Constant complexity.
|
||||||
*/
|
*/
|
||||||
GenericValue& Swap(GenericValue& other) {
|
GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {
|
||||||
GenericValue temp;
|
GenericValue temp;
|
||||||
temp.RawAssign(*this);
|
temp.RawAssign(*this);
|
||||||
RawAssign(other);
|
RawAssign(other);
|
||||||
@ -622,7 +657,7 @@ public:
|
|||||||
|
|
||||||
//! Prepare Value for move semantics
|
//! Prepare Value for move semantics
|
||||||
/*! \return *this */
|
/*! \return *this */
|
||||||
GenericValue& Move() { return *this; }
|
GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
//!@name Equal-to and not-equal-to operators
|
//!@name Equal-to and not-equal-to operators
|
||||||
@ -632,7 +667,9 @@ public:
|
|||||||
\note If an object contains duplicated named member, comparing equality with any object is always \c false.
|
\note If an object contains duplicated named member, comparing equality with any object is always \c false.
|
||||||
\note Linear time complexity (number of all values in the subtree and total lengths of all strings).
|
\note Linear time complexity (number of all values in the subtree and total lengths of all strings).
|
||||||
*/
|
*/
|
||||||
bool operator==(const GenericValue& rhs) const {
|
template <typename SourceAllocator>
|
||||||
|
bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
|
||||||
|
typedef GenericValue<Encoding, SourceAllocator> RhsType;
|
||||||
if (GetType() != rhs.GetType())
|
if (GetType() != rhs.GetType())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -641,7 +678,7 @@ public:
|
|||||||
if (data_.o.size != rhs.data_.o.size)
|
if (data_.o.size != rhs.data_.o.size)
|
||||||
return false;
|
return false;
|
||||||
for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
|
for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
|
||||||
ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
|
typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
|
||||||
if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
|
if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -659,7 +696,7 @@ public:
|
|||||||
return StringEqual(rhs);
|
return StringEqual(rhs);
|
||||||
|
|
||||||
case kNumberType:
|
case kNumberType:
|
||||||
if (IsDouble() || rhs.GetDouble())
|
if (IsDouble() || rhs.IsDouble())
|
||||||
return GetDouble() == rhs.GetDouble(); // May convert one operand from integer to double.
|
return GetDouble() == rhs.GetDouble(); // May convert one operand from integer to double.
|
||||||
else
|
else
|
||||||
return data_.n.u64 == rhs.data_.n.u64;
|
return data_.n.u64 == rhs.data_.n.u64;
|
||||||
@ -672,7 +709,7 @@ public:
|
|||||||
//! Equal-to operator with const C-string pointer
|
//! Equal-to operator with const C-string pointer
|
||||||
bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }
|
bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }
|
||||||
|
|
||||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
//! Equal-to operator with string object
|
//! Equal-to operator with string object
|
||||||
/*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
|
/*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
|
||||||
*/
|
*/
|
||||||
@ -682,22 +719,31 @@ public:
|
|||||||
//! Equal-to operator with primitive types
|
//! Equal-to operator with primitive types
|
||||||
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
|
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
|
||||||
*/
|
*/
|
||||||
template <typename T> RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>, bool) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
|
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
|
||||||
|
|
||||||
|
//! Not-equal-to operator
|
||||||
|
/*! \return !(*this == rhs)
|
||||||
|
*/
|
||||||
|
template <typename SourceAllocator>
|
||||||
|
bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); }
|
||||||
|
|
||||||
|
//! Not-equal-to operator with const C-string pointer
|
||||||
|
bool operator!=(const Ch* rhs) const { return !(*this == rhs); }
|
||||||
|
|
||||||
//! Not-equal-to operator with arbitrary types
|
//! Not-equal-to operator with arbitrary types
|
||||||
/*! \return !(*this == rhs)
|
/*! \return !(*this == rhs)
|
||||||
*/
|
*/
|
||||||
template <typename T> bool operator!=(const T& rhs) const { return !(*this == rhs); }
|
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
|
||||||
|
|
||||||
//! Equal-to operator with arbitrary types (symmetric version)
|
//! Equal-to operator with arbitrary types (symmetric version)
|
||||||
/*! \return (rhs == lhs)
|
/*! \return (rhs == lhs)
|
||||||
*/
|
*/
|
||||||
template <typename T> friend bool operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
|
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
|
||||||
|
|
||||||
//! Not-Equal-to operator with arbitrary types (symmetric version)
|
//! Not-Equal-to operator with arbitrary types (symmetric version)
|
||||||
/*! \return !(rhs == lhs)
|
/*! \return !(rhs == lhs)
|
||||||
*/
|
*/
|
||||||
template <typename T> friend bool operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
|
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
//!@name Type
|
//!@name Type
|
||||||
@ -766,7 +812,8 @@ public:
|
|||||||
|
|
||||||
// This version is faster because it does not need a StrLen().
|
// This version is faster because it does not need a StrLen().
|
||||||
// It can also handle string with null character.
|
// It can also handle string with null character.
|
||||||
GenericValue& operator[](const GenericValue& name) {
|
template <typename SourceAllocator>
|
||||||
|
GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {
|
||||||
MemberIterator member = FindMember(name);
|
MemberIterator member = FindMember(name);
|
||||||
if (member != MemberEnd())
|
if (member != MemberEnd())
|
||||||
return member->value;
|
return member->value;
|
||||||
@ -776,7 +823,8 @@ public:
|
|||||||
return NullValue;
|
return NullValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const GenericValue& operator[](const GenericValue& name) const { return const_cast<GenericValue&>(*this)[name]; }
|
template <typename SourceAllocator>
|
||||||
|
const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }
|
||||||
|
|
||||||
//! Const member iterator
|
//! Const member iterator
|
||||||
/*! \pre IsObject() == true */
|
/*! \pre IsObject() == true */
|
||||||
@ -810,7 +858,8 @@ public:
|
|||||||
\note It is better to use FindMember() directly if you need the obtain the value as well.
|
\note It is better to use FindMember() directly if you need the obtain the value as well.
|
||||||
\note Linear time complexity.
|
\note Linear time complexity.
|
||||||
*/
|
*/
|
||||||
bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); }
|
template <typename SourceAllocator>
|
||||||
|
bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }
|
||||||
|
|
||||||
//! Find member by name.
|
//! Find member by name.
|
||||||
/*!
|
/*!
|
||||||
@ -844,7 +893,8 @@ public:
|
|||||||
\c std::map, this has been changed to MemberEnd() now.
|
\c std::map, this has been changed to MemberEnd() now.
|
||||||
\note Linear time complexity.
|
\note Linear time complexity.
|
||||||
*/
|
*/
|
||||||
MemberIterator FindMember(const GenericValue& name) {
|
template <typename SourceAllocator>
|
||||||
|
MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
|
||||||
RAPIDJSON_ASSERT(IsObject());
|
RAPIDJSON_ASSERT(IsObject());
|
||||||
RAPIDJSON_ASSERT(name.IsString());
|
RAPIDJSON_ASSERT(name.IsString());
|
||||||
MemberIterator member = MemberBegin();
|
MemberIterator member = MemberBegin();
|
||||||
@ -853,7 +903,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
return member;
|
return member;
|
||||||
}
|
}
|
||||||
ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
||||||
|
|
||||||
//! Add a member (name-value pair) to the object.
|
//! Add a member (name-value pair) to the object.
|
||||||
/*! \param name A string value as name of member.
|
/*! \param name A string value as name of member.
|
||||||
@ -877,7 +927,7 @@ public:
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SizeType oldCapacity = o.capacity;
|
SizeType oldCapacity = o.capacity;
|
||||||
o.capacity *= 2;
|
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)));
|
o.members = reinterpret_cast<Member*>(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -887,6 +937,23 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {
|
||||||
|
return AddMember(name, value, allocator);
|
||||||
|
}
|
||||||
|
GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) {
|
||||||
|
return AddMember(name, value, allocator);
|
||||||
|
}
|
||||||
|
GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) {
|
||||||
|
return AddMember(name, value, allocator);
|
||||||
|
}
|
||||||
|
GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) {
|
||||||
|
GenericValue n(name);
|
||||||
|
return AddMember(n, value, allocator);
|
||||||
|
}
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
|
||||||
|
|
||||||
//! Add a member (name-value pair) to the object.
|
//! Add a member (name-value pair) to the object.
|
||||||
/*! \param name A constant string reference as name of member.
|
/*! \param name A constant string reference as name of member.
|
||||||
\param value Value of any type.
|
\param value Value of any type.
|
||||||
@ -934,7 +1001,7 @@ public:
|
|||||||
\note Amortized Constant time complexity.
|
\note Amortized Constant time complexity.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,GenericValue&)
|
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
|
||||||
AddMember(StringRefType name, T value, Allocator& allocator) {
|
AddMember(StringRefType name, T value, Allocator& allocator) {
|
||||||
GenericValue n(name);
|
GenericValue n(name);
|
||||||
GenericValue v(value);
|
GenericValue v(value);
|
||||||
@ -963,7 +1030,8 @@ public:
|
|||||||
return RemoveMember(n);
|
return RemoveMember(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemoveMember(const GenericValue& name) {
|
template <typename SourceAllocator>
|
||||||
|
bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
|
||||||
MemberIterator m = FindMember(name);
|
MemberIterator m = FindMember(name);
|
||||||
if (m != MemberEnd()) {
|
if (m != MemberEnd()) {
|
||||||
RemoveMember(m);
|
RemoveMember(m);
|
||||||
@ -1122,11 +1190,17 @@ int z = a[0u].GetInt(); // This works too.
|
|||||||
GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
|
GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
|
||||||
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 * 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);
|
data_.a.elements[data_.a.size++].RawAssign(value);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {
|
||||||
|
return PushBack(value, allocator);
|
||||||
|
}
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
|
||||||
//! Append a constant string reference at the end of the array.
|
//! Append a constant string reference at the end of the array.
|
||||||
/*! \param value Constant string reference to be appended.
|
/*! \param value Constant string reference to be appended.
|
||||||
\param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().
|
\param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().
|
||||||
@ -1158,7 +1232,7 @@ int z = a[0u].GetInt(); // This works too.
|
|||||||
\note Amortized constant time complexity.
|
\note Amortized constant time complexity.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,GenericValue&)
|
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
|
||||||
PushBack(T value, Allocator& allocator) {
|
PushBack(T value, Allocator& allocator) {
|
||||||
GenericValue v(value);
|
GenericValue v(value);
|
||||||
return PushBack(v, allocator);
|
return PushBack(v, allocator);
|
||||||
@ -1239,12 +1313,12 @@ int z = a[0u].GetInt(); // This works too.
|
|||||||
//!@name String
|
//!@name String
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
|
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? data_.ss.str : data_.s.str); }
|
||||||
|
|
||||||
//! 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 data_.s.length; }
|
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((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.
|
||||||
@ -1281,7 +1355,7 @@ int z = a[0u].GetInt(); // This works too.
|
|||||||
*/
|
*/
|
||||||
GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
|
GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
|
||||||
|
|
||||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
//! Set this value as a string by copying from source string.
|
//! Set this value as a string by copying from source string.
|
||||||
/*! \param s source string.
|
/*! \param s source string.
|
||||||
\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
|
\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
|
||||||
@ -1312,7 +1386,7 @@ int z = a[0u].GetInt(); // This works too.
|
|||||||
if (!handler.StartObject())
|
if (!handler.StartObject())
|
||||||
return false;
|
return false;
|
||||||
for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
|
for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
|
||||||
if (!handler.String(m->name.data_.s.str, m->name.data_.s.length, (m->name.flags_ & kCopyFlag) != 0))
|
if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0))
|
||||||
return false;
|
return false;
|
||||||
if (!m->value.Accept(handler))
|
if (!m->value.Accept(handler))
|
||||||
return false;
|
return false;
|
||||||
@ -1328,7 +1402,7 @@ int z = a[0u].GetInt(); // This works too.
|
|||||||
return handler.EndArray(data_.a.size);
|
return handler.EndArray(data_.a.size);
|
||||||
|
|
||||||
case kStringType:
|
case kStringType:
|
||||||
return handler.String(data_.s.str, data_.s.length, (flags_ & kCopyFlag) != 0);
|
return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0);
|
||||||
|
|
||||||
case kNumberType:
|
case kNumberType:
|
||||||
if (IsInt()) return handler.Int(data_.n.i.i);
|
if (IsInt()) return handler.Int(data_.n.i.i);
|
||||||
@ -1344,8 +1418,8 @@ int z = a[0u].GetInt(); // This works too.
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename, typename, typename>
|
template <typename, typename> friend class GenericValue;
|
||||||
friend class GenericDocument;
|
template <typename, typename, typename> friend class GenericDocument;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
kBoolFlag = 0x100,
|
kBoolFlag = 0x100,
|
||||||
@ -1357,6 +1431,7 @@ private:
|
|||||||
kDoubleFlag = 0x4000,
|
kDoubleFlag = 0x4000,
|
||||||
kStringFlag = 0x100000,
|
kStringFlag = 0x100000,
|
||||||
kCopyFlag = 0x200000,
|
kCopyFlag = 0x200000,
|
||||||
|
kInlineStrFlag = 0x400000,
|
||||||
|
|
||||||
// Initial flags of different types.
|
// Initial flags of different types.
|
||||||
kNullFlag = kNullType,
|
kNullFlag = kNullType,
|
||||||
@ -1370,6 +1445,7 @@ private:
|
|||||||
kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
|
kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
|
||||||
kConstStringFlag = kStringType | kStringFlag,
|
kConstStringFlag = kStringType | kStringFlag,
|
||||||
kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
|
kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
|
||||||
|
kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
|
||||||
kObjectFlag = kObjectType,
|
kObjectFlag = kObjectType,
|
||||||
kArrayFlag = kArrayType,
|
kArrayFlag = kArrayType,
|
||||||
|
|
||||||
@ -1385,6 +1461,23 @@ private:
|
|||||||
unsigned hashcode; //!< reserved
|
unsigned hashcode; //!< reserved
|
||||||
}; // 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
|
||||||
|
// (excluding the terminating zero) and store a value to determine the length of the contained
|
||||||
|
// string in the last character str[LenPos] by storing "MaxSize - length" there. If the string
|
||||||
|
// 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
|
||||||
|
// "MaxSize - str[LenPos]".
|
||||||
|
// This allows to store 11-chars strings in 32-bit mode and 15-chars strings in 64-bit mode
|
||||||
|
// inline (for `UTF8`-encoded strings).
|
||||||
|
struct ShortString {
|
||||||
|
enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
|
||||||
|
Ch str[MaxChars];
|
||||||
|
|
||||||
|
inline static bool Usable(SizeType len) { return (MaxSize >= len); }
|
||||||
|
inline void SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - len); }
|
||||||
|
inline SizeType GetLength() const { return (SizeType)(MaxSize - str[LenPos]); }
|
||||||
|
}; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||||
|
|
||||||
// By using proper binary layout, retrieval of different integer types do not need conversions.
|
// By using proper binary layout, retrieval of different integer types do not need conversions.
|
||||||
union Number {
|
union Number {
|
||||||
#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
|
#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
|
||||||
@ -1425,6 +1518,7 @@ private:
|
|||||||
|
|
||||||
union Data {
|
union Data {
|
||||||
String s;
|
String s;
|
||||||
|
ShortString ss;
|
||||||
Number n;
|
Number n;
|
||||||
Object o;
|
Object o;
|
||||||
Array a;
|
Array a;
|
||||||
@ -1447,7 +1541,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Initialize this value as constant string, without calling destructor.
|
//! Initialize this value as constant string, without calling destructor.
|
||||||
void SetStringRaw(StringRefType s) {
|
void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
|
||||||
flags_ = kConstStringFlag;
|
flags_ = kConstStringFlag;
|
||||||
data_.s.str = s;
|
data_.s.str = s;
|
||||||
data_.s.length = s.length;
|
data_.s.length = s.length;
|
||||||
@ -1455,26 +1549,42 @@ private:
|
|||||||
|
|
||||||
//! 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;
|
||||||
|
if(ShortString::Usable(s.length)) {
|
||||||
|
flags_ = kShortStringFlag;
|
||||||
|
data_.ss.SetLength(s.length);
|
||||||
|
str = data_.ss.str;
|
||||||
|
} else {
|
||||||
flags_ = kCopyStringFlag;
|
flags_ = kCopyStringFlag;
|
||||||
data_.s.str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch));
|
|
||||||
data_.s.length = s.length;
|
data_.s.length = s.length;
|
||||||
memcpy(const_cast<Ch*>(data_.s.str), s, s.length * sizeof(Ch));
|
str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch));
|
||||||
const_cast<Ch*>(data_.s.str)[s.length] = '\0';
|
data_.s.str = str;
|
||||||
|
}
|
||||||
|
memcpy(str, s, s.length * sizeof(Ch));
|
||||||
|
str[s.length] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Assignment without calling destructor
|
//! Assignment without calling destructor
|
||||||
void RawAssign(GenericValue& rhs) {
|
void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
|
||||||
data_ = rhs.data_;
|
data_ = rhs.data_;
|
||||||
flags_ = rhs.flags_;
|
flags_ = rhs.flags_;
|
||||||
rhs.flags_ = kNullFlag;
|
rhs.flags_ = kNullFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StringEqual(const GenericValue& rhs) const {
|
template <typename SourceAllocator>
|
||||||
|
bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {
|
||||||
RAPIDJSON_ASSERT(IsString());
|
RAPIDJSON_ASSERT(IsString());
|
||||||
RAPIDJSON_ASSERT(rhs.IsString());
|
RAPIDJSON_ASSERT(rhs.IsString());
|
||||||
return data_.s.length == rhs.data_.s.length &&
|
|
||||||
(data_.s.str == rhs.data_.s.str // fast path for constant string
|
const SizeType len1 = GetStringLength();
|
||||||
|| memcmp(data_.s.str, rhs.data_.s.str, sizeof(Ch) * data_.s.length) == 0);
|
const SizeType len2 = rhs.GetStringLength();
|
||||||
|
if(len1 != len2) { return false; }
|
||||||
|
|
||||||
|
const Ch* const str1 = GetString();
|
||||||
|
const Ch* const str2 = rhs.GetString();
|
||||||
|
if(str1 == str2) { return true; } // fast path for constant string
|
||||||
|
|
||||||
|
return (memcmp(str1, str2, sizeof(Ch) * len1) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Data data_;
|
Data data_;
|
||||||
@ -1663,7 +1773,7 @@ private:
|
|||||||
|
|
||||||
// callers of the following private Handler functions
|
// callers of the following private Handler functions
|
||||||
template <typename,typename,typename> friend class GenericReader; // for parsing
|
template <typename,typename,typename> friend class GenericReader; // for parsing
|
||||||
friend class GenericValue<Encoding,Allocator>; // for deep copying
|
template <typename, typename> friend class GenericValue; // for deep copying
|
||||||
|
|
||||||
// Implementation of Handler
|
// Implementation of Handler
|
||||||
bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
|
bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
|
||||||
@ -1684,6 +1794,8 @@ private:
|
|||||||
|
|
||||||
bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
|
bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
|
||||||
|
|
||||||
|
bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }
|
||||||
|
|
||||||
bool EndObject(SizeType memberCount) {
|
bool EndObject(SizeType memberCount) {
|
||||||
typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
|
typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
|
||||||
stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
|
stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
|
||||||
|
@ -21,57 +21,129 @@
|
|||||||
#ifndef RAPIDJSON_INTERNAL_META_H_
|
#ifndef RAPIDJSON_INTERNAL_META_H_
|
||||||
#define RAPIDJSON_INTERNAL_META_H_
|
#define RAPIDJSON_INTERNAL_META_H_
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_RAPIDJSON_H_
|
||||||
|
#error <rapidjson.h> not yet included. Do not include this file directly.
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(effc++)
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(6334)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
#include <type_traits>
|
||||||
|
#endif
|
||||||
|
|
||||||
//@cond RAPIDJSON_INTERNAL
|
//@cond RAPIDJSON_INTERNAL
|
||||||
namespace rapidjson {
|
namespace rapidjson {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template <int N> struct IntegralC { enum { Value = N }; };
|
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
|
||||||
template <bool Cond> struct BoolType : IntegralC<Cond> {};
|
template <typename T> struct Void { typedef void Type; };
|
||||||
struct TrueType : BoolType<true> {};
|
|
||||||
struct FalseType : BoolType<false> {};
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// BoolType, TrueType, FalseType
|
||||||
|
//
|
||||||
|
template <bool Cond> struct BoolType {
|
||||||
|
static const bool Value = Cond;
|
||||||
|
typedef BoolType Type;
|
||||||
|
};
|
||||||
|
typedef BoolType<true> TrueType;
|
||||||
|
typedef BoolType<false> FalseType;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
|
||||||
|
//
|
||||||
|
|
||||||
|
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
|
||||||
|
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
|
||||||
|
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
|
||||||
|
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
|
||||||
|
|
||||||
|
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
|
||||||
|
template <> struct AndExprCond<true, true> : TrueType {};
|
||||||
|
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
|
||||||
|
template <> struct OrExprCond<false, false> : FalseType {};
|
||||||
|
|
||||||
|
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
|
||||||
|
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
|
||||||
|
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
|
||||||
|
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AddConst, MaybeAddConst, RemoveConst
|
||||||
template <typename T> struct AddConst { typedef const T Type; };
|
template <typename T> struct AddConst { typedef const T Type; };
|
||||||
|
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||||
template <typename T> struct RemoveConst { typedef T Type; };
|
template <typename T> struct RemoveConst { typedef T Type; };
|
||||||
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||||
|
|
||||||
template <bool Condition, typename T1, typename T2> struct SelectIfCond;
|
|
||||||
template <typename T1, typename T2> struct SelectIfCond<true,T1,T2> { typedef T1 Type; };
|
|
||||||
template <typename T1, typename T2> struct SelectIfCond<false,T1,T2> { typedef T2 Type; };
|
|
||||||
|
|
||||||
template <typename Condition, typename T1, typename T2>
|
|
||||||
struct SelectIf : SelectIfCond<Condition::Value,T1,T2> {};
|
|
||||||
|
|
||||||
template <bool Constify, typename T>
|
|
||||||
struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// IsSame, IsConst, IsMoreConst, IsPointer
|
||||||
|
//
|
||||||
template <typename T, typename U> struct IsSame : FalseType {};
|
template <typename T, typename U> struct IsSame : FalseType {};
|
||||||
template <typename T> struct IsSame<T,T> : TrueType {};
|
template <typename T> struct IsSame<T, T> : TrueType {};
|
||||||
|
|
||||||
template <typename T> struct IsConst : FalseType {};
|
template <typename T> struct IsConst : FalseType {};
|
||||||
template <typename T> struct IsConst<const T> : TrueType {};
|
template <typename T> struct IsConst<const T> : TrueType {};
|
||||||
|
|
||||||
|
template <typename CT, typename T>
|
||||||
|
struct IsMoreConst
|
||||||
|
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
|
||||||
|
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
|
||||||
|
|
||||||
template <typename T> struct IsPointer : FalseType {};
|
template <typename T> struct IsPointer : FalseType {};
|
||||||
template <typename T> struct IsPointer<T*> : TrueType {};
|
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||||
|
|
||||||
template <typename CT, typename T>
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
struct IsMoreConst {
|
// IsBaseOf
|
||||||
enum { Value =
|
//
|
||||||
( IsSame< typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>::Value
|
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
&& ( IsConst<CT>::Value >= IsConst<T>::Value ) )
|
|
||||||
|
template <typename B, typename D> struct IsBaseOf
|
||||||
|
: BoolType< ::std::is_base_of<B,D>::value> {};
|
||||||
|
|
||||||
|
#else // simplified version adopted from Boost
|
||||||
|
|
||||||
|
template<typename B, typename D> struct IsBaseOfImpl {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
|
||||||
|
|
||||||
|
typedef char (&Yes)[1];
|
||||||
|
typedef char (&No) [2];
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static Yes Check(const D*, T);
|
||||||
|
static No Check(const B*, int);
|
||||||
|
|
||||||
|
struct Host {
|
||||||
|
operator const B*() const;
|
||||||
|
operator const D*();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
|
||||||
};
|
};
|
||||||
|
|
||||||
template <bool Condition, typename T = void> struct EnableIfCond;
|
template <typename B, typename D> struct IsBaseOf
|
||||||
template <typename T> struct EnableIfCond<true, T> { typedef T Type; };
|
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// EnableIf / DisableIf
|
||||||
|
//
|
||||||
|
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
|
||||||
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||||
|
|
||||||
template <bool Condition, typename T = void>
|
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
|
||||||
struct DisableIfCond : EnableIfCond<!Condition, T> {};
|
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
|
||||||
|
|
||||||
template <typename Condition, typename T = void>
|
template <typename Condition, typename T = void>
|
||||||
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||||
@ -80,26 +152,37 @@ template <typename Condition, typename T = void>
|
|||||||
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||||
|
|
||||||
// SFINAE helpers
|
// SFINAE helpers
|
||||||
struct SfinaeResultTag {};
|
struct SfinaeTag {};
|
||||||
template <typename T> struct RemoveSfinaeFptr {};
|
template <typename T> struct RemoveSfinaeTag;
|
||||||
template <typename T> struct RemoveSfinaeFptr<SfinaeResultTag&(*)(T)> { typedef T Type; };
|
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
|
||||||
|
|
||||||
#define RAPIDJSON_REMOVEFPTR_(type) \
|
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||||
typename ::rapidjson::internal::RemoveSfinaeFptr \
|
typename ::rapidjson::internal::RemoveSfinaeTag \
|
||||||
< ::rapidjson::internal::SfinaeResultTag&(*) type>::Type
|
< ::rapidjson::internal::SfinaeTag&(*) type>::Type
|
||||||
|
|
||||||
#define RAPIDJSON_ENABLEIF(cond) \
|
#define RAPIDJSON_ENABLEIF(cond) \
|
||||||
typename ::rapidjson::internal::EnableIf \
|
typename ::rapidjson::internal::EnableIf \
|
||||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||||
|
|
||||||
|
#define RAPIDJSON_DISABLEIF(cond) \
|
||||||
|
typename ::rapidjson::internal::DisableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
|
||||||
|
typename ::rapidjson::internal::EnableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||||
|
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||||
|
|
||||||
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||||
typename ::rapidjson::internal::DisableIf<cond,returntype>::Type
|
typename ::rapidjson::internal::DisableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||||
|
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace rapidjson
|
} // namespace rapidjson
|
||||||
//@endcond
|
//@endcond
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -88,6 +88,8 @@ public:
|
|||||||
return Base::WriteStartObject();
|
return Base::WriteStartObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
|
||||||
|
|
||||||
bool EndObject(SizeType memberCount = 0) {
|
bool EndObject(SizeType memberCount = 0) {
|
||||||
(void)memberCount;
|
(void)memberCount;
|
||||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||||
@ -135,6 +137,7 @@ public:
|
|||||||
|
|
||||||
//! Simpler but slower overload.
|
//! Simpler but slower overload.
|
||||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||||
|
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
protected:
|
protected:
|
||||||
|
@ -318,7 +318,12 @@ template<int x> struct StaticAssertTest {};
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
|
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
|
||||||
|
|
||||||
#if defined(__clang__) || (defined(__GNUC__) && RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) >= RAPIDJSON_VERSION_CODE(4,2,0))
|
#if defined(__GNUC__)
|
||||||
|
#define RAPIDJSON_GNUC \
|
||||||
|
RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
|
||||||
|
|
||||||
#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
|
#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
|
||||||
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
|
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
|
||||||
@ -326,7 +331,7 @@ template<int x> struct StaticAssertTest {};
|
|||||||
RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
|
RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
|
||||||
|
|
||||||
// push/pop support in Clang and GCC>=4.6
|
// push/pop support in Clang and GCC>=4.6
|
||||||
#if defined(__clang__) || (defined(__GNUC__) && RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) >= RAPIDJSON_VERSION_CODE(4,6,0))
|
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
|
||||||
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
|
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
|
||||||
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
|
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
|
||||||
#else // GCC >= 4.2, < 4.6
|
#else // GCC >= 4.2, < 4.6
|
||||||
@ -352,6 +357,42 @@ template<int x> struct StaticAssertTest {};
|
|||||||
|
|
||||||
#endif // RAPIDJSON_DIAG_*
|
#endif // RAPIDJSON_DIAG_*
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// C++11 features
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS __has_feature(cxx_rvalue_references)
|
||||||
|
#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_RVALUE_REFS 1
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
|
||||||
|
#endif
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
|
||||||
|
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||||
|
// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
|
||||||
|
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||||
|
#define RAPIDJSON_NOEXCEPT noexcept
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_NOEXCEPT /* noexcept */
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||||
|
|
||||||
|
// no automatic detection, yet
|
||||||
|
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
//!@endcond
|
//!@endcond
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -48,6 +48,11 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
|||||||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
|
||||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||||
#define RAPIDJSON_NOTHING /* deliberately empty */
|
#define RAPIDJSON_NOTHING /* deliberately empty */
|
||||||
#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
|
#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
|
||||||
@ -156,6 +161,7 @@ concept Handler {
|
|||||||
bool Double(double d);
|
bool Double(double d);
|
||||||
bool String(const Ch* str, SizeType length, bool copy);
|
bool String(const Ch* str, SizeType length, bool copy);
|
||||||
bool StartObject();
|
bool StartObject();
|
||||||
|
bool Key(const Ch* str, SizeType length, bool copy);
|
||||||
bool EndObject(SizeType memberCount);
|
bool EndObject(SizeType memberCount);
|
||||||
bool StartArray();
|
bool StartArray();
|
||||||
bool EndArray(SizeType elementCount);
|
bool EndArray(SizeType elementCount);
|
||||||
@ -185,6 +191,7 @@ struct BaseReaderHandler {
|
|||||||
bool Double(double) { return static_cast<Override&>(*this).Default(); }
|
bool Double(double) { return static_cast<Override&>(*this).Default(); }
|
||||||
bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }
|
bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }
|
||||||
bool StartObject() { return static_cast<Override&>(*this).Default(); }
|
bool StartObject() { return static_cast<Override&>(*this).Default(); }
|
||||||
|
bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
|
||||||
bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }
|
bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }
|
||||||
bool StartArray() { return static_cast<Override&>(*this).Default(); }
|
bool StartArray() { return static_cast<Override&>(*this).Default(); }
|
||||||
bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }
|
bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }
|
||||||
@ -475,7 +482,7 @@ private:
|
|||||||
if (is.Peek() != '"')
|
if (is.Peek() != '"')
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
|
||||||
|
|
||||||
ParseString<parseFlags>(is, handler);
|
ParseString<parseFlags>(is, handler, true);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespace(is);
|
||||||
@ -627,27 +634,30 @@ private:
|
|||||||
|
|
||||||
// Parse string and generate String event. Different code paths for kParseInsituFlag.
|
// Parse string and generate String event. Different code paths for kParseInsituFlag.
|
||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
void ParseString(InputStream& is, Handler& handler) {
|
void ParseString(InputStream& is, Handler& handler, bool isKey = false) {
|
||||||
internal::StreamLocalCopy<InputStream> copy(is);
|
internal::StreamLocalCopy<InputStream> copy(is);
|
||||||
InputStream& s(copy.s);
|
InputStream& s(copy.s);
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
if (parseFlags & kParseInsituFlag) {
|
if (parseFlags & kParseInsituFlag) {
|
||||||
typename InputStream::Ch *head = s.PutBegin();
|
typename InputStream::Ch *head = s.PutBegin();
|
||||||
ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
|
ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
size_t length = s.PutEnd(head) - 1;
|
size_t length = s.PutEnd(head) - 1;
|
||||||
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
|
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
|
||||||
if (!handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false))
|
const typename TargetEncoding::Ch* const str = (typename TargetEncoding::Ch*)head;
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
StackStream<typename TargetEncoding::Ch> stackStream(stack_);
|
StackStream<typename TargetEncoding::Ch> stackStream(stack_);
|
||||||
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
|
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
size_t length = stackStream.Length();
|
SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
|
||||||
if (!handler.String(stackStream.Pop(), SizeType(length - 1), true))
|
const typename TargetEncoding::Ch* const str = stackStream.Pop();
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));
|
||||||
}
|
}
|
||||||
|
if (!success)
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse string to an output is
|
// Parse string to an output is
|
||||||
@ -712,29 +722,35 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename InputStream, bool backup>
|
template<typename InputStream, bool backup>
|
||||||
class NumberStream {
|
class NumberStream {};
|
||||||
|
|
||||||
|
template<typename InputStream>
|
||||||
|
class NumberStream<InputStream, false> {
|
||||||
public:
|
public:
|
||||||
NumberStream(GenericReader& reader, InputStream& is) : reader(reader), is(is) {}
|
NumberStream(GenericReader& reader, InputStream& is) : is(is) { (void)reader; }
|
||||||
|
~NumberStream() {}
|
||||||
|
|
||||||
Ch Peek() { return is.Peek(); }
|
Ch Peek() { return is.Peek(); }
|
||||||
Ch Take() { return is.Take(); }
|
Ch Take() { return is.Take(); }
|
||||||
size_t Tell() { return is.Tell(); }
|
size_t Tell() { return is.Tell(); }
|
||||||
const char* Pop() { return 0; }
|
const char* Pop() { return 0; }
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
NumberStream& operator=(const NumberStream&);
|
NumberStream& operator=(const NumberStream&);
|
||||||
|
|
||||||
GenericReader& reader;
|
|
||||||
InputStream& is;
|
InputStream& is;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename InputStream>
|
template<typename InputStream>
|
||||||
struct NumberStream<InputStream, true> {
|
class NumberStream<InputStream, true> : public NumberStream<InputStream, false> {
|
||||||
|
typedef NumberStream<InputStream, false> Base;
|
||||||
public:
|
public:
|
||||||
NumberStream(GenericReader& reader, InputStream& is) : reader(reader), is(is), stackStream(reader.stack_) {}
|
NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {}
|
||||||
|
~NumberStream() {}
|
||||||
|
|
||||||
Ch Take() {
|
Ch Take() {
|
||||||
stackStream.Put((char)is.Peek());
|
stackStream.Put((char)Base::is.Peek());
|
||||||
return is.Take();
|
return Base::is.Take();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Pop() {
|
const char* Pop() {
|
||||||
@ -743,15 +759,22 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GenericReader& reader;
|
|
||||||
InputStream& is;
|
|
||||||
StackStream<char> stackStream;
|
StackStream<char> stackStream;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
double StrtodFastPath(double significand, int exp) {
|
||||||
|
if (exp < -308)
|
||||||
|
return 0.0;
|
||||||
|
else if (exp >= 0)
|
||||||
|
return significand * internal::Pow10(exp);
|
||||||
|
else
|
||||||
|
return significand / internal::Pow10(-exp);
|
||||||
|
}
|
||||||
|
|
||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
void ParseNumber(InputStream& is, Handler& handler) {
|
void ParseNumber(InputStream& is, Handler& handler) {
|
||||||
internal::StreamLocalCopy<InputStream> copy(is);
|
internal::StreamLocalCopy<InputStream> copy(is);
|
||||||
NumberStream<InputStream, parseFlags & kParseFullPrecisionFlag> s(*this, copy.s);
|
NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s(*this, copy.s);
|
||||||
|
|
||||||
// Parse minus
|
// Parse minus
|
||||||
bool minus = false;
|
bool minus = false;
|
||||||
@ -800,11 +823,13 @@ private:
|
|||||||
// Parse 64bit int
|
// Parse 64bit int
|
||||||
bool useDouble = false;
|
bool useDouble = false;
|
||||||
bool useStrtod = false;
|
bool useStrtod = false;
|
||||||
|
double d = 0.0;
|
||||||
if (use64bit) {
|
if (use64bit) {
|
||||||
if (minus)
|
if (minus)
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||||
if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808
|
if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808
|
||||||
if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') {
|
if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') {
|
||||||
|
d = i64;
|
||||||
useDouble = true;
|
useDouble = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -814,6 +839,7 @@ private:
|
|||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||||
if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615
|
if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615
|
||||||
if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') {
|
if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') {
|
||||||
|
d = i64;
|
||||||
useDouble = true;
|
useDouble = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -823,10 +849,19 @@ private:
|
|||||||
|
|
||||||
// Force double for big integer
|
// Force double for big integer
|
||||||
if (useDouble) {
|
if (useDouble) {
|
||||||
|
if (parseFlags & kParseFullPrecisionFlag) {
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9')
|
while (s.Peek() >= '0' && s.Peek() <= '9')
|
||||||
s.Take();
|
s.Take();
|
||||||
useStrtod = true;
|
useStrtod = true;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||||
|
if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
||||||
|
d = d * 10 + (s.Take() - '0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parse frac = decimal-point 1*DIGIT
|
// Parse frac = decimal-point 1*DIGIT
|
||||||
int expFrac = 0;
|
int expFrac = 0;
|
||||||
@ -834,27 +869,28 @@ private:
|
|||||||
s.Take();
|
s.Take();
|
||||||
|
|
||||||
if (!useDouble) {
|
if (!useDouble) {
|
||||||
if (!use64bit) {
|
d = use64bit ? i64 : i;
|
||||||
i64 = i;
|
useDouble = true;
|
||||||
use64bit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||||
if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) {
|
if (d >= 9007199254740991.0) {
|
||||||
|
if (parseFlags & kParseFullPrecisionFlag)
|
||||||
useStrtod = true;
|
useStrtod = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
|
d = d * 10.0 + static_cast<unsigned>(s.Take() - '0');
|
||||||
--expFrac;
|
--expFrac;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useDouble = true;
|
|
||||||
|
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||||
|
//s.Take();
|
||||||
|
if (parseFlags & kParseFullPrecisionFlag)
|
||||||
s.Take();
|
s.Take();
|
||||||
|
else
|
||||||
|
d = d * 10 + (s.Take() - '0');
|
||||||
--expFrac;
|
--expFrac;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -865,7 +901,10 @@ private:
|
|||||||
// Parse exp = e [ minus / plus ] 1*DIGIT
|
// Parse exp = e [ minus / plus ] 1*DIGIT
|
||||||
int exp = 0;
|
int exp = 0;
|
||||||
if (s.Peek() == 'e' || s.Peek() == 'E') {
|
if (s.Peek() == 'e' || s.Peek() == 'E') {
|
||||||
|
if (!useDouble) {
|
||||||
|
d = use64bit ? i64 : i;
|
||||||
useDouble = true;
|
useDouble = true;
|
||||||
|
}
|
||||||
s.Take();
|
s.Take();
|
||||||
|
|
||||||
bool expMinus = false;
|
bool expMinus = false;
|
||||||
@ -893,33 +932,25 @@ private:
|
|||||||
|
|
||||||
// Finish parsing, call event according to the type of number.
|
// Finish parsing, call event according to the type of number.
|
||||||
bool cont = true;
|
bool cont = true;
|
||||||
|
const char* str = s.Pop(); // Pop stack no matter if it will be used or not.
|
||||||
// Pop stack no matter if it will be used or not.
|
|
||||||
const char* str = s.Pop();
|
|
||||||
|
|
||||||
if (useDouble) {
|
if (useDouble) {
|
||||||
int p = exp + expFrac;
|
int p = exp + expFrac;
|
||||||
double d;
|
if (parseFlags & kParseFullPrecisionFlag) {
|
||||||
double significand = use64bit ? i64 : i;
|
|
||||||
|
|
||||||
// Use fast path for string-to-double conversion if possible
|
// Use fast path for string-to-double conversion if possible
|
||||||
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||||
if (!useStrtod && p > 22) {
|
if (!useStrtod && p > 22) {
|
||||||
if (p < 22 + 16) {
|
if (p < 22 + 16) {
|
||||||
// Fast Path Cases In Disguise
|
// Fast Path Cases In Disguise
|
||||||
significand *= internal::Pow10(p - 22);
|
d *= internal::Pow10(p - 22);
|
||||||
p = 22;
|
p = 22;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
useStrtod = true;
|
useStrtod = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!useStrtod && p >= -22 && significand <= 9007199254740991.0) { // 2^53 - 1
|
if (!useStrtod && p >= -22 && d <= 9007199254740991.0) { // 2^53 - 1
|
||||||
if (p >= 0)
|
d = StrtodFastPath(d, p);
|
||||||
d = significand * internal::Pow10(p);
|
|
||||||
else
|
|
||||||
d = significand / internal::Pow10(-p);
|
|
||||||
|
|
||||||
if (minus)
|
if (minus)
|
||||||
d = -d;
|
d = -d;
|
||||||
}
|
}
|
||||||
@ -931,6 +962,19 @@ private:
|
|||||||
if (d == HUGE_VAL || d == -HUGE_VAL)
|
if (d == HUGE_VAL || d == -HUGE_VAL)
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (p < -308) {
|
||||||
|
// Prevent expSum < -308, making Pow10(p) = 0
|
||||||
|
d = StrtodFastPath(d, exp);
|
||||||
|
d = StrtodFastPath(d, expFrac);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
d = StrtodFastPath(d, p);
|
||||||
|
|
||||||
|
if (minus)
|
||||||
|
d = -d;
|
||||||
|
}
|
||||||
cont = handler.Double(d);
|
cont = handler.Double(d);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1247,7 +1291,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
case IterativeParsingMemberKeyState:
|
case IterativeParsingMemberKeyState:
|
||||||
ParseString<parseFlags>(is, handler);
|
ParseString<parseFlags>(is, handler, true);
|
||||||
if (HasParseError())
|
if (HasParseError())
|
||||||
return IterativeParsingErrorState;
|
return IterativeParsingErrorState;
|
||||||
else
|
else
|
||||||
@ -1410,6 +1454,10 @@ typedef GenericReader<UTF8<>, UTF8<> > Reader;
|
|||||||
|
|
||||||
} // namespace rapidjson
|
} // namespace rapidjson
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
@ -131,6 +131,8 @@ public:
|
|||||||
return WriteStartObject();
|
return WriteStartObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
|
||||||
|
|
||||||
bool EndObject(SizeType memberCount = 0) {
|
bool EndObject(SizeType memberCount = 0) {
|
||||||
(void)memberCount;
|
(void)memberCount;
|
||||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||||
@ -165,6 +167,7 @@ public:
|
|||||||
|
|
||||||
//! Simpler but slower overload.
|
//! Simpler but slower overload.
|
||||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||||
|
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
@ -103,8 +103,8 @@ struct ParseDoubleHandler : BaseReaderHandler<UTF8<>, ParseDoubleHandler> {
|
|||||||
double actual_;
|
double actual_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(Reader, ParseNumberHandler) {
|
TEST(Reader, ParseNumber_Integer) {
|
||||||
#define TEST_NUMBER(Handler, str, x) \
|
#define TEST_INTEGER(Handler, str, x) \
|
||||||
{ \
|
{ \
|
||||||
StringStream s(str); \
|
StringStream s(str); \
|
||||||
Handler h; \
|
Handler h; \
|
||||||
@ -114,67 +114,19 @@ TEST(Reader, ParseNumberHandler) {
|
|||||||
EXPECT_EQ(double(x), h.actual_); \
|
EXPECT_EQ(double(x), h.actual_); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TEST_DOUBLE(str, x) \
|
TEST_INTEGER(ParseUintHandler, "0", 0);
|
||||||
{ \
|
TEST_INTEGER(ParseUintHandler, "123", 123);
|
||||||
StringStream s(str); \
|
TEST_INTEGER(ParseUintHandler, "2147483648", 2147483648u); // 2^31 - 1 (cannot be stored in int)
|
||||||
ParseDoubleHandler h; \
|
TEST_INTEGER(ParseUintHandler, "4294967295", 4294967295u);
|
||||||
Reader reader; \
|
|
||||||
reader.Parse(s, h); \
|
|
||||||
EXPECT_EQ(1u, h.step_); \
|
|
||||||
EXPECT_EQ(x, h.actual_); \
|
|
||||||
if (x != h.actual_) \
|
|
||||||
printf(" Actual: %.17g\nExpected: %.17g\n", h.actual_, x);\
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_NUMBER(ParseUintHandler, "0", 0);
|
TEST_INTEGER(ParseIntHandler, "-123", -123);
|
||||||
TEST_NUMBER(ParseUintHandler, "123", 123);
|
TEST_INTEGER(ParseIntHandler, "-2147483648", -2147483648LL); // -2^31 (min of int)
|
||||||
TEST_NUMBER(ParseUintHandler, "2147483648", 2147483648u); // 2^31 - 1 (cannot be stored in int)
|
|
||||||
TEST_NUMBER(ParseUintHandler, "4294967295", 4294967295u);
|
|
||||||
|
|
||||||
TEST_NUMBER(ParseIntHandler, "-123", -123);
|
TEST_INTEGER(ParseUint64Handler, "4294967296", 4294967296ULL); // 2^32 (max of unsigned + 1, force to use uint64_t)
|
||||||
TEST_NUMBER(ParseIntHandler, "-2147483648", -2147483648LL); // -2^31 (min of int)
|
TEST_INTEGER(ParseUint64Handler, "18446744073709551615", 18446744073709551615ULL); // 2^64 - 1 (max of uint64_t)
|
||||||
|
|
||||||
TEST_NUMBER(ParseUint64Handler, "4294967296", 4294967296ULL); // 2^32 (max of unsigned + 1, force to use uint64_t)
|
TEST_INTEGER(ParseInt64Handler, "-2147483649", -2147483649LL); // -2^31 -1 (min of int - 1, force to use int64_t)
|
||||||
TEST_NUMBER(ParseUint64Handler, "18446744073709551615", 18446744073709551615ULL); // 2^64 - 1 (max of uint64_t)
|
TEST_INTEGER(ParseInt64Handler, "-9223372036854775808", (-9223372036854775807LL - 1)); // -2^63 (min of int64_t)
|
||||||
|
|
||||||
TEST_NUMBER(ParseInt64Handler, "-2147483649", -2147483649LL); // -2^31 -1 (min of int - 1, force to use int64_t)
|
|
||||||
TEST_NUMBER(ParseInt64Handler, "-9223372036854775808", (-9223372036854775807LL - 1)); // -2^63 (min of int64_t)
|
|
||||||
|
|
||||||
TEST_DOUBLE("0.0", 0.0);
|
|
||||||
TEST_DOUBLE("1.0", 1.0);
|
|
||||||
TEST_DOUBLE("-1.0", -1.0);
|
|
||||||
TEST_DOUBLE("1.5", 1.5);
|
|
||||||
TEST_DOUBLE("-1.5", -1.5);
|
|
||||||
TEST_DOUBLE("3.1416", 3.1416);
|
|
||||||
TEST_DOUBLE("1E10", 1E10);
|
|
||||||
TEST_DOUBLE("1e10", 1e10);
|
|
||||||
TEST_DOUBLE("1E+10", 1E+10);
|
|
||||||
TEST_DOUBLE("1E-10", 1E-10);
|
|
||||||
TEST_DOUBLE("-1E10", -1E10);
|
|
||||||
TEST_DOUBLE("-1e10", -1e10);
|
|
||||||
TEST_DOUBLE("-1E+10", -1E+10);
|
|
||||||
TEST_DOUBLE("-1E-10", -1E-10);
|
|
||||||
TEST_DOUBLE("1.234E+10", 1.234E+10);
|
|
||||||
TEST_DOUBLE("1.234E-10", 1.234E-10);
|
|
||||||
TEST_DOUBLE("1.79769e+308", 1.79769e+308);
|
|
||||||
TEST_DOUBLE("2.22507e-308", 2.22507e-308);
|
|
||||||
TEST_DOUBLE("-1.79769e+308", -1.79769e+308);
|
|
||||||
TEST_DOUBLE("-2.22507e-308", -2.22507e-308);
|
|
||||||
TEST_DOUBLE("4.9406564584124654e-324", 4.9406564584124654e-324); // minimum denormal
|
|
||||||
TEST_DOUBLE("1e-10000", 0.0); // must underflow
|
|
||||||
TEST_DOUBLE("18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double)
|
|
||||||
TEST_DOUBLE("-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double)
|
|
||||||
TEST_DOUBLE("0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120
|
|
||||||
TEST_DOUBLE("123e34", 123e34); // Fast Path Cases In Disguise
|
|
||||||
|
|
||||||
{
|
|
||||||
char n1e308[310]; // '1' followed by 308 '0'
|
|
||||||
n1e308[0] = '1';
|
|
||||||
for (int i = 1; i < 309; i++)
|
|
||||||
n1e308[i] = '0';
|
|
||||||
n1e308[309] = '\0';
|
|
||||||
TEST_DOUBLE(n1e308, 1E308);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Random test for uint32_t/int32_t
|
// Random test for uint32_t/int32_t
|
||||||
{
|
{
|
||||||
@ -189,11 +141,11 @@ TEST(Reader, ParseNumberHandler) {
|
|||||||
|
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
*internal::u32toa(u.u, buffer) = '\0';
|
*internal::u32toa(u.u, buffer) = '\0';
|
||||||
TEST_NUMBER(ParseUintHandler, buffer, u.u);
|
TEST_INTEGER(ParseUintHandler, buffer, u.u);
|
||||||
|
|
||||||
if (u.i < 0) {
|
if (u.i < 0) {
|
||||||
*internal::i32toa(u.i, buffer) = '\0';
|
*internal::i32toa(u.i, buffer) = '\0';
|
||||||
TEST_NUMBER(ParseIntHandler, buffer, u.i);
|
TEST_INTEGER(ParseIntHandler, buffer, u.i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,18 +165,74 @@ TEST(Reader, ParseNumberHandler) {
|
|||||||
char buffer[32];
|
char buffer[32];
|
||||||
if (u.u >= 4294967296ULL) {
|
if (u.u >= 4294967296ULL) {
|
||||||
*internal::u64toa(u.u, buffer) = '\0';
|
*internal::u64toa(u.u, buffer) = '\0';
|
||||||
TEST_NUMBER(ParseUint64Handler, buffer, u.u);
|
TEST_INTEGER(ParseUint64Handler, buffer, u.u);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u.i <= -2147483649LL) {
|
if (u.i <= -2147483649LL) {
|
||||||
*internal::i64toa(u.i, buffer) = '\0';
|
*internal::i64toa(u.i, buffer) = '\0';
|
||||||
TEST_NUMBER(ParseInt64Handler, buffer, u.i);
|
TEST_INTEGER(ParseInt64Handler, buffer, u.i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#undef TEST_INTEGER
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool fullPrecision>
|
||||||
|
static void TestParseDouble() {
|
||||||
|
#define TEST_DOUBLE(fullPrecision, str, x) \
|
||||||
|
{ \
|
||||||
|
StringStream s(str); \
|
||||||
|
ParseDoubleHandler h; \
|
||||||
|
Reader reader; \
|
||||||
|
reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h); \
|
||||||
|
EXPECT_EQ(1u, h.step_); \
|
||||||
|
if (fullPrecision) { \
|
||||||
|
EXPECT_EQ(x, h.actual_); \
|
||||||
|
if (x != h.actual_) \
|
||||||
|
printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", str, h.actual_, x); \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
EXPECT_DOUBLE_EQ(x, h.actual_); \
|
||||||
|
}
|
||||||
|
|
||||||
// Random test for double
|
TEST_DOUBLE(fullPrecision, "0.0", 0.0);
|
||||||
{
|
TEST_DOUBLE(fullPrecision, "1.0", 1.0);
|
||||||
|
TEST_DOUBLE(fullPrecision, "-1.0", -1.0);
|
||||||
|
TEST_DOUBLE(fullPrecision, "1.5", 1.5);
|
||||||
|
TEST_DOUBLE(fullPrecision, "-1.5", -1.5);
|
||||||
|
TEST_DOUBLE(fullPrecision, "3.1416", 3.1416);
|
||||||
|
TEST_DOUBLE(fullPrecision, "1E10", 1E10);
|
||||||
|
TEST_DOUBLE(fullPrecision, "1e10", 1e10);
|
||||||
|
TEST_DOUBLE(fullPrecision, "1E+10", 1E+10);
|
||||||
|
TEST_DOUBLE(fullPrecision, "1E-10", 1E-10);
|
||||||
|
TEST_DOUBLE(fullPrecision, "-1E10", -1E10);
|
||||||
|
TEST_DOUBLE(fullPrecision, "-1e10", -1e10);
|
||||||
|
TEST_DOUBLE(fullPrecision, "-1E+10", -1E+10);
|
||||||
|
TEST_DOUBLE(fullPrecision, "-1E-10", -1E-10);
|
||||||
|
TEST_DOUBLE(fullPrecision, "1.234E+10", 1.234E+10);
|
||||||
|
TEST_DOUBLE(fullPrecision, "1.234E-10", 1.234E-10);
|
||||||
|
TEST_DOUBLE(fullPrecision, "1.79769e+308", 1.79769e+308);
|
||||||
|
TEST_DOUBLE(fullPrecision, "2.22507e-308", 2.22507e-308);
|
||||||
|
TEST_DOUBLE(fullPrecision, "-1.79769e+308", -1.79769e+308);
|
||||||
|
TEST_DOUBLE(fullPrecision, "-2.22507e-308", -2.22507e-308);
|
||||||
|
TEST_DOUBLE(fullPrecision, "4.9406564584124654e-324", 4.9406564584124654e-324); // minimum denormal
|
||||||
|
TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow
|
||||||
|
TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double)
|
||||||
|
TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double)
|
||||||
|
TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120
|
||||||
|
TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise
|
||||||
|
|
||||||
|
{
|
||||||
|
char n1e308[310]; // '1' followed by 308 '0'
|
||||||
|
n1e308[0] = '1';
|
||||||
|
for (int i = 1; i < 309; i++)
|
||||||
|
n1e308[i] = '0';
|
||||||
|
n1e308[309] = '\0';
|
||||||
|
TEST_DOUBLE(fullPrecision, n1e308, 1E308);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Random test for double
|
||||||
|
{
|
||||||
union {
|
union {
|
||||||
double d;
|
double d;
|
||||||
uint64_t u;
|
uint64_t u;
|
||||||
@ -236,18 +244,30 @@ TEST(Reader, ParseNumberHandler) {
|
|||||||
// Need to call r() in two statements for cross-platform coherent sequence.
|
// Need to call r() in two statements for cross-platform coherent sequence.
|
||||||
u.u = uint64_t(r()) << 32;
|
u.u = uint64_t(r()) << 32;
|
||||||
u.u |= uint64_t(r());
|
u.u |= uint64_t(r());
|
||||||
} while (isnan(u.d) || isinf(u.d));
|
} while (std::isnan(u.d) || std::isinf(u.d)
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// VC's strtod() has problem with denormal numbers
|
||||||
|
|| !std::isnormal(u.d)
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
*internal::dtoa(u.d, buffer) = '\0';
|
*internal::dtoa(u.d, buffer) = '\0';
|
||||||
TEST_DOUBLE(buffer, u.d);
|
TEST_DOUBLE(fullPrecision, buffer, u.d);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#undef TEST_NUMBER
|
|
||||||
#undef TEST_DOUBLE
|
#undef TEST_DOUBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Reader, ParseNumber_NormalPrecisionDouble) {
|
||||||
|
TestParseDouble<false>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Reader, ParseNumber_FullPrecisionDouble) {
|
||||||
|
TestParseDouble<true>();
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Reader, ParseNumber_Error) {
|
TEST(Reader, ParseNumber_Error) {
|
||||||
#define TEST_NUMBER_ERROR(errorCode, str) \
|
#define TEST_NUMBER_ERROR(errorCode, str) \
|
||||||
{ \
|
{ \
|
||||||
@ -894,9 +914,10 @@ struct IterativeParsingReaderHandler {
|
|||||||
const static int LOG_DOUBLE = -7;
|
const static int LOG_DOUBLE = -7;
|
||||||
const static int LOG_STRING = -8;
|
const static int LOG_STRING = -8;
|
||||||
const static int LOG_STARTOBJECT = -9;
|
const static int LOG_STARTOBJECT = -9;
|
||||||
const static int LOG_ENDOBJECT = -10;
|
const static int LOG_KEY = -10;
|
||||||
const static int LOG_STARTARRAY = -11;
|
const static int LOG_ENDOBJECT = -11;
|
||||||
const static int LOG_ENDARRAY = -12;
|
const static int LOG_STARTARRAY = -12;
|
||||||
|
const static int LOG_ENDARRAY = -13;
|
||||||
|
|
||||||
const static size_t LogCapacity = 256;
|
const static size_t LogCapacity = 256;
|
||||||
int Logs[LogCapacity];
|
int Logs[LogCapacity];
|
||||||
@ -923,6 +944,8 @@ struct IterativeParsingReaderHandler {
|
|||||||
|
|
||||||
bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; }
|
bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; }
|
||||||
|
|
||||||
|
bool Key (const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_KEY; return true; }
|
||||||
|
|
||||||
bool EndObject(SizeType c) {
|
bool EndObject(SizeType c) {
|
||||||
RAPIDJSON_ASSERT(LogCount < LogCapacity);
|
RAPIDJSON_ASSERT(LogCount < LogCapacity);
|
||||||
Logs[LogCount++] = LOG_ENDOBJECT;
|
Logs[LogCount++] = LOG_ENDOBJECT;
|
||||||
@ -955,7 +978,7 @@ TEST(Reader, IterativeParsing_General) {
|
|||||||
handler.LOG_STARTARRAY,
|
handler.LOG_STARTARRAY,
|
||||||
handler.LOG_INT,
|
handler.LOG_INT,
|
||||||
handler.LOG_STARTOBJECT,
|
handler.LOG_STARTOBJECT,
|
||||||
handler.LOG_STRING,
|
handler.LOG_KEY,
|
||||||
handler.LOG_STARTARRAY,
|
handler.LOG_STARTARRAY,
|
||||||
handler.LOG_INT,
|
handler.LOG_INT,
|
||||||
handler.LOG_INT,
|
handler.LOG_INT,
|
||||||
@ -993,7 +1016,7 @@ TEST(Reader, IterativeParsing_Count) {
|
|||||||
handler.LOG_STARTOBJECT,
|
handler.LOG_STARTOBJECT,
|
||||||
handler.LOG_ENDOBJECT, 0,
|
handler.LOG_ENDOBJECT, 0,
|
||||||
handler.LOG_STARTOBJECT,
|
handler.LOG_STARTOBJECT,
|
||||||
handler.LOG_STRING,
|
handler.LOG_KEY,
|
||||||
handler.LOG_INT,
|
handler.LOG_INT,
|
||||||
handler.LOG_ENDOBJECT, 1,
|
handler.LOG_ENDOBJECT, 1,
|
||||||
handler.LOG_STARTARRAY,
|
handler.LOG_STARTARRAY,
|
||||||
|
@ -89,15 +89,9 @@ inline FILE* TempFile(char *filename) {
|
|||||||
#pragma warning(disable : 4127)
|
#pragma warning(disable : 4127)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class AssertException : public std::exception {
|
class AssertException : public std::logic_error {
|
||||||
public:
|
public:
|
||||||
AssertException(const char* w) : what_(w) {}
|
AssertException(const char* w) : std::logic_error(w) {}
|
||||||
AssertException(const AssertException& other) : what_(other.what_) {}
|
|
||||||
AssertException& operator=(const AssertException& rhs) { what_ = rhs.what_; return *this; }
|
|
||||||
virtual const char* what() const throw() { return what_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const char* what_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
|
#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
TEST(Value, default_constructor) {
|
TEST(Value, DefaultConstructor) {
|
||||||
Value x;
|
Value x;
|
||||||
EXPECT_EQ(kNullType, x.GetType());
|
EXPECT_EQ(kNullType, x.GetType());
|
||||||
EXPECT_TRUE(x.IsNull());
|
EXPECT_TRUE(x.IsNull());
|
||||||
@ -38,7 +38,32 @@ TEST(Value, default_constructor) {
|
|||||||
// Value y = x;
|
// Value y = x;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
TEST(Value, assignment_operator) {
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
TEST(Value, MoveConstructor) {
|
||||||
|
typedef GenericValue<UTF8<>, CrtAllocator> Value;
|
||||||
|
Value::AllocatorType allocator;
|
||||||
|
|
||||||
|
Value x((Value(kArrayType)));
|
||||||
|
x.Reserve(4u, allocator);
|
||||||
|
x.PushBack(1, allocator).PushBack(2, allocator).PushBack(3, allocator).PushBack(4, allocator);
|
||||||
|
EXPECT_TRUE(x.IsArray());
|
||||||
|
EXPECT_EQ(4u, x.Size());
|
||||||
|
|
||||||
|
// Value y(x); // should not compile
|
||||||
|
Value y(std::move(x));
|
||||||
|
EXPECT_TRUE(x.IsNull());
|
||||||
|
EXPECT_TRUE(y.IsArray());
|
||||||
|
EXPECT_EQ(4u, y.Size());
|
||||||
|
|
||||||
|
// Value z = y; // should not compile
|
||||||
|
Value z = std::move(y);
|
||||||
|
EXPECT_TRUE(y.IsNull());
|
||||||
|
EXPECT_TRUE(z.IsArray());
|
||||||
|
EXPECT_EQ(4u, z.Size());
|
||||||
|
}
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
|
||||||
|
TEST(Value, AssignmentOperator) {
|
||||||
Value x(1234);
|
Value x(1234);
|
||||||
Value y;
|
Value y;
|
||||||
y = x;
|
y = x;
|
||||||
@ -63,6 +88,22 @@ TEST(Value, assignment_operator) {
|
|||||||
y = StringRef(mstr);
|
y = StringRef(mstr);
|
||||||
EXPECT_TRUE(y.IsString());
|
EXPECT_TRUE(y.IsString());
|
||||||
EXPECT_EQ(y.GetString(),mstr);
|
EXPECT_EQ(y.GetString(),mstr);
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
// C++11 move assignment
|
||||||
|
x = Value("World");
|
||||||
|
EXPECT_TRUE(x.IsString());
|
||||||
|
EXPECT_STREQ("World", x.GetString());
|
||||||
|
|
||||||
|
x = std::move(y);
|
||||||
|
EXPECT_TRUE(y.IsNull());
|
||||||
|
EXPECT_TRUE(x.IsString());
|
||||||
|
EXPECT_EQ(x.GetString(), mstr);
|
||||||
|
|
||||||
|
y = std::move(Value().SetInt(1234));
|
||||||
|
EXPECT_TRUE(y.IsInt());
|
||||||
|
EXPECT_EQ(1234, y);
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename A, typename B>
|
template <typename A, typename B>
|
||||||
@ -81,7 +122,7 @@ void TestUnequal(const A& a, const B& b) {
|
|||||||
EXPECT_TRUE (b != a);
|
EXPECT_TRUE (b != a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Value, equalto_operator) {
|
TEST(Value, EqualtoOperator) {
|
||||||
Value::AllocatorType allocator;
|
Value::AllocatorType allocator;
|
||||||
Value x(kObjectType);
|
Value x(kObjectType);
|
||||||
x.AddMember("hello", "world", allocator)
|
x.AddMember("hello", "world", allocator)
|
||||||
@ -105,16 +146,33 @@ TEST(Value, equalto_operator) {
|
|||||||
TestEqual(x["i"], 123);
|
TestEqual(x["i"], 123);
|
||||||
TestEqual(x["pi"], 3.14);
|
TestEqual(x["pi"], 3.14);
|
||||||
|
|
||||||
// Test operator==()
|
// Test operator==() (including different allocators)
|
||||||
Value y;
|
CrtAllocator crtAllocator;
|
||||||
y.CopyFrom(x, allocator);
|
GenericValue<UTF8<>, CrtAllocator> y;
|
||||||
|
GenericDocument<UTF8<>, CrtAllocator> z(&crtAllocator);
|
||||||
|
y.CopyFrom(x, crtAllocator);
|
||||||
|
z.CopyFrom(y, z.GetAllocator());
|
||||||
TestEqual(x, y);
|
TestEqual(x, y);
|
||||||
|
TestEqual(y, z);
|
||||||
|
TestEqual(z, x);
|
||||||
|
|
||||||
// Swapping member order should be fine.
|
// Swapping member order should be fine.
|
||||||
y.RemoveMember("t");
|
EXPECT_TRUE(y.RemoveMember("t"));
|
||||||
TestUnequal(x, y);
|
TestUnequal(x, y);
|
||||||
y.AddMember("t", Value(true).Move(), allocator);
|
TestUnequal(z, y);
|
||||||
|
EXPECT_TRUE(z.RemoveMember("t"));
|
||||||
|
TestUnequal(x, z);
|
||||||
|
TestEqual(y, z);
|
||||||
|
y.AddMember("t", true, crtAllocator);
|
||||||
|
z.AddMember("t", true, z.GetAllocator());
|
||||||
TestEqual(x, y);
|
TestEqual(x, y);
|
||||||
|
TestEqual(y, z);
|
||||||
|
TestEqual(z, x);
|
||||||
|
|
||||||
|
// Issue #129: compare Uint64
|
||||||
|
x.SetUint64(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF0));
|
||||||
|
y.SetUint64(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF));
|
||||||
|
TestUnequal(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value>
|
template <typename Value>
|
||||||
@ -538,7 +596,7 @@ TEST(Value, String) {
|
|||||||
EXPECT_STREQ("World", w.GetString());
|
EXPECT_STREQ("World", w.GetString());
|
||||||
EXPECT_EQ(5u, w.GetStringLength());
|
EXPECT_EQ(5u, w.GetStringLength());
|
||||||
|
|
||||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
{
|
{
|
||||||
std::string str = "Hello World";
|
std::string str = "Hello World";
|
||||||
str[5] = '\0';
|
str[5] = '\0';
|
||||||
@ -626,6 +684,21 @@ TEST(Value, Array) {
|
|||||||
EXPECT_TRUE(y[4u].IsString());
|
EXPECT_TRUE(y[4u].IsString());
|
||||||
EXPECT_STREQ("foo", y[4u].GetString());
|
EXPECT_STREQ("foo", y[4u].GetString());
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
// PushBack(GenericValue&&, Allocator&);
|
||||||
|
{
|
||||||
|
Value y(kArrayType);
|
||||||
|
y.PushBack(Value(true), allocator);
|
||||||
|
y.PushBack(std::move(Value(kArrayType).PushBack(Value(1), allocator).PushBack("foo", allocator)), allocator);
|
||||||
|
EXPECT_EQ(2u, y.Size());
|
||||||
|
EXPECT_TRUE(y[0u].IsTrue());
|
||||||
|
EXPECT_TRUE(y[1u].IsArray());
|
||||||
|
EXPECT_EQ(2u, y[1u].Size());
|
||||||
|
EXPECT_TRUE(y[1u][0u].IsInt());
|
||||||
|
EXPECT_TRUE(y[1u][1u].IsString());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// iterator
|
// iterator
|
||||||
Value::ValueIterator itr = x.Begin();
|
Value::ValueIterator itr = x.Begin();
|
||||||
EXPECT_TRUE(itr != x.End());
|
EXPECT_TRUE(itr != x.End());
|
||||||
@ -734,7 +807,6 @@ TEST(Value, Array) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
#if 0
|
|
||||||
// http://en.wikipedia.org/wiki/Erase-remove_idiom
|
// http://en.wikipedia.org/wiki/Erase-remove_idiom
|
||||||
x.Clear();
|
x.Clear();
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
@ -743,11 +815,11 @@ TEST(Value, Array) {
|
|||||||
else
|
else
|
||||||
x.PushBack(Value(kNullType).Move(), allocator);
|
x.PushBack(Value(kNullType).Move(), allocator);
|
||||||
|
|
||||||
x.Erase(std::remove(x.Begin(), x.End(), Value(kNullType)), x.End());
|
const Value null(kNullType);
|
||||||
|
x.Erase(std::remove(x.Begin(), x.End(), null), x.End());
|
||||||
EXPECT_EQ(5u, x.Size());
|
EXPECT_EQ(5u, x.Size());
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
EXPECT_EQ(i * 2, x[i]);
|
EXPECT_EQ(i * 2, x[i]);
|
||||||
#endif
|
|
||||||
|
|
||||||
// SetArray()
|
// SetArray()
|
||||||
Value z;
|
Value z;
|
||||||
@ -801,6 +873,22 @@ TEST(Value, Object) {
|
|||||||
EXPECT_EQ(8u, o.MemberCount());
|
EXPECT_EQ(8u, o.MemberCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
// AddMember(GenericValue&&, ...) variants
|
||||||
|
{
|
||||||
|
Value o(kObjectType);
|
||||||
|
o.AddMember(Value("true"), Value(true), allocator);
|
||||||
|
o.AddMember(Value("false"), Value(false).Move(), allocator); // value is lvalue ref
|
||||||
|
o.AddMember(Value("int").Move(), Value(-1), allocator); // name is lvalue ref
|
||||||
|
o.AddMember("uint", std::move(Value().SetUint(1u)), allocator); // name is literal, value is rvalue
|
||||||
|
EXPECT_TRUE(o["true"].GetBool());
|
||||||
|
EXPECT_FALSE(o["false"].GetBool());
|
||||||
|
EXPECT_EQ(-1, o["int"].GetInt());
|
||||||
|
EXPECT_EQ(1u, o["uint"].GetUint());
|
||||||
|
EXPECT_EQ(4u, o.MemberCount());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Tests a member with null character
|
// Tests a member with null character
|
||||||
Value name;
|
Value name;
|
||||||
const Value C0D("C\0D", 3);
|
const Value C0D("C\0D", 3);
|
||||||
@ -818,10 +906,18 @@ TEST(Value, Object) {
|
|||||||
EXPECT_TRUE(x.HasMember(name));
|
EXPECT_TRUE(x.HasMember(name));
|
||||||
EXPECT_TRUE(y.HasMember(name));
|
EXPECT_TRUE(y.HasMember(name));
|
||||||
|
|
||||||
|
GenericValue<UTF8<>, CrtAllocator> othername("A");
|
||||||
|
EXPECT_TRUE(x.HasMember(othername));
|
||||||
|
EXPECT_TRUE(y.HasMember(othername));
|
||||||
|
othername.SetString("C\0D");
|
||||||
|
EXPECT_TRUE(x.HasMember(othername));
|
||||||
|
EXPECT_TRUE(y.HasMember(othername));
|
||||||
|
|
||||||
// operator[]
|
// operator[]
|
||||||
EXPECT_STREQ("Apple", x["A"].GetString());
|
EXPECT_STREQ("Apple", x["A"].GetString());
|
||||||
EXPECT_STREQ("Banana", x["B"].GetString());
|
EXPECT_STREQ("Banana", x["B"].GetString());
|
||||||
EXPECT_STREQ("CherryD", x[C0D].GetString());
|
EXPECT_STREQ("CherryD", x[C0D].GetString());
|
||||||
|
EXPECT_STREQ("CherryD", x[othername].GetString());
|
||||||
|
|
||||||
// const operator[]
|
// const operator[]
|
||||||
EXPECT_STREQ("Apple", y["A"].GetString());
|
EXPECT_STREQ("Apple", y["A"].GetString());
|
||||||
@ -892,7 +988,7 @@ TEST(Value, Object) {
|
|||||||
x.RemoveMember("B");
|
x.RemoveMember("B");
|
||||||
EXPECT_FALSE(x.HasMember("B"));
|
EXPECT_FALSE(x.HasMember("B"));
|
||||||
|
|
||||||
x.RemoveMember(name);
|
x.RemoveMember(othername);
|
||||||
EXPECT_FALSE(x.HasMember(name));
|
EXPECT_FALSE(x.HasMember(name));
|
||||||
|
|
||||||
EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
|
EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
|
||||||
@ -905,11 +1001,14 @@ TEST(Value, Object) {
|
|||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator);
|
x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator);
|
||||||
|
|
||||||
|
// MemberCount, iterator difference
|
||||||
|
EXPECT_EQ(x.MemberCount(), SizeType(x.MemberEnd() - x.MemberBegin()));
|
||||||
|
|
||||||
// Erase the first
|
// Erase the first
|
||||||
itr = x.EraseMember(x.MemberBegin());
|
itr = x.EraseMember(x.MemberBegin());
|
||||||
EXPECT_FALSE(x.HasMember(keys[0]));
|
EXPECT_FALSE(x.HasMember(keys[0]));
|
||||||
EXPECT_EQ(x.MemberBegin(), itr);
|
EXPECT_EQ(x.MemberBegin(), itr);
|
||||||
EXPECT_EQ(9, x.MemberEnd() - x.MemberBegin());
|
EXPECT_EQ(9u, x.MemberCount());
|
||||||
for (; itr != x.MemberEnd(); ++itr) {
|
for (; itr != x.MemberEnd(); ++itr) {
|
||||||
int i = (itr - x.MemberBegin()) + 1;
|
int i = (itr - x.MemberBegin()) + 1;
|
||||||
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
||||||
@ -920,7 +1019,7 @@ TEST(Value, Object) {
|
|||||||
itr = x.EraseMember(x.MemberEnd() - 1);
|
itr = x.EraseMember(x.MemberEnd() - 1);
|
||||||
EXPECT_FALSE(x.HasMember(keys[9]));
|
EXPECT_FALSE(x.HasMember(keys[9]));
|
||||||
EXPECT_EQ(x.MemberEnd(), itr);
|
EXPECT_EQ(x.MemberEnd(), itr);
|
||||||
EXPECT_EQ(8, x.MemberEnd() - x.MemberBegin());
|
EXPECT_EQ(8u, x.MemberCount());
|
||||||
for (; itr != x.MemberEnd(); ++itr) {
|
for (; itr != x.MemberEnd(); ++itr) {
|
||||||
int i = (itr - x.MemberBegin()) + 1;
|
int i = (itr - x.MemberBegin()) + 1;
|
||||||
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
||||||
@ -931,7 +1030,7 @@ TEST(Value, Object) {
|
|||||||
itr = x.EraseMember(x.MemberBegin() + 4);
|
itr = x.EraseMember(x.MemberBegin() + 4);
|
||||||
EXPECT_FALSE(x.HasMember(keys[5]));
|
EXPECT_FALSE(x.HasMember(keys[5]));
|
||||||
EXPECT_EQ(x.MemberBegin() + 4, itr);
|
EXPECT_EQ(x.MemberBegin() + 4, itr);
|
||||||
EXPECT_EQ(7, x.MemberEnd() - x.MemberBegin());
|
EXPECT_EQ(7u, x.MemberCount());
|
||||||
for (; itr != x.MemberEnd(); ++itr) {
|
for (; itr != x.MemberEnd(); ++itr) {
|
||||||
int i = (itr - x.MemberBegin());
|
int i = (itr - x.MemberBegin());
|
||||||
i += (i<4) ? 1 : 2;
|
i += (i<4) ? 1 : 2;
|
||||||
@ -955,7 +1054,7 @@ TEST(Value, Object) {
|
|||||||
EXPECT_EQ(x.MemberBegin() + first, itr);
|
EXPECT_EQ(x.MemberBegin() + first, itr);
|
||||||
|
|
||||||
size_t removeCount = last - first;
|
size_t removeCount = last - first;
|
||||||
EXPECT_EQ(n - removeCount, size_t(x.MemberEnd() - x.MemberBegin()));
|
EXPECT_EQ(n - removeCount, x.MemberCount());
|
||||||
for (unsigned i = 0; i < first; i++)
|
for (unsigned i = 0; i < first; i++)
|
||||||
EXPECT_EQ(i, x[keys[i]][0u].GetUint());
|
EXPECT_EQ(i, x[keys[i]][0u].GetUint());
|
||||||
for (unsigned i = first; i < n - removeCount; i++)
|
for (unsigned i = first; i < n - removeCount; i++)
|
||||||
@ -1059,3 +1158,23 @@ TEST(Document, CrtAllocator) {
|
|||||||
V a(kArrayType);
|
V a(kArrayType);
|
||||||
a.PushBack(1, allocator); // Should not call destructor on uninitialized Value of newly allocated elements.
|
a.PushBack(1, allocator); // Should not call destructor on uninitialized Value of newly allocated elements.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void TestShortStringOptimization(const char* str) {
|
||||||
|
const rapidjson::SizeType len = (rapidjson::SizeType)strlen(str);
|
||||||
|
|
||||||
|
rapidjson::Document doc;
|
||||||
|
rapidjson::Value val;
|
||||||
|
val.SetString(str, len, doc.GetAllocator());
|
||||||
|
|
||||||
|
EXPECT_EQ(val.GetStringLength(), len);
|
||||||
|
EXPECT_STREQ(val.GetString(), str);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Value, AllocateShortString) {
|
||||||
|
TestShortStringOptimization(""); // edge case: empty string
|
||||||
|
TestShortStringOptimization("12345678"); // regular case for short strings: 8 chars
|
||||||
|
TestShortStringOptimization("12345678901"); // edge case: 11 chars in 32-bit mode (=> short string)
|
||||||
|
TestShortStringOptimization("123456789012"); // edge case: 12 chars in 32-bit mode (=> regular string)
|
||||||
|
TestShortStringOptimization("123456789012345"); // edge case: 15 chars in 64-bit mode (=> short string)
|
||||||
|
TestShortStringOptimization("1234567890123456"); // edge case: 16 chars in 64-bit mode (=> regular string)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user