Merge master and implement kParseFullPrecision
This commit is contained in:
commit
881c91d696
@ -1993,7 +1993,9 @@ INCLUDE_FILE_PATTERNS =
|
||||
|
||||
PREDEFINED = \
|
||||
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
|
||||
# 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.
|
||||
# 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
|
||||
# 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
|
||||
}
|
||||
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 StartArray() { return out_.StartArray(); }
|
||||
bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); }
|
||||
|
@ -17,6 +17,10 @@ struct MyHandler {
|
||||
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 StartArray() { cout << "StartArray()" << endl; return true; }
|
||||
bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; }
|
||||
|
@ -24,6 +24,7 @@
|
||||
/*! \file document.h */
|
||||
|
||||
#include "reader.h"
|
||||
#include "internal/meta.h"
|
||||
#include "internal/strfunc.h"
|
||||
#include <new> // placement new
|
||||
|
||||
@ -38,15 +39,17 @@ RAPIDJSON_DIAG_OFF(effc++)
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_HAS_STDSTRING
|
||||
|
||||
#ifndef RAPIDJSON_HAS_STDSTRING
|
||||
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||
#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
|
||||
#else
|
||||
#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
|
||||
#endif
|
||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
||||
/*! \def RAPIDJSON_HAS_STDSTRING
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\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
|
||||
for construction and comparison.
|
||||
|
||||
@ -56,7 +59,6 @@ RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif // RAPIDJSON_HAS_STDSTRING
|
||||
|
||||
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
|
||||
#include "internal/meta.h"
|
||||
#include <iterator> // std::iterator, std::random_access_iterator_tag
|
||||
#endif
|
||||
|
||||
@ -277,7 +279,7 @@ struct GenericStringRef {
|
||||
GenericValue instead.
|
||||
*/
|
||||
template<SizeType N>
|
||||
GenericStringRef(const CharType (&str)[N])
|
||||
GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
|
||||
: s(str), length(N-1) {}
|
||||
|
||||
//! Explicitly create string reference from \c const character pointer
|
||||
@ -300,7 +302,7 @@ struct GenericStringRef {
|
||||
GenericValue instead.
|
||||
*/
|
||||
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
|
||||
/*! \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));
|
||||
}
|
||||
|
||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
//! Mark a string object as constant string
|
||||
/*! 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
|
||||
@ -382,6 +384,22 @@ inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& s
|
||||
}
|
||||
#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
|
||||
|
||||
@ -414,7 +432,14 @@ public:
|
||||
//@{
|
||||
|
||||
//! 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:
|
||||
//! Copy constructor is not permitted.
|
||||
@ -427,7 +452,7 @@ public:
|
||||
\param type Type of the value.
|
||||
\note Default content for number is zero.
|
||||
*/
|
||||
GenericValue(Type type) : data_(), flags_() {
|
||||
GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() {
|
||||
static const unsigned defaultFlags[7] = {
|
||||
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag,
|
||||
kNumberAnyFlag
|
||||
@ -444,7 +469,7 @@ public:
|
||||
\see CopyFrom()
|
||||
*/
|
||||
template< typename SourceAllocator >
|
||||
GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator & allocator);
|
||||
GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
|
||||
|
||||
//! Constructor for boolean value.
|
||||
/*! \param b Boolean value
|
||||
@ -454,28 +479,31 @@ public:
|
||||
*/
|
||||
#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
|
||||
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
|
||||
explicit GenericValue(bool b)
|
||||
explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
|
||||
#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.
|
||||
explicit GenericValue(int i) : data_(), flags_(kNumberIntFlag) {
|
||||
explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) {
|
||||
data_.n.i64 = i;
|
||||
if (i >= 0)
|
||||
flags_ |= kUintFlag | kUint64Flag;
|
||||
}
|
||||
|
||||
//! Constructor for unsigned value.
|
||||
explicit GenericValue(unsigned u) : data_(), flags_(kNumberUintFlag) {
|
||||
explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) {
|
||||
data_.n.u64 = u;
|
||||
if (!(u & 0x80000000))
|
||||
flags_ |= kIntFlag | kInt64Flag;
|
||||
}
|
||||
|
||||
//! 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;
|
||||
if (i64 >= 0) {
|
||||
flags_ |= kNumberUint64Flag;
|
||||
@ -489,7 +517,7 @@ public:
|
||||
}
|
||||
|
||||
//! 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;
|
||||
if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
|
||||
flags_ |= kInt64Flag;
|
||||
@ -500,13 +528,13 @@ public:
|
||||
}
|
||||
|
||||
//! 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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
/*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
|
||||
*/
|
||||
@ -557,19 +585,26 @@ public:
|
||||
//! Assignment with move semantics.
|
||||
/*! \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);
|
||||
this->~GenericValue();
|
||||
RawAssign(rhs);
|
||||
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)
|
||||
/*! \param str Constant string reference to be assigned
|
||||
\note This overload is needed to avoid clashes with the generic primitive type assignment overload below.
|
||||
\see GenericStringRef, operator=(T)
|
||||
*/
|
||||
GenericValue& operator=(StringRefType str) {
|
||||
GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {
|
||||
GenericValue s(str);
|
||||
return *this = s;
|
||||
}
|
||||
@ -587,7 +622,7 @@ public:
|
||||
use \ref SetBool() instead.
|
||||
*/
|
||||
template <typename T>
|
||||
RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,GenericValue&)
|
||||
RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
|
||||
operator=(T value) {
|
||||
GenericValue v(value);
|
||||
return *this = v;
|
||||
@ -600,10 +635,10 @@ public:
|
||||
\param allocator Allocator to use for copying
|
||||
*/
|
||||
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);
|
||||
this->~GenericValue();
|
||||
new (this) GenericValue(rhs,allocator);
|
||||
new (this) GenericValue(rhs, allocator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -612,7 +647,7 @@ public:
|
||||
\param other Another value.
|
||||
\note Constant complexity.
|
||||
*/
|
||||
GenericValue& Swap(GenericValue& other) {
|
||||
GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {
|
||||
GenericValue temp;
|
||||
temp.RawAssign(*this);
|
||||
RawAssign(other);
|
||||
@ -622,7 +657,7 @@ public:
|
||||
|
||||
//! Prepare Value for move semantics
|
||||
/*! \return *this */
|
||||
GenericValue& Move() { return *this; }
|
||||
GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
|
||||
//@}
|
||||
|
||||
//!@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 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())
|
||||
return false;
|
||||
|
||||
@ -641,7 +678,7 @@ public:
|
||||
if (data_.o.size != rhs.data_.o.size)
|
||||
return false;
|
||||
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)
|
||||
return false;
|
||||
}
|
||||
@ -659,7 +696,7 @@ public:
|
||||
return StringEqual(rhs);
|
||||
|
||||
case kNumberType:
|
||||
if (IsDouble() || rhs.GetDouble())
|
||||
if (IsDouble() || rhs.IsDouble())
|
||||
return GetDouble() == rhs.GetDouble(); // May convert one operand from integer to double.
|
||||
else
|
||||
return data_.n.u64 == rhs.data_.n.u64;
|
||||
@ -672,7 +709,7 @@ public:
|
||||
//! Equal-to operator with const C-string pointer
|
||||
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
|
||||
/*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
|
||||
*/
|
||||
@ -682,22 +719,31 @@ public:
|
||||
//! 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
|
||||
*/
|
||||
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
|
||||
/*! \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)
|
||||
/*! \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)
|
||||
/*! \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
|
||||
@ -766,7 +812,8 @@ public:
|
||||
|
||||
// This version is faster because it does not need a StrLen().
|
||||
// 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);
|
||||
if (member != MemberEnd())
|
||||
return member->value;
|
||||
@ -776,7 +823,8 @@ public:
|
||||
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
|
||||
/*! \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 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.
|
||||
/*!
|
||||
@ -844,7 +893,8 @@ public:
|
||||
\c std::map, this has been changed to MemberEnd() now.
|
||||
\note Linear time complexity.
|
||||
*/
|
||||
MemberIterator FindMember(const GenericValue& name) {
|
||||
template <typename SourceAllocator>
|
||||
MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
|
||||
RAPIDJSON_ASSERT(IsObject());
|
||||
RAPIDJSON_ASSERT(name.IsString());
|
||||
MemberIterator member = MemberBegin();
|
||||
@ -853,7 +903,7 @@ public:
|
||||
break;
|
||||
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.
|
||||
/*! \param name A string value as name of member.
|
||||
@ -877,7 +927,7 @@ public:
|
||||
}
|
||||
else {
|
||||
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)));
|
||||
}
|
||||
}
|
||||
@ -887,6 +937,23 @@ public:
|
||||
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.
|
||||
/*! \param name A constant string reference as name of member.
|
||||
\param value Value of any type.
|
||||
@ -934,7 +1001,7 @@ public:
|
||||
\note Amortized Constant time complexity.
|
||||
*/
|
||||
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) {
|
||||
GenericValue n(name);
|
||||
GenericValue v(value);
|
||||
@ -963,7 +1030,8 @@ public:
|
||||
return RemoveMember(n);
|
||||
}
|
||||
|
||||
bool RemoveMember(const GenericValue& name) {
|
||||
template <typename SourceAllocator>
|
||||
bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
|
||||
MemberIterator m = FindMember(name);
|
||||
if (m != MemberEnd()) {
|
||||
RemoveMember(m);
|
||||
@ -1122,11 +1190,17 @@ int z = a[0u].GetInt(); // This works too.
|
||||
GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
|
||||
RAPIDJSON_ASSERT(IsArray());
|
||||
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);
|
||||
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.
|
||||
/*! \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().
|
||||
@ -1158,7 +1232,7 @@ int z = a[0u].GetInt(); // This works too.
|
||||
\note Amortized constant time complexity.
|
||||
*/
|
||||
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) {
|
||||
GenericValue v(value);
|
||||
return PushBack(v, allocator);
|
||||
@ -1239,12 +1313,12 @@ int z = a[0u].GetInt(); // This works too.
|
||||
//!@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.
|
||||
/*! 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.
|
||||
/*! 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); }
|
||||
|
||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
//! Set this value as a string by copying from source string.
|
||||
/*! \param s source string.
|
||||
\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())
|
||||
return false;
|
||||
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;
|
||||
if (!m->value.Accept(handler))
|
||||
return false;
|
||||
@ -1328,7 +1402,7 @@ int z = a[0u].GetInt(); // This works too.
|
||||
return handler.EndArray(data_.a.size);
|
||||
|
||||
case kStringType:
|
||||
return handler.String(data_.s.str, data_.s.length, (flags_ & kCopyFlag) != 0);
|
||||
return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0);
|
||||
|
||||
case kNumberType:
|
||||
if (IsInt()) return handler.Int(data_.n.i.i);
|
||||
@ -1344,8 +1418,8 @@ int z = a[0u].GetInt(); // This works too.
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename, typename, typename>
|
||||
friend class GenericDocument;
|
||||
template <typename, typename> friend class GenericValue;
|
||||
template <typename, typename, typename> friend class GenericDocument;
|
||||
|
||||
enum {
|
||||
kBoolFlag = 0x100,
|
||||
@ -1357,6 +1431,7 @@ private:
|
||||
kDoubleFlag = 0x4000,
|
||||
kStringFlag = 0x100000,
|
||||
kCopyFlag = 0x200000,
|
||||
kInlineStrFlag = 0x400000,
|
||||
|
||||
// Initial flags of different types.
|
||||
kNullFlag = kNullType,
|
||||
@ -1370,6 +1445,7 @@ private:
|
||||
kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
|
||||
kConstStringFlag = kStringType | kStringFlag,
|
||||
kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
|
||||
kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
|
||||
kObjectFlag = kObjectType,
|
||||
kArrayFlag = kArrayType,
|
||||
|
||||
@ -1385,6 +1461,23 @@ private:
|
||||
unsigned hashcode; //!< reserved
|
||||
}; // 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.
|
||||
union Number {
|
||||
#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
|
||||
@ -1425,6 +1518,7 @@ private:
|
||||
|
||||
union Data {
|
||||
String s;
|
||||
ShortString ss;
|
||||
Number n;
|
||||
Object o;
|
||||
Array a;
|
||||
@ -1447,7 +1541,7 @@ private:
|
||||
}
|
||||
|
||||
//! Initialize this value as constant string, without calling destructor.
|
||||
void SetStringRaw(StringRefType s) {
|
||||
void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
|
||||
flags_ = kConstStringFlag;
|
||||
data_.s.str = s;
|
||||
data_.s.length = s.length;
|
||||
@ -1455,26 +1549,42 @@ private:
|
||||
|
||||
//! Initialize this value as copy string with initial data, without calling destructor.
|
||||
void SetStringRaw(StringRefType s, Allocator& allocator) {
|
||||
flags_ = kCopyStringFlag;
|
||||
data_.s.str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch));
|
||||
data_.s.length = s.length;
|
||||
memcpy(const_cast<Ch*>(data_.s.str), s, s.length * sizeof(Ch));
|
||||
const_cast<Ch*>(data_.s.str)[s.length] = '\0';
|
||||
Ch* str = NULL;
|
||||
if(ShortString::Usable(s.length)) {
|
||||
flags_ = kShortStringFlag;
|
||||
data_.ss.SetLength(s.length);
|
||||
str = data_.ss.str;
|
||||
} else {
|
||||
flags_ = kCopyStringFlag;
|
||||
data_.s.length = s.length;
|
||||
str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch));
|
||||
data_.s.str = str;
|
||||
}
|
||||
memcpy(str, s, s.length * sizeof(Ch));
|
||||
str[s.length] = '\0';
|
||||
}
|
||||
|
||||
//! Assignment without calling destructor
|
||||
void RawAssign(GenericValue& rhs) {
|
||||
void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
|
||||
data_ = rhs.data_;
|
||||
flags_ = rhs.flags_;
|
||||
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(rhs.IsString());
|
||||
return data_.s.length == rhs.data_.s.length &&
|
||||
(data_.s.str == rhs.data_.s.str // fast path for constant string
|
||||
|| memcmp(data_.s.str, rhs.data_.s.str, sizeof(Ch) * data_.s.length) == 0);
|
||||
|
||||
const SizeType len1 = GetStringLength();
|
||||
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_;
|
||||
@ -1663,7 +1773,7 @@ private:
|
||||
|
||||
// callers of the following private Handler functions
|
||||
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
|
||||
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 Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }
|
||||
|
||||
bool EndObject(SizeType memberCount) {
|
||||
typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
|
||||
stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
|
||||
|
@ -21,57 +21,129 @@
|
||||
#ifndef 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__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#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
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
template <int N> struct IntegralC { enum { Value = N }; };
|
||||
template <bool Cond> struct BoolType : IntegralC<Cond> {};
|
||||
struct TrueType : BoolType<true> {};
|
||||
struct FalseType : BoolType<false> {};
|
||||
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
|
||||
template <typename T> struct Void { typedef void Type; };
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||
template <typename T> struct RemoveConst { 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> {};
|
||||
|
||||
template <typename T, typename U> struct IsSame : FalseType {};
|
||||
template <typename T> struct IsSame<T,T> : TrueType {};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsSame, IsConst, IsMoreConst, IsPointer
|
||||
//
|
||||
template <typename T, typename U> struct IsSame : FalseType {};
|
||||
template <typename T> struct IsSame<T, T> : TrueType {};
|
||||
|
||||
template <typename T> struct IsConst : FalseType {};
|
||||
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<T*> : TrueType {};
|
||||
|
||||
template <typename CT, typename T>
|
||||
struct IsMoreConst {
|
||||
enum { Value =
|
||||
( IsSame< typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>::Value
|
||||
&& ( IsConst<CT>::Value >= IsConst<T>::Value ) )
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsBaseOf
|
||||
//
|
||||
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
|
||||
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 T> struct EnableIfCond<true, T> { typedef T Type; };
|
||||
template <typename B, typename D> struct IsBaseOf
|
||||
: 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 <bool Condition, typename T = void>
|
||||
struct DisableIfCond : EnableIfCond<!Condition, T> {};
|
||||
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
|
||||
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||
@ -80,26 +152,37 @@ template <typename Condition, typename T = void>
|
||||
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||
|
||||
// SFINAE helpers
|
||||
struct SfinaeResultTag {};
|
||||
template <typename T> struct RemoveSfinaeFptr {};
|
||||
template <typename T> struct RemoveSfinaeFptr<SfinaeResultTag&(*)(T)> { typedef T Type; };
|
||||
struct SfinaeTag {};
|
||||
template <typename T> struct RemoveSfinaeTag;
|
||||
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
|
||||
|
||||
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||
typename ::rapidjson::internal::RemoveSfinaeFptr \
|
||||
< ::rapidjson::internal::SfinaeResultTag&(*) type>::Type
|
||||
typename ::rapidjson::internal::RemoveSfinaeTag \
|
||||
< ::rapidjson::internal::SfinaeTag&(*) type>::Type
|
||||
|
||||
#define RAPIDJSON_ENABLEIF(cond) \
|
||||
typename ::rapidjson::internal::EnableIf \
|
||||
<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) \
|
||||
typename ::rapidjson::internal::DisableIf<cond,returntype>::Type
|
||||
typename ::rapidjson::internal::DisableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
//@endcond
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
|
@ -88,6 +88,8 @@ public:
|
||||
return Base::WriteStartObject();
|
||||
}
|
||||
|
||||
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
|
||||
|
||||
bool EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
@ -135,6 +137,7 @@ public:
|
||||
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
|
||||
|
||||
//@}
|
||||
protected:
|
||||
|
@ -318,7 +318,12 @@ template<int x> struct StaticAssertTest {};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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_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)))
|
||||
|
||||
// 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_POP RAPIDJSON_DIAG_PRAGMA(pop)
|
||||
#else // GCC >= 4.2, < 4.6
|
||||
@ -352,6 +357,42 @@ template<int x> struct StaticAssertTest {};
|
||||
|
||||
#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
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -48,6 +48,11 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
#define RAPIDJSON_NOTHING /* deliberately empty */
|
||||
#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
|
||||
@ -156,6 +161,7 @@ concept Handler {
|
||||
bool Double(double d);
|
||||
bool String(const Ch* str, SizeType length, bool copy);
|
||||
bool StartObject();
|
||||
bool Key(const Ch* str, SizeType length, bool copy);
|
||||
bool EndObject(SizeType memberCount);
|
||||
bool StartArray();
|
||||
bool EndArray(SizeType elementCount);
|
||||
@ -185,6 +191,7 @@ struct BaseReaderHandler {
|
||||
bool Double(double) { 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 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 StartArray() { return static_cast<Override&>(*this).Default(); }
|
||||
bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }
|
||||
@ -475,7 +482,7 @@ private:
|
||||
if (is.Peek() != '"')
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
|
||||
|
||||
ParseString<parseFlags>(is, handler);
|
||||
ParseString<parseFlags>(is, handler, true);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
SkipWhitespace(is);
|
||||
@ -627,27 +634,30 @@ private:
|
||||
|
||||
// Parse string and generate String event. Different code paths for kParseInsituFlag.
|
||||
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);
|
||||
InputStream& s(copy.s);
|
||||
|
||||
bool success = false;
|
||||
if (parseFlags & kParseInsituFlag) {
|
||||
typename InputStream::Ch *head = s.PutBegin();
|
||||
ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
size_t length = s.PutEnd(head) - 1;
|
||||
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
|
||||
if (!handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false))
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
||||
const typename TargetEncoding::Ch* const str = (typename TargetEncoding::Ch*)head;
|
||||
success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));
|
||||
}
|
||||
else {
|
||||
StackStream<typename TargetEncoding::Ch> stackStream(stack_);
|
||||
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
size_t length = stackStream.Length();
|
||||
if (!handler.String(stackStream.Pop(), SizeType(length - 1), true))
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
||||
SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
|
||||
const typename TargetEncoding::Ch* const str = stackStream.Pop();
|
||||
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
|
||||
@ -712,29 +722,35 @@ private:
|
||||
}
|
||||
|
||||
template<typename InputStream, bool backup>
|
||||
class NumberStream {
|
||||
class NumberStream {};
|
||||
|
||||
template<typename InputStream>
|
||||
class NumberStream<InputStream, false> {
|
||||
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 Take() { return is.Take(); }
|
||||
size_t Tell() { return is.Tell(); }
|
||||
const char* Pop() { return 0; }
|
||||
|
||||
private:
|
||||
protected:
|
||||
NumberStream& operator=(const NumberStream&);
|
||||
|
||||
GenericReader& reader;
|
||||
InputStream& is;
|
||||
};
|
||||
|
||||
template<typename InputStream>
|
||||
struct NumberStream<InputStream, true> {
|
||||
class NumberStream<InputStream, true> : public NumberStream<InputStream, false> {
|
||||
typedef NumberStream<InputStream, false> Base;
|
||||
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() {
|
||||
stackStream.Put((char)is.Peek());
|
||||
return is.Take();
|
||||
stackStream.Put((char)Base::is.Peek());
|
||||
return Base::is.Take();
|
||||
}
|
||||
|
||||
const char* Pop() {
|
||||
@ -743,15 +759,22 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
GenericReader& reader;
|
||||
InputStream& is;
|
||||
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>
|
||||
void ParseNumber(InputStream& is, Handler& handler) {
|
||||
internal::StreamLocalCopy<InputStream> copy(is);
|
||||
NumberStream<InputStream, parseFlags & kParseFullPrecisionFlag> s(*this, copy.s);
|
||||
NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s(*this, copy.s);
|
||||
|
||||
// Parse minus
|
||||
bool minus = false;
|
||||
@ -800,11 +823,13 @@ private:
|
||||
// Parse 64bit int
|
||||
bool useDouble = false;
|
||||
bool useStrtod = false;
|
||||
double d = 0.0;
|
||||
if (use64bit) {
|
||||
if (minus)
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808
|
||||
if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') {
|
||||
d = i64;
|
||||
useDouble = true;
|
||||
break;
|
||||
}
|
||||
@ -814,6 +839,7 @@ private:
|
||||
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) || s.Peek() > '5') {
|
||||
d = i64;
|
||||
useDouble = true;
|
||||
break;
|
||||
}
|
||||
@ -823,9 +849,18 @@ private:
|
||||
|
||||
// Force double for big integer
|
||||
if (useDouble) {
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9')
|
||||
s.Take();
|
||||
useStrtod = true;
|
||||
if (parseFlags & kParseFullPrecisionFlag) {
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9')
|
||||
s.Take();
|
||||
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
|
||||
@ -834,27 +869,28 @@ private:
|
||||
s.Take();
|
||||
|
||||
if (!useDouble) {
|
||||
if (!use64bit) {
|
||||
i64 = i;
|
||||
use64bit = true;
|
||||
}
|
||||
|
||||
d = use64bit ? i64 : i;
|
||||
useDouble = true;
|
||||
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) {
|
||||
useStrtod = true;
|
||||
if (d >= 9007199254740991.0) {
|
||||
if (parseFlags & kParseFullPrecisionFlag)
|
||||
useStrtod = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
|
||||
d = d * 10.0 + static_cast<unsigned>(s.Take() - '0');
|
||||
--expFrac;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useDouble = true;
|
||||
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
s.Take();
|
||||
//s.Take();
|
||||
if (parseFlags & kParseFullPrecisionFlag)
|
||||
s.Take();
|
||||
else
|
||||
d = d * 10 + (s.Take() - '0');
|
||||
--expFrac;
|
||||
}
|
||||
|
||||
@ -865,7 +901,10 @@ private:
|
||||
// Parse exp = e [ minus / plus ] 1*DIGIT
|
||||
int exp = 0;
|
||||
if (s.Peek() == 'e' || s.Peek() == 'E') {
|
||||
useDouble = true;
|
||||
if (!useDouble) {
|
||||
d = use64bit ? i64 : i;
|
||||
useDouble = true;
|
||||
}
|
||||
s.Take();
|
||||
|
||||
bool expMinus = false;
|
||||
@ -893,43 +932,48 @@ private:
|
||||
|
||||
// Finish parsing, call event according to the type of number.
|
||||
bool cont = true;
|
||||
|
||||
// Pop stack no matter if it will be used or not.
|
||||
const char* str = s.Pop();
|
||||
const char* str = s.Pop(); // Pop stack no matter if it will be used or not.
|
||||
|
||||
if (useDouble) {
|
||||
int p = exp + expFrac;
|
||||
double d;
|
||||
double significand = use64bit ? i64 : i;
|
||||
|
||||
// Use fast path for string-to-double conversion if possible
|
||||
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||
if (!useStrtod && p > 22) {
|
||||
if (p < 22 + 16) {
|
||||
// Fast Path Cases In Disguise
|
||||
significand *= internal::Pow10(p - 22);
|
||||
p = 22;
|
||||
if (parseFlags & kParseFullPrecisionFlag) {
|
||||
// Use fast path for string-to-double conversion if possible
|
||||
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||
if (!useStrtod && p > 22) {
|
||||
if (p < 22 + 16) {
|
||||
// Fast Path Cases In Disguise
|
||||
d *= internal::Pow10(p - 22);
|
||||
p = 22;
|
||||
}
|
||||
else
|
||||
useStrtod = true;
|
||||
}
|
||||
else
|
||||
useStrtod = true;
|
||||
}
|
||||
|
||||
if (!useStrtod && p >= -22 && significand <= 9007199254740991.0) { // 2^53 - 1
|
||||
if (p >= 0)
|
||||
d = significand * internal::Pow10(p);
|
||||
else
|
||||
d = significand / internal::Pow10(-p);
|
||||
|
||||
if (minus)
|
||||
d = -d;
|
||||
if (!useStrtod && p >= -22 && d <= 9007199254740991.0) { // 2^53 - 1
|
||||
d = StrtodFastPath(d, p);
|
||||
if (minus)
|
||||
d = -d;
|
||||
}
|
||||
else {
|
||||
char* end = 0;
|
||||
d = strtod(str, &end);
|
||||
RAPIDJSON_ASSERT(*end == '\0'); // Should have consumed the whole string.
|
||||
|
||||
if (d == HUGE_VAL || d == -HUGE_VAL)
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
||||
}
|
||||
}
|
||||
else {
|
||||
char* end = 0;
|
||||
d = strtod(str, &end);
|
||||
RAPIDJSON_ASSERT(*end == '\0'); // Should have consumed the whole string.
|
||||
if (p < -308) {
|
||||
// Prevent expSum < -308, making Pow10(p) = 0
|
||||
d = StrtodFastPath(d, exp);
|
||||
d = StrtodFastPath(d, expFrac);
|
||||
}
|
||||
else
|
||||
d = StrtodFastPath(d, p);
|
||||
|
||||
if (d == HUGE_VAL || d == -HUGE_VAL)
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
||||
if (minus)
|
||||
d = -d;
|
||||
}
|
||||
cont = handler.Double(d);
|
||||
}
|
||||
@ -1247,7 +1291,7 @@ private:
|
||||
}
|
||||
|
||||
case IterativeParsingMemberKeyState:
|
||||
ParseString<parseFlags>(is, handler);
|
||||
ParseString<parseFlags>(is, handler, true);
|
||||
if (HasParseError())
|
||||
return IterativeParsingErrorState;
|
||||
else
|
||||
@ -1410,6 +1454,10 @@ typedef GenericReader<UTF8<>, UTF8<> > Reader;
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
@ -131,6 +131,8 @@ public:
|
||||
return WriteStartObject();
|
||||
}
|
||||
|
||||
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
|
||||
|
||||
bool EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||
@ -165,6 +167,7 @@ public:
|
||||
|
||||
//! Simpler but slower overload.
|
||||
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_;
|
||||
};
|
||||
|
||||
TEST(Reader, ParseNumberHandler) {
|
||||
#define TEST_NUMBER(Handler, str, x) \
|
||||
TEST(Reader, ParseNumber_Integer) {
|
||||
#define TEST_INTEGER(Handler, str, x) \
|
||||
{ \
|
||||
StringStream s(str); \
|
||||
Handler h; \
|
||||
@ -114,67 +114,19 @@ TEST(Reader, ParseNumberHandler) {
|
||||
EXPECT_EQ(double(x), h.actual_); \
|
||||
}
|
||||
|
||||
#define TEST_DOUBLE(str, x) \
|
||||
{ \
|
||||
StringStream s(str); \
|
||||
ParseDoubleHandler h; \
|
||||
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_INTEGER(ParseUintHandler, "0", 0);
|
||||
TEST_INTEGER(ParseUintHandler, "123", 123);
|
||||
TEST_INTEGER(ParseUintHandler, "2147483648", 2147483648u); // 2^31 - 1 (cannot be stored in int)
|
||||
TEST_INTEGER(ParseUintHandler, "4294967295", 4294967295u);
|
||||
|
||||
TEST_NUMBER(ParseUintHandler, "0", 0);
|
||||
TEST_NUMBER(ParseUintHandler, "123", 123);
|
||||
TEST_NUMBER(ParseUintHandler, "2147483648", 2147483648u); // 2^31 - 1 (cannot be stored in int)
|
||||
TEST_NUMBER(ParseUintHandler, "4294967295", 4294967295u);
|
||||
TEST_INTEGER(ParseIntHandler, "-123", -123);
|
||||
TEST_INTEGER(ParseIntHandler, "-2147483648", -2147483648LL); // -2^31 (min of int)
|
||||
|
||||
TEST_NUMBER(ParseIntHandler, "-123", -123);
|
||||
TEST_NUMBER(ParseIntHandler, "-2147483648", -2147483648LL); // -2^31 (min of int)
|
||||
TEST_INTEGER(ParseUint64Handler, "4294967296", 4294967296ULL); // 2^32 (max of unsigned + 1, force to use uint64_t)
|
||||
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_NUMBER(ParseUint64Handler, "18446744073709551615", 18446744073709551615ULL); // 2^64 - 1 (max of uint64_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);
|
||||
}
|
||||
TEST_INTEGER(ParseInt64Handler, "-2147483649", -2147483649LL); // -2^31 -1 (min of int - 1, force to use int64_t)
|
||||
TEST_INTEGER(ParseInt64Handler, "-9223372036854775808", (-9223372036854775807LL - 1)); // -2^63 (min of int64_t)
|
||||
|
||||
// Random test for uint32_t/int32_t
|
||||
{
|
||||
@ -189,11 +141,11 @@ TEST(Reader, ParseNumberHandler) {
|
||||
|
||||
char buffer[32];
|
||||
*internal::u32toa(u.u, buffer) = '\0';
|
||||
TEST_NUMBER(ParseUintHandler, buffer, u.u);
|
||||
TEST_INTEGER(ParseUintHandler, buffer, u.u);
|
||||
|
||||
if (u.i < 0) {
|
||||
*internal::i32toa(u.i, buffer) = '\0';
|
||||
TEST_NUMBER(ParseIntHandler, buffer, u.i);
|
||||
TEST_INTEGER(ParseIntHandler, buffer, u.i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -213,41 +165,109 @@ TEST(Reader, ParseNumberHandler) {
|
||||
char buffer[32];
|
||||
if (u.u >= 4294967296ULL) {
|
||||
*internal::u64toa(u.u, buffer) = '\0';
|
||||
TEST_NUMBER(ParseUint64Handler, buffer, u.u);
|
||||
TEST_INTEGER(ParseUint64Handler, buffer, u.u);
|
||||
}
|
||||
|
||||
if (u.i <= -2147483649LL) {
|
||||
*internal::i64toa(u.i, buffer) = '\0';
|
||||
TEST_NUMBER(ParseInt64Handler, buffer, u.i);
|
||||
TEST_INTEGER(ParseInt64Handler, buffer, u.i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef TEST_INTEGER
|
||||
}
|
||||
|
||||
// Random test for double
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t u;
|
||||
}u;
|
||||
Random r;
|
||||
|
||||
for (unsigned i = 0; i < 100000; i++) {
|
||||
do {
|
||||
// Need to call r() in two statements for cross-platform coherent sequence.
|
||||
u.u = uint64_t(r()) << 32;
|
||||
u.u |= uint64_t(r());
|
||||
} while (isnan(u.d) || isinf(u.d));
|
||||
|
||||
char buffer[32];
|
||||
*internal::dtoa(u.d, buffer) = '\0';
|
||||
TEST_DOUBLE(buffer, u.d);
|
||||
}
|
||||
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_); \
|
||||
}
|
||||
|
||||
#undef TEST_NUMBER
|
||||
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 {
|
||||
double d;
|
||||
uint64_t u;
|
||||
}u;
|
||||
Random r;
|
||||
|
||||
for (unsigned i = 0; i < 100000; i++) {
|
||||
do {
|
||||
// Need to call r() in two statements for cross-platform coherent sequence.
|
||||
u.u = uint64_t(r()) << 32;
|
||||
u.u |= uint64_t(r());
|
||||
} 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];
|
||||
*internal::dtoa(u.d, buffer) = '\0';
|
||||
TEST_DOUBLE(fullPrecision, buffer, u.d);
|
||||
}
|
||||
}
|
||||
|
||||
#undef TEST_DOUBLE
|
||||
}
|
||||
|
||||
TEST(Reader, ParseNumber_NormalPrecisionDouble) {
|
||||
TestParseDouble<false>();
|
||||
}
|
||||
|
||||
TEST(Reader, ParseNumber_FullPrecisionDouble) {
|
||||
TestParseDouble<true>();
|
||||
}
|
||||
|
||||
TEST(Reader, ParseNumber_Error) {
|
||||
#define TEST_NUMBER_ERROR(errorCode, str) \
|
||||
{ \
|
||||
@ -894,9 +914,10 @@ struct IterativeParsingReaderHandler {
|
||||
const static int LOG_DOUBLE = -7;
|
||||
const static int LOG_STRING = -8;
|
||||
const static int LOG_STARTOBJECT = -9;
|
||||
const static int LOG_ENDOBJECT = -10;
|
||||
const static int LOG_STARTARRAY = -11;
|
||||
const static int LOG_ENDARRAY = -12;
|
||||
const static int LOG_KEY = -10;
|
||||
const static int LOG_ENDOBJECT = -11;
|
||||
const static int LOG_STARTARRAY = -12;
|
||||
const static int LOG_ENDARRAY = -13;
|
||||
|
||||
const static size_t LogCapacity = 256;
|
||||
int Logs[LogCapacity];
|
||||
@ -923,6 +944,8 @@ struct IterativeParsingReaderHandler {
|
||||
|
||||
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) {
|
||||
RAPIDJSON_ASSERT(LogCount < LogCapacity);
|
||||
Logs[LogCount++] = LOG_ENDOBJECT;
|
||||
@ -955,7 +978,7 @@ TEST(Reader, IterativeParsing_General) {
|
||||
handler.LOG_STARTARRAY,
|
||||
handler.LOG_INT,
|
||||
handler.LOG_STARTOBJECT,
|
||||
handler.LOG_STRING,
|
||||
handler.LOG_KEY,
|
||||
handler.LOG_STARTARRAY,
|
||||
handler.LOG_INT,
|
||||
handler.LOG_INT,
|
||||
@ -993,7 +1016,7 @@ TEST(Reader, IterativeParsing_Count) {
|
||||
handler.LOG_STARTOBJECT,
|
||||
handler.LOG_ENDOBJECT, 0,
|
||||
handler.LOG_STARTOBJECT,
|
||||
handler.LOG_STRING,
|
||||
handler.LOG_KEY,
|
||||
handler.LOG_INT,
|
||||
handler.LOG_ENDOBJECT, 1,
|
||||
handler.LOG_STARTARRAY,
|
||||
|
@ -89,15 +89,9 @@ inline FILE* TempFile(char *filename) {
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
|
||||
class AssertException : public std::exception {
|
||||
class AssertException : public std::logic_error {
|
||||
public:
|
||||
AssertException(const char* w) : what_(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_;
|
||||
AssertException(const char* w) : std::logic_error(w) {}
|
||||
};
|
||||
|
||||
#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
TEST(Value, default_constructor) {
|
||||
TEST(Value, DefaultConstructor) {
|
||||
Value x;
|
||||
EXPECT_EQ(kNullType, x.GetType());
|
||||
EXPECT_TRUE(x.IsNull());
|
||||
@ -38,7 +38,32 @@ TEST(Value, default_constructor) {
|
||||
// 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 y;
|
||||
y = x;
|
||||
@ -63,6 +88,22 @@ TEST(Value, assignment_operator) {
|
||||
y = StringRef(mstr);
|
||||
EXPECT_TRUE(y.IsString());
|
||||
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>
|
||||
@ -81,7 +122,7 @@ void TestUnequal(const A& a, const B& b) {
|
||||
EXPECT_TRUE (b != a);
|
||||
}
|
||||
|
||||
TEST(Value, equalto_operator) {
|
||||
TEST(Value, EqualtoOperator) {
|
||||
Value::AllocatorType allocator;
|
||||
Value x(kObjectType);
|
||||
x.AddMember("hello", "world", allocator)
|
||||
@ -105,16 +146,33 @@ TEST(Value, equalto_operator) {
|
||||
TestEqual(x["i"], 123);
|
||||
TestEqual(x["pi"], 3.14);
|
||||
|
||||
// Test operator==()
|
||||
Value y;
|
||||
y.CopyFrom(x, allocator);
|
||||
// Test operator==() (including different allocators)
|
||||
CrtAllocator crtAllocator;
|
||||
GenericValue<UTF8<>, CrtAllocator> y;
|
||||
GenericDocument<UTF8<>, CrtAllocator> z(&crtAllocator);
|
||||
y.CopyFrom(x, crtAllocator);
|
||||
z.CopyFrom(y, z.GetAllocator());
|
||||
TestEqual(x, y);
|
||||
TestEqual(y, z);
|
||||
TestEqual(z, x);
|
||||
|
||||
// Swapping member order should be fine.
|
||||
y.RemoveMember("t");
|
||||
EXPECT_TRUE(y.RemoveMember("t"));
|
||||
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(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>
|
||||
@ -538,7 +596,7 @@ TEST(Value, String) {
|
||||
EXPECT_STREQ("World", w.GetString());
|
||||
EXPECT_EQ(5u, w.GetStringLength());
|
||||
|
||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
{
|
||||
std::string str = "Hello World";
|
||||
str[5] = '\0';
|
||||
@ -626,6 +684,21 @@ TEST(Value, Array) {
|
||||
EXPECT_TRUE(y[4u].IsString());
|
||||
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
|
||||
Value::ValueIterator itr = x.Begin();
|
||||
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.
|
||||
#if 0
|
||||
// http://en.wikipedia.org/wiki/Erase-remove_idiom
|
||||
x.Clear();
|
||||
for (int i = 0; i < 10; i++)
|
||||
@ -743,11 +815,11 @@ TEST(Value, Array) {
|
||||
else
|
||||
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());
|
||||
for (int i = 0; i < 5; i++)
|
||||
EXPECT_EQ(i * 2, x[i]);
|
||||
#endif
|
||||
|
||||
// SetArray()
|
||||
Value z;
|
||||
@ -801,6 +873,22 @@ TEST(Value, Object) {
|
||||
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
|
||||
Value name;
|
||||
const Value C0D("C\0D", 3);
|
||||
@ -818,10 +906,18 @@ TEST(Value, Object) {
|
||||
EXPECT_TRUE(x.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[]
|
||||
EXPECT_STREQ("Apple", x["A"].GetString());
|
||||
EXPECT_STREQ("Banana", x["B"].GetString());
|
||||
EXPECT_STREQ("CherryD", x[C0D].GetString());
|
||||
EXPECT_STREQ("CherryD", x[othername].GetString());
|
||||
|
||||
// const operator[]
|
||||
EXPECT_STREQ("Apple", y["A"].GetString());
|
||||
@ -892,7 +988,7 @@ TEST(Value, Object) {
|
||||
x.RemoveMember("B");
|
||||
EXPECT_FALSE(x.HasMember("B"));
|
||||
|
||||
x.RemoveMember(name);
|
||||
x.RemoveMember(othername);
|
||||
EXPECT_FALSE(x.HasMember(name));
|
||||
|
||||
EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
|
||||
@ -905,11 +1001,14 @@ TEST(Value, Object) {
|
||||
for (int i = 0; i < 10; i++)
|
||||
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
|
||||
itr = x.EraseMember(x.MemberBegin());
|
||||
EXPECT_FALSE(x.HasMember(keys[0]));
|
||||
EXPECT_EQ(x.MemberBegin(), itr);
|
||||
EXPECT_EQ(9, x.MemberEnd() - x.MemberBegin());
|
||||
EXPECT_EQ(9u, x.MemberCount());
|
||||
for (; itr != x.MemberEnd(); ++itr) {
|
||||
int i = (itr - x.MemberBegin()) + 1;
|
||||
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
||||
@ -920,7 +1019,7 @@ TEST(Value, Object) {
|
||||
itr = x.EraseMember(x.MemberEnd() - 1);
|
||||
EXPECT_FALSE(x.HasMember(keys[9]));
|
||||
EXPECT_EQ(x.MemberEnd(), itr);
|
||||
EXPECT_EQ(8, x.MemberEnd() - x.MemberBegin());
|
||||
EXPECT_EQ(8u, x.MemberCount());
|
||||
for (; itr != x.MemberEnd(); ++itr) {
|
||||
int i = (itr - x.MemberBegin()) + 1;
|
||||
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
||||
@ -931,7 +1030,7 @@ TEST(Value, Object) {
|
||||
itr = x.EraseMember(x.MemberBegin() + 4);
|
||||
EXPECT_FALSE(x.HasMember(keys[5]));
|
||||
EXPECT_EQ(x.MemberBegin() + 4, itr);
|
||||
EXPECT_EQ(7, x.MemberEnd() - x.MemberBegin());
|
||||
EXPECT_EQ(7u, x.MemberCount());
|
||||
for (; itr != x.MemberEnd(); ++itr) {
|
||||
int i = (itr - x.MemberBegin());
|
||||
i += (i<4) ? 1 : 2;
|
||||
@ -955,7 +1054,7 @@ TEST(Value, Object) {
|
||||
EXPECT_EQ(x.MemberBegin() + first, itr);
|
||||
|
||||
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++)
|
||||
EXPECT_EQ(i, x[keys[i]][0u].GetUint());
|
||||
for (unsigned i = first; i < n - removeCount; i++)
|
||||
@ -1059,3 +1158,23 @@ TEST(Document, CrtAllocator) {
|
||||
V a(kArrayType);
|
||||
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