document.h (rapidjson-1.0.2) | : | document.h (rapidjson-1.1.0) | ||
---|---|---|---|---|
skipping to change at line 23 | skipping to change at line 23 | |||
// specific language governing permissions and limitations under the License. | // specific language governing permissions and limitations under the License. | |||
#ifndef RAPIDJSON_DOCUMENT_H_ | #ifndef RAPIDJSON_DOCUMENT_H_ | |||
#define RAPIDJSON_DOCUMENT_H_ | #define RAPIDJSON_DOCUMENT_H_ | |||
/*! \file document.h */ | /*! \file document.h */ | |||
#include "reader.h" | #include "reader.h" | |||
#include "internal/meta.h" | #include "internal/meta.h" | |||
#include "internal/strfunc.h" | #include "internal/strfunc.h" | |||
#include "memorystream.h" | ||||
#include "encodedstream.h" | ||||
#include <new> // placement new | #include <new> // placement new | |||
#include <limits> | ||||
#ifdef _MSC_VER | ||||
RAPIDJSON_DIAG_PUSH | RAPIDJSON_DIAG_PUSH | |||
#ifdef _MSC_VER | ||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant | RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant | |||
#elif defined(__GNUC__) | RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible lo | |||
RAPIDJSON_DIAG_PUSH | ss of data | |||
RAPIDJSON_DIAG_OFF(effc++) | ||||
#endif | #endif | |||
/////////////////////////////////////////////////////////////////////////////// | #ifdef __clang__ | |||
// RAPIDJSON_HAS_STDSTRING | RAPIDJSON_DIAG_OFF(padded) | |||
RAPIDJSON_DIAG_OFF(switch-enum) | ||||
#ifndef RAPIDJSON_HAS_STDSTRING | RAPIDJSON_DIAG_OFF(c++98-compat) | |||
#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 | #endif | |||
/*! \def RAPIDJSON_HAS_STDSTRING | ||||
\ingroup RAPIDJSON_CONFIG | ||||
\brief Enable RapidJSON support for \c std::string | ||||
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. | ||||
\hideinitializer | #ifdef __GNUC__ | |||
*/ | RAPIDJSON_DIAG_OFF(effc++) | |||
#endif // !defined(RAPIDJSON_HAS_STDSTRING) | #if __GNUC__ >= 6 | |||
RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_N | ||||
#if RAPIDJSON_HAS_STDSTRING | OEXCEPT functions | |||
#include <string> | #endif | |||
#endif // RAPIDJSON_HAS_STDSTRING | #endif // __GNUC__ | |||
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS | #ifndef RAPIDJSON_NOMEMBERITERATORCLASS | |||
#include <iterator> // std::iterator, std::random_access_iterator_tag | #include <iterator> // std::iterator, std::random_access_iterator_tag | |||
#endif | #endif | |||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS | |||
#include <utility> // std::move | #include <utility> // std::move | |||
#endif | #endif | |||
RAPIDJSON_NAMESPACE_BEGIN | RAPIDJSON_NAMESPACE_BEGIN | |||
// Forward declaration. | // Forward declaration. | |||
template <typename Encoding, typename Allocator> | template <typename Encoding, typename Allocator> | |||
class GenericValue; | class GenericValue; | |||
template <typename Encoding, typename Allocator, typename StackAllocator> | ||||
class GenericDocument; | ||||
//! Name-value pair in a JSON object value. | //! Name-value pair in a JSON object value. | |||
/*! | /*! | |||
This class was internal to GenericValue. It used to be a inner struct. | This class was internal to GenericValue. It used to be a inner struct. | |||
But a compiler (IBM XL C/C++ for AIX) have reported to have problem with tha t so it moved as a namespace scope struct. | But a compiler (IBM XL C/C++ for AIX) have reported to have problem with tha t so it moved as a namespace scope struct. | |||
https://code.google.com/p/rapidjson/issues/detail?id=64 | https://code.google.com/p/rapidjson/issues/detail?id=64 | |||
*/ | */ | |||
template <typename Encoding, typename Allocator> | template <typename Encoding, typename Allocator> | |||
struct GenericMember { | struct GenericMember { | |||
GenericValue<Encoding, Allocator> name; //!< name of member (must be a s tring) | GenericValue<Encoding, Allocator> name; //!< name of member (must be a s tring) | |||
GenericValue<Encoding, Allocator> value; //!< value of member. | GenericValue<Encoding, Allocator> value; //!< value of member. | |||
skipping to change at line 158 | skipping to change at line 150 | |||
\li const -> non-const (not ok) | \li const -> non-const (not ok) | |||
\li const -> const (ok) | \li const -> const (ok) | |||
\li non-const -> const (ok) | \li non-const -> const (ok) | |||
\li non-const -> non-const (ok) | \li non-const -> non-const (ok) | |||
\note If the \c Const template parameter is already \c false, this | \note If the \c Const template parameter is already \c false, this | |||
constructor effectively defines a regular copy-constructor. | constructor effectively defines a regular copy-constructor. | |||
Otherwise, the copy constructor is implicitly defined. | Otherwise, the copy constructor is implicitly defined. | |||
*/ | */ | |||
GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} | GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} | |||
Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *t his; } | ||||
//! @name stepping | //! @name stepping | |||
//@{ | //@{ | |||
Iterator& operator++(){ ++ptr_; return *this; } | Iterator& operator++(){ ++ptr_; return *this; } | |||
Iterator& operator--(){ --ptr_; return *this; } | Iterator& operator--(){ --ptr_; return *this; } | |||
Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } | Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } | |||
Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } | Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } | |||
//@} | //@} | |||
//! @name increment/decrement | //! @name increment/decrement | |||
skipping to change at line 260 | skipping to change at line 253 | |||
Value y(StringRef(bar, 3)); // ok, explicitly pass length | Value y(StringRef(bar, 3)); // ok, explicitly pass length | |||
\endcode | \endcode | |||
\see StringRef, GenericValue::SetString | \see StringRef, GenericValue::SetString | |||
*/ | */ | |||
template<typename CharType> | template<typename CharType> | |||
struct GenericStringRef { | struct GenericStringRef { | |||
typedef CharType Ch; //!< character type of the string | typedef CharType Ch; //!< character type of the string | |||
//! Create string reference from \c const character array | //! Create string reference from \c const character array | |||
#ifndef __clang__ // -Wdocumentation | ||||
/*! | /*! | |||
This constructor implicitly creates a constant string reference from | This constructor implicitly creates a constant string reference from | |||
a \c const character array. It has better performance than | a \c const character array. It has better performance than | |||
\ref StringRef(const CharType*) by inferring the string \ref length | \ref StringRef(const CharType*) by inferring the string \ref length | |||
from the array length, and also supports strings containing null | from the array length, and also supports strings containing null | |||
characters. | characters. | |||
\tparam N length of the string, automatically inferred | \tparam N length of the string, automatically inferred | |||
\param str Constant character array, lifetime assumed to be longer | \param str Constant character array, lifetime assumed to be longer | |||
skipping to change at line 282 | skipping to change at line 276 | |||
\post \ref s == str | \post \ref s == str | |||
\note Constant complexity. | \note Constant complexity. | |||
\note There is a hidden, private overload to disallow references to | \note There is a hidden, private overload to disallow references to | |||
non-const character arrays to be created via this constructor. | non-const character arrays to be created via this constructor. | |||
By this, e.g. function-scope arrays used to be filled via | By this, e.g. function-scope arrays used to be filled via | |||
\c snprintf are excluded from consideration. | \c snprintf are excluded from consideration. | |||
In such cases, the referenced string should be \b copied to the | In such cases, the referenced string should be \b copied to the | |||
GenericValue instead. | GenericValue instead. | |||
*/ | */ | |||
#endif | ||||
template<SizeType N> | template<SizeType N> | |||
GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT | 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 | |||
#ifndef __clang__ // -Wdocumentation | ||||
/*! | /*! | |||
This constructor can be used to \b explicitly create a reference to | This constructor can be used to \b explicitly create a reference to | |||
a constant string pointer. | a constant string pointer. | |||
\see StringRef(const CharType*) | \see StringRef(const CharType*) | |||
\param str Constant character pointer, lifetime assumed to be longer | \param str Constant character pointer, lifetime assumed to be longer | |||
than the use of the string in e.g. a GenericValue | than the use of the string in e.g. a GenericValue | |||
\post \ref s == str | \post \ref s == str | |||
\note There is a hidden, private overload to disallow references to | \note There is a hidden, private overload to disallow references to | |||
non-const character arrays to be created via this constructor. | non-const character arrays to be created via this constructor. | |||
By this, e.g. function-scope arrays used to be filled via | By this, e.g. function-scope arrays used to be filled via | |||
\c snprintf are excluded from consideration. | \c snprintf are excluded from consideration. | |||
In such cases, the referenced string should be \b copied to the | In such cases, the referenced string should be \b copied to the | |||
GenericValue instead. | GenericValue instead. | |||
*/ | */ | |||
#endif | ||||
explicit GenericStringRef(const CharType* str) | explicit GenericStringRef(const CharType* str) | |||
: s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); } | : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); } | |||
//! Create constant string reference from pointer and length | //! Create constant string reference from pointer and length | |||
#ifndef __clang__ // -Wdocumentation | ||||
/*! \param str constant string, lifetime assumed to be longer than the use o f the string in e.g. a GenericValue | /*! \param str constant string, lifetime assumed to be longer than the use o f the string in e.g. a GenericValue | |||
\param len length of the string, excluding the trailing NULL terminator | \param len length of the string, excluding the trailing NULL terminator | |||
\post \ref s == str && \ref length == len | \post \ref s == str && \ref length == len | |||
\note Constant complexity. | \note Constant complexity. | |||
*/ | */ | |||
#endif | ||||
GenericStringRef(const CharType* str, SizeType len) | GenericStringRef(const CharType* str, SizeType len) | |||
: s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); } | : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); } | |||
GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) | ||||
{} | ||||
GenericStringRef& operator=(const GenericStringRef& rhs) { s = rhs.s; length | ||||
= rhs.length; } | ||||
//! implicit conversion to plain CharType pointer | //! implicit conversion to plain CharType pointer | |||
operator const Ch *() const { return s; } | operator const Ch *() const { return s; } | |||
const Ch* const s; //!< plain CharType pointer | const Ch* const s; //!< plain CharType pointer | |||
const SizeType length; //!< length of the string (excluding the trailing NUL L terminator) | const SizeType length; //!< length of the string (excluding the trailing NUL L terminator) | |||
private: | private: | |||
//! Disallow copy-assignment | ||||
GenericStringRef operator=(const GenericStringRef&); | ||||
//! Disallow construction from non-const array | //! Disallow construction from non-const array | |||
template<SizeType N> | template<SizeType N> | |||
GenericStringRef(CharType (&str)[N]) /* = delete */; | GenericStringRef(CharType (&str)[N]) /* = delete */; | |||
}; | }; | |||
//! Mark a character pointer as constant string | //! Mark a character pointer as constant string | |||
/*! Mark a plain character pointer as a "string literal". This function | /*! Mark a plain character pointer as a "string literal". This function | |||
can be used to avoid copying a character string to be referenced as a | can be used to avoid copying a character string to be referenced as a | |||
value in a JSON GenericValue object, if the string's lifetime is known | value in a JSON GenericValue object, if the string's lifetime is known | |||
to be valid long enough. | to be valid long enough. | |||
skipping to change at line 405 | skipping to change at line 406 | |||
// select candidates according to nested encoding and allocator types | // select candidates according to nested encoding and allocator types | |||
template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::Enc odingType>::Type, typename Void<typename T::AllocatorType>::Type> | template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::Enc odingType>::Type, typename Void<typename T::AllocatorType>::Type> | |||
: IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType> , T>::Type {}; | : IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType> , T>::Type {}; | |||
// helper to match arbitrary GenericValue instantiations, including derived clas ses | // helper to match arbitrary GenericValue instantiations, including derived clas ses | |||
template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {}; | template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {}; | |||
} // namespace internal | } // namespace internal | |||
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | |||
// TypeHelper | ||||
namespace internal { | ||||
template <typename ValueType, typename T> | ||||
struct TypeHelper {}; | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, bool> { | ||||
static bool Is(const ValueType& v) { return v.IsBool(); } | ||||
static bool Get(const ValueType& v) { return v.GetBool(); } | ||||
static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } | ||||
static ValueType& Set(ValueType& v, bool data, typename ValueType::Allocator | ||||
Type&) { return v.SetBool(data); } | ||||
}; | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, int> { | ||||
static bool Is(const ValueType& v) { return v.IsInt(); } | ||||
static int Get(const ValueType& v) { return v.GetInt(); } | ||||
static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } | ||||
static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorT | ||||
ype&) { return v.SetInt(data); } | ||||
}; | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, unsigned> { | ||||
static bool Is(const ValueType& v) { return v.IsUint(); } | ||||
static unsigned Get(const ValueType& v) { return v.GetUint(); } | ||||
static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); | ||||
} | ||||
static ValueType& Set(ValueType& v, unsigned data, typename ValueType::Alloc | ||||
atorType&) { return v.SetUint(data); } | ||||
}; | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, int64_t> { | ||||
static bool Is(const ValueType& v) { return v.IsInt64(); } | ||||
static int64_t Get(const ValueType& v) { return v.GetInt64(); } | ||||
static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); | ||||
} | ||||
static ValueType& Set(ValueType& v, int64_t data, typename ValueType::Alloca | ||||
torType&) { return v.SetInt64(data); } | ||||
}; | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, uint64_t> { | ||||
static bool Is(const ValueType& v) { return v.IsUint64(); } | ||||
static uint64_t Get(const ValueType& v) { return v.GetUint64(); } | ||||
static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data | ||||
); } | ||||
static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::Alloc | ||||
atorType&) { return v.SetUint64(data); } | ||||
}; | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, double> { | ||||
static bool Is(const ValueType& v) { return v.IsDouble(); } | ||||
static double Get(const ValueType& v) { return v.GetDouble(); } | ||||
static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); | ||||
} | ||||
static ValueType& Set(ValueType& v, double data, typename ValueType::Allocat | ||||
orType&) { return v.SetDouble(data); } | ||||
}; | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, float> { | ||||
static bool Is(const ValueType& v) { return v.IsFloat(); } | ||||
static float Get(const ValueType& v) { return v.GetFloat(); } | ||||
static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } | ||||
static ValueType& Set(ValueType& v, float data, typename ValueType::Allocato | ||||
rType&) { return v.SetFloat(data); } | ||||
}; | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, const typename ValueType::Ch*> { | ||||
typedef const typename ValueType::Ch* StringType; | ||||
static bool Is(const ValueType& v) { return v.IsString(); } | ||||
static StringType Get(const ValueType& v) { return v.GetString(); } | ||||
static ValueType& Set(ValueType& v, const StringType data) { return v.SetStr | ||||
ing(typename ValueType::StringRefType(data)); } | ||||
static ValueType& Set(ValueType& v, const StringType data, typename ValueTyp | ||||
e::AllocatorType& a) { return v.SetString(data, a); } | ||||
}; | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > { | ||||
typedef std::basic_string<typename ValueType::Ch> StringType; | ||||
static bool Is(const ValueType& v) { return v.IsString(); } | ||||
static StringType Get(const ValueType& v) { return StringType(v.GetString(), | ||||
v.GetStringLength()); } | ||||
static ValueType& Set(ValueType& v, const StringType& data, typename ValueTy | ||||
pe::AllocatorType& a) { return v.SetString(data, a); } | ||||
}; | ||||
#endif | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, typename ValueType::Array> { | ||||
typedef typename ValueType::Array ArrayType; | ||||
static bool Is(const ValueType& v) { return v.IsArray(); } | ||||
static ArrayType Get(ValueType& v) { return v.GetArray(); } | ||||
static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } | ||||
static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::Allo | ||||
catorType&) { return v = data; } | ||||
}; | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, typename ValueType::ConstArray> { | ||||
typedef typename ValueType::ConstArray ArrayType; | ||||
static bool Is(const ValueType& v) { return v.IsArray(); } | ||||
static ArrayType Get(const ValueType& v) { return v.GetArray(); } | ||||
}; | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, typename ValueType::Object> { | ||||
typedef typename ValueType::Object ObjectType; | ||||
static bool Is(const ValueType& v) { return v.IsObject(); } | ||||
static ObjectType Get(ValueType& v) { return v.GetObject(); } | ||||
static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } | ||||
static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::All | ||||
ocatorType&) { v = data; } | ||||
}; | ||||
template<typename ValueType> | ||||
struct TypeHelper<ValueType, typename ValueType::ConstObject> { | ||||
typedef typename ValueType::ConstObject ObjectType; | ||||
static bool Is(const ValueType& v) { return v.IsObject(); } | ||||
static ObjectType Get(const ValueType& v) { return v.GetObject(); } | ||||
}; | ||||
} // namespace internal | ||||
// Forward declarations | ||||
template <bool, typename> class GenericArray; | ||||
template <bool, typename> class GenericObject; | ||||
/////////////////////////////////////////////////////////////////////////////// | ||||
// GenericValue | // GenericValue | |||
//! Represents a JSON value. Use Value for UTF8 encoding and default allocator. | //! Represents a JSON value. Use Value for UTF8 encoding and default allocator. | |||
/*! | /*! | |||
A JSON value can be one of 7 types. This class is a variant type supporting | A JSON value can be one of 7 types. This class is a variant type supporting | |||
these types. | these types. | |||
Use the Value if UTF8 and default allocator | Use the Value if UTF8 and default allocator | |||
\tparam Encoding Encoding of the value. (Even non-string values need to h ave the same encoding in a document) | \tparam Encoding Encoding of the value. (Even non-string values need to h ave the same encoding in a document) | |||
skipping to change at line 431 | skipping to change at line 553 | |||
typedef GenericMember<Encoding, Allocator> Member; | typedef GenericMember<Encoding, Allocator> Member; | |||
typedef Encoding EncodingType; //!< Encoding type from temp late parameter. | typedef Encoding EncodingType; //!< Encoding type from temp late parameter. | |||
typedef Allocator AllocatorType; //!< Allocator type from tem plate parameter. | typedef Allocator AllocatorType; //!< Allocator type from tem plate parameter. | |||
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. | typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. | |||
typedef GenericStringRef<Ch> StringRefType; //!< Reference to a constant string | typedef GenericStringRef<Ch> StringRefType; //!< Reference to a constant string | |||
typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator M emberIterator; //!< Member iterator for iterating in object. | typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator M emberIterator; //!< Member iterator for iterating in object. | |||
typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator Co nstMemberIterator; //!< Constant member iterator for iterating in object. | typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator Co nstMemberIterator; //!< Constant member iterator for iterating in object. | |||
typedef GenericValue* ValueIterator; //!< Value iterator for iter ating in array. | typedef GenericValue* ValueIterator; //!< Value iterator for iter ating in array. | |||
typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. | typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. | |||
typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of i tself. | typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of i tself. | |||
typedef GenericArray<false, ValueType> Array; | ||||
typedef GenericArray<true, ValueType> ConstArray; | ||||
typedef GenericObject<false, ValueType> Object; | ||||
typedef GenericObject<true, ValueType> ConstObject; | ||||
//!@name Constructors and destructor. | //!@name Constructors and destructor. | |||
//@{ | //@{ | |||
//! Default constructor creates a null value. | //! Default constructor creates a null value. | |||
GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {} | GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } | |||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS | |||
//! Move constructor in C++11 | //! Move constructor in C++11 | |||
GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flag | GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) { | |||
s_(rhs.flags_) { | rhs.data_.f.flags = kNullFlag; // give up contents | |||
rhs.flags_ = kNullFlag; // give up contents | ||||
} | } | |||
#endif | #endif | |||
private: | private: | |||
//! Copy constructor is not permitted. | //! Copy constructor is not permitted. | |||
GenericValue(const GenericValue& rhs); | GenericValue(const GenericValue& rhs); | |||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||
//! Moving from a GenericDocument is not permitted. | ||||
template <typename StackAllocator> | ||||
GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs); | ||||
//! Move assignment from a GenericDocument is not permitted. | ||||
template <typename StackAllocator> | ||||
GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& | ||||
rhs); | ||||
#endif | ||||
public: | public: | |||
//! Constructor with JSON value type. | //! Constructor with JSON value type. | |||
/*! This creates a Value of specified type with default content. | /*! This creates a Value of specified type with default content. | |||
\param type Type of the value. | \param type Type of the value. | |||
\note Default content for number is zero. | \note Default content for number is zero. | |||
*/ | */ | |||
explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() { | explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { | |||
static const unsigned defaultFlags[7] = { | static const uint16_t defaultFlags[7] = { | |||
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStr ingFlag, | kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStr ingFlag, | |||
kNumberAnyFlag | kNumberAnyFlag | |||
}; | }; | |||
RAPIDJSON_ASSERT(type <= kNumberType); | RAPIDJSON_ASSERT(type <= kNumberType); | |||
flags_ = defaultFlags[type]; | data_.f.flags = defaultFlags[type]; | |||
// Use ShortString to store empty string. | // Use ShortString to store empty string. | |||
if (type == kStringType) | if (type == kStringType) | |||
data_.ss.SetLength(0); | data_.ss.SetLength(0); | |||
} | } | |||
//! Explicit copy constructor (with allocator) | //! Explicit copy constructor (with allocator) | |||
/*! Creates a copy of a Value by using the given Allocator | /*! Creates a copy of a Value by using the given Allocator | |||
\tparam SourceAllocator allocator of \c rhs | \tparam SourceAllocator allocator of \c rhs | |||
\param rhs Value to copy from (read-only) | \param rhs Value to copy from (read-only) | |||
skipping to change at line 487 | skipping to change at line 623 | |||
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 | |||
\note This constructor is limited to \em real boolean values and rejects | \note This constructor is limited to \em real boolean values and rejects | |||
implicitly converted types like arbitrary pointers. Use an explicit cast | implicitly converted types like arbitrary pointers. Use an explicit cast | |||
to \c bool, if you want to construct a boolean JSON value in such ca ses. | to \c bool, if you want to construct a boolean JSON value in such ca ses. | |||
*/ | */ | |||
#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>))) R APIDJSON_NOEXCEPT | explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<bool, T>))) RAPIDJSON_NOEXCEPT // See #472 | |||
#else | #else | |||
explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT | explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT | |||
#endif | #endif | |||
: data_(), flags_(b ? kTrueFlag : kFalseFlag) { | : data_() { | |||
// safe-guard against failing SFINAE | // safe-guard against failing SFINAE | |||
RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value)); | RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value)); | |||
data_.f.flags = b ? kTrueFlag : kFalseFlag; | ||||
} | } | |||
//! Constructor for int value. | //! Constructor for int value. | |||
explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt Flag) { | explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() { | |||
data_.n.i64 = i; | data_.n.i64 = i; | |||
if (i >= 0) | data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : | |||
flags_ |= kUintFlag | kUint64Flag; | kNumberIntFlag; | |||
} | } | |||
//! Constructor for unsigned value. | //! Constructor for unsigned value. | |||
explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumb erUintFlag) { | explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() { | |||
data_.n.u64 = u; | data_.n.u64 = u; | |||
if (!(u & 0x80000000)) | data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | | |||
flags_ |= kIntFlag | kInt64Flag; | kIntFlag | kInt64Flag); | |||
} | } | |||
//! Constructor for int64_t value. | //! Constructor for int64_t value. | |||
explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNum berInt64Flag) { | explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() { | |||
data_.n.i64 = i64; | data_.n.i64 = i64; | |||
data_.f.flags = kNumberInt64Flag; | ||||
if (i64 >= 0) { | if (i64 >= 0) { | |||
flags_ |= kNumberUint64Flag; | data_.f.flags |= kNumberUint64Flag; | |||
if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0 x00000000))) | if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0 x00000000))) | |||
flags_ |= kUintFlag; | data_.f.flags |= kUintFlag; | |||
if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0 x80000000))) | if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0 x80000000))) | |||
flags_ |= kIntFlag; | data_.f.flags |= kIntFlag; | |||
} | } | |||
else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x8 0000000))) | else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x8 0000000))) | |||
flags_ |= kIntFlag; | data_.f.flags |= kIntFlag; | |||
} | } | |||
//! Constructor for uint64_t value. | //! Constructor for uint64_t value. | |||
explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNu mberUint64Flag) { | explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() { | |||
data_.n.u64 = u64; | data_.n.u64 = u64; | |||
data_.f.flags = kNumberUint64Flag; | ||||
if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) | if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) | |||
flags_ |= kInt64Flag; | data_.f.flags |= kInt64Flag; | |||
if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) | if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) | |||
flags_ |= kUintFlag; | data_.f.flags |= kUintFlag; | |||
if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) | if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) | |||
flags_ |= kIntFlag; | data_.f.flags |= kIntFlag; | |||
} | } | |||
//! Constructor for double value. | //! Constructor for double value. | |||
explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumber DoubleFlag) { data_.n.d = d; } | explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d ; data_.f.flags = kNumberDoubleFlag; } | |||
//! Constructor for constant string (i.e. do not make a copy of string) | //! Constructor for constant string (i.e. do not make a copy of string) | |||
GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), fla gs_() { SetStringRaw(StringRef(s, length)); } | GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { Se tStringRaw(StringRef(s, length)); } | |||
//! Constructor for constant string (i.e. do not make a copy of string) | //! Constructor for constant string (i.e. do not make a copy of string) | |||
explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_( ) { SetStringRaw(s); } | explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStr ingRaw(s); } | |||
//! Constructor for copy-string (i.e. do make a copy of string) | //! Constructor for copy-string (i.e. do make a copy of string) | |||
GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); } | GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } | |||
//! Constructor for copy-string (i.e. do make a copy of string) | //! Constructor for copy-string (i.e. do make a copy of string) | |||
GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStri ngRaw(StringRef(s), allocator); } | GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(Stri ngRef(s), allocator); } | |||
#if RAPIDJSON_HAS_STDSTRING | #if RAPIDJSON_HAS_STDSTRING | |||
//! Constructor for copy-string from a string object (i.e. do make a copy of string) | //! Constructor for copy-string from a string object (i.e. do make a copy of string) | |||
/*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_ HAS_STDSTRING. | /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_ HAS_STDSTRING. | |||
*/ | */ | |||
GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() , flags_() { SetStringRaw(StringRef(s), allocator); } | GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } | |||
#endif | #endif | |||
//! Constructor for Array. | ||||
/*! | ||||
\param a An array obtained by \c GetArray(). | ||||
\note \c Array is always pass-by-value. | ||||
\note the source array is moved into this value and the sourec array bec | ||||
omes empty. | ||||
*/ | ||||
GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { | ||||
a.value_.data_ = Data(); | ||||
a.value_.data_.f.flags = kArrayFlag; | ||||
} | ||||
//! Constructor for Object. | ||||
/*! | ||||
\param o An object obtained by \c GetObject(). | ||||
\note \c Object is always pass-by-value. | ||||
\note the source object is moved into this value and the sourec object b | ||||
ecomes empty. | ||||
*/ | ||||
GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { | ||||
o.value_.data_ = Data(); | ||||
o.value_.data_.f.flags = kObjectFlag; | ||||
} | ||||
//! Destructor. | //! Destructor. | |||
/*! Need to destruct elements of array, members of object, or copy-string. | /*! Need to destruct elements of array, members of object, or copy-string. | |||
*/ | */ | |||
~GenericValue() { | ~GenericValue() { | |||
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait | if (Allocator::kNeedFree) { // Shortcut by Allocator's trait | |||
switch(flags_) { | switch(data_.f.flags) { | |||
case kArrayFlag: | case kArrayFlag: | |||
for (GenericValue* v = data_.a.elements; v != data_.a.elements + | { | |||
data_.a.size; ++v) | GenericValue* e = GetElementsPointer(); | |||
v->~GenericValue(); | for (GenericValue* v = e; v != e + data_.a.size; ++v) | |||
Allocator::Free(data_.a.elements); | v->~GenericValue(); | |||
Allocator::Free(e); | ||||
} | ||||
break; | break; | |||
case kObjectFlag: | case kObjectFlag: | |||
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) | for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) | |||
m->~Member(); | m->~Member(); | |||
Allocator::Free(data_.o.members); | Allocator::Free(GetMembersPointer()); | |||
break; | break; | |||
case kCopyStringFlag: | case kCopyStringFlag: | |||
Allocator::Free(const_cast<Ch*>(data_.s.str)); | Allocator::Free(const_cast<Ch*>(GetStringPointer())); | |||
break; | break; | |||
default: | default: | |||
break; // Do nothing for other types. | break; // Do nothing for other types. | |||
} | } | |||
} | } | |||
} | } | |||
//@} | //@} | |||
skipping to change at line 644 | skipping to change at line 806 | |||
} | } | |||
//! Deep-copy assignment from Value | //! Deep-copy assignment from Value | |||
/*! Assigns a \b copy of the Value to the current Value object | /*! Assigns a \b copy of the Value to the current Value object | |||
\tparam SourceAllocator Allocator type of \c rhs | \tparam SourceAllocator Allocator type of \c rhs | |||
\param rhs Value to copy from (read-only) | \param rhs Value to copy from (read-only) | |||
\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, A llocator& allocator) { | GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, A llocator& allocator) { | |||
RAPIDJSON_ASSERT((void*)this != (void const*)&rhs); | RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&r hs)); | |||
this->~GenericValue(); | this->~GenericValue(); | |||
new (this) GenericValue(rhs, allocator); | new (this) GenericValue(rhs, allocator); | |||
return *this; | return *this; | |||
} | } | |||
//! Exchange the contents of this value with those of other. | //! Exchange the contents of this value with those of other. | |||
/*! | /*! | |||
\param other Another value. | \param other Another value. | |||
\note Constant complexity. | \note Constant complexity. | |||
*/ | */ | |||
GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { | GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { | |||
GenericValue temp; | GenericValue temp; | |||
temp.RawAssign(*this); | temp.RawAssign(*this); | |||
RawAssign(other); | RawAssign(other); | |||
other.RawAssign(temp); | other.RawAssign(temp); | |||
return *this; | return *this; | |||
} | } | |||
//! free-standing swap function helper | ||||
/*! | ||||
Helper function to enable support for common swap implementation pattern | ||||
based on \c std::swap: | ||||
\code | ||||
void swap(MyClass& a, MyClass& b) { | ||||
using std::swap; | ||||
swap(a.value, b.value); | ||||
// ... | ||||
} | ||||
\endcode | ||||
\see Swap() | ||||
*/ | ||||
friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT | ||||
{ a.Swap(b); } | ||||
//! Prepare Value for move semantics | //! Prepare Value for move semantics | |||
/*! \return *this */ | /*! \return *this */ | |||
GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } | GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } | |||
//@} | //@} | |||
//!@name Equal-to and not-equal-to operators | //!@name Equal-to and not-equal-to operators | |||
//@{ | //@{ | |||
//! Equal-to operator | //! Equal-to operator | |||
/*! | /*! | |||
\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. | |||
skipping to change at line 712 | skipping to change at line 888 | |||
case kNumberType: | case kNumberType: | |||
if (IsDouble() || rhs.IsDouble()) { | if (IsDouble() || rhs.IsDouble()) { | |||
double a = GetDouble(); // May convert from integer to doubl e. | double a = GetDouble(); // May convert from integer to doubl e. | |||
double b = rhs.GetDouble(); // Ditto | double b = rhs.GetDouble(); // Ditto | |||
return a >= b && a <= b; // Prevent -Wfloat-equal | return a >= b && a <= b; // Prevent -Wfloat-equal | |||
} | } | |||
else | else | |||
return data_.n.u64 == rhs.data_.n.u64; | return data_.n.u64 == rhs.data_.n.u64; | |||
default: // kTrueType, kFalseType, kNullType | default: | |||
return true; | return true; | |||
} | } | |||
} | } | |||
//! 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(StringRe f(rhs)); } | bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRe f(rhs)); } | |||
#if 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. | |||
skipping to change at line 760 | skipping to change at line 936 | |||
//! 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 RAPIDJSON_DISABLEIF_RETURN((internal::IsGeneric Value<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !( rhs == lhs); } | template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGeneric Value<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !( rhs == lhs); } | |||
//@} | //@} | |||
//!@name Type | //!@name Type | |||
//@{ | //@{ | |||
Type GetType() const { return static_cast<Type>(flags_ & kTypeMask); } | Type GetType() const { return static_cast<Type>(data_.f.flags & kTypeMask); | |||
bool IsNull() const { return flags_ == kNullFlag; } | } | |||
bool IsFalse() const { return flags_ == kFalseFlag; } | bool IsNull() const { return data_.f.flags == kNullFlag; } | |||
bool IsTrue() const { return flags_ == kTrueFlag; } | bool IsFalse() const { return data_.f.flags == kFalseFlag; } | |||
bool IsBool() const { return (flags_ & kBoolFlag) != 0; } | bool IsTrue() const { return data_.f.flags == kTrueFlag; } | |||
bool IsObject() const { return flags_ == kObjectFlag; } | bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } | |||
bool IsArray() const { return flags_ == kArrayFlag; } | bool IsObject() const { return data_.f.flags == kObjectFlag; } | |||
bool IsNumber() const { return (flags_ & kNumberFlag) != 0; } | bool IsArray() const { return data_.f.flags == kArrayFlag; } | |||
bool IsInt() const { return (flags_ & kIntFlag) != 0; } | bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } | |||
bool IsUint() const { return (flags_ & kUintFlag) != 0; } | bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } | |||
bool IsInt64() const { return (flags_ & kInt64Flag) != 0; } | bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } | |||
bool IsUint64() const { return (flags_ & kUint64Flag) != 0; } | bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } | |||
bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; } | bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } | |||
bool IsString() const { return (flags_ & kStringFlag) != 0; } | bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } | |||
bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } | ||||
// Checks whether a number can be losslessly converted to a double. | ||||
bool IsLosslessDouble() const { | ||||
if (!IsNumber()) return false; | ||||
if (IsUint64()) { | ||||
uint64_t u = GetUint64(); | ||||
volatile double d = static_cast<double>(u); | ||||
return (d >= 0.0) | ||||
&& (d < static_cast<double>(std::numeric_limits<uint64_t>::max() | ||||
)) | ||||
&& (u == static_cast<uint64_t>(d)); | ||||
} | ||||
if (IsInt64()) { | ||||
int64_t i = GetInt64(); | ||||
volatile double d = static_cast<double>(i); | ||||
return (d >= static_cast<double>(std::numeric_limits<int64_t>::min() | ||||
)) | ||||
&& (d < static_cast<double>(std::numeric_limits<int64_t>::max()) | ||||
) | ||||
&& (i == static_cast<int64_t>(d)); | ||||
} | ||||
return true; // double, int, uint are always lossless | ||||
} | ||||
// Checks whether a number is a float (possible lossy). | ||||
bool IsFloat() const { | ||||
if ((data_.f.flags & kDoubleFlag) == 0) | ||||
return false; | ||||
double d = GetDouble(); | ||||
return d >= -3.4028234e38 && d <= 3.4028234e38; | ||||
} | ||||
// Checks whether a number can be losslessly converted to a float. | ||||
bool IsLosslessFloat() const { | ||||
if (!IsNumber()) return false; | ||||
double a = GetDouble(); | ||||
if (a < static_cast<double>(-std::numeric_limits<float>::max()) | ||||
|| a > static_cast<double>(std::numeric_limits<float>::max())) | ||||
return false; | ||||
double b = static_cast<double>(static_cast<float>(a)); | ||||
return a >= b && a <= b; // Prevent -Wfloat-equal | ||||
} | ||||
//@} | //@} | |||
//!@name Null | //!@name Null | |||
//@{ | //@{ | |||
GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } | GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } | |||
//@} | //@} | |||
//!@name Bool | //!@name Bool | |||
//@{ | //@{ | |||
bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFla g; } | bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == k TrueFlag; } | |||
//!< Set boolean value | //!< Set boolean value | |||
/*! \post IsBool() == true */ | /*! \post IsBool() == true */ | |||
GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericVal ue(b); return *this; } | GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericVal ue(b); return *this; } | |||
//@} | //@} | |||
//!@name Object | //!@name Object | |||
//@{ | //@{ | |||
//! Set this value as an empty object. | //! Set this value as an empty object. | |||
skipping to change at line 840 | skipping to change at line 1054 | |||
\note Linear time complexity. | \note Linear time complexity. | |||
*/ | */ | |||
template <typename SourceAllocator> | template <typename SourceAllocator> | |||
GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name ) { | 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; | |||
else { | else { | |||
RAPIDJSON_ASSERT(false); // see above note | RAPIDJSON_ASSERT(false); // see above note | |||
static GenericValue NullValue; | ||||
return NullValue; | // This will generate -Wexit-time-destructors in clang | |||
// static GenericValue NullValue; | ||||
// return NullValue; | ||||
// Use static buffer and placement-new to prevent destruction | ||||
static char buffer[sizeof(GenericValue)]; | ||||
return *new (buffer) GenericValue(); | ||||
} | } | |||
} | } | |||
template <typename SourceAllocator> | template <typename SourceAllocator> | |||
const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator> & name) const { return const_cast<GenericValue&>(*this)[name]; } | const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator> & name) const { return const_cast<GenericValue&>(*this)[name]; } | |||
#if RAPIDJSON_HAS_STDSTRING | #if RAPIDJSON_HAS_STDSTRING | |||
//! Get a value from an object associated with name (string object). | //! Get a value from an object associated with name (string object). | |||
GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this) [GenericValue(StringRef(name))]; } | GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this) [GenericValue(StringRef(name))]; } | |||
const GenericValue& operator[](const std::basic_string<Ch>& name) const { re turn (*this)[GenericValue(StringRef(name))]; } | const GenericValue& operator[](const std::basic_string<Ch>& name) const { re turn (*this)[GenericValue(StringRef(name))]; } | |||
#endif | #endif | |||
//! Const member iterator | //! Const member iterator | |||
/*! \pre IsObject() == true */ | /*! \pre IsObject() == true */ | |||
ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); retu rn ConstMemberIterator(data_.o.members); } | ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); retu rn ConstMemberIterator(GetMembersPointer()); } | |||
//! Const \em past-the-end member iterator | //! Const \em past-the-end member iterator | |||
/*! \pre IsObject() == true */ | /*! \pre IsObject() == true */ | |||
ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); retu rn ConstMemberIterator(data_.o.members + data_.o.size); } | ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); retu rn ConstMemberIterator(GetMembersPointer() + data_.o.size); } | |||
//! Member iterator | //! Member iterator | |||
/*! \pre IsObject() == true */ | /*! \pre IsObject() == true */ | |||
MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); retu rn MemberIterator(data_.o.members); } | MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); retu rn MemberIterator(GetMembersPointer()); } | |||
//! \em Past-the-end member iterator | //! \em Past-the-end member iterator | |||
/*! \pre IsObject() == true */ | /*! \pre IsObject() == true */ | |||
MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); retu rn MemberIterator(data_.o.members + data_.o.size); } | MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); retu rn MemberIterator(GetMembersPointer() + data_.o.size); } | |||
//! Check whether a member exists in the object. | //! Check whether a member exists in the object. | |||
/*! | /*! | |||
\param name Member name to be searched. | \param name Member name to be searched. | |||
\pre IsObject() == true | \pre IsObject() == true | |||
\return Whether a member with that name exists. | \return Whether a member with that name exists. | |||
\note It is better to use FindMember() directly if you need the obtain t he value as well. | \note It is better to use FindMember() directly if you need the obtain t he value as well. | |||
\note Linear time complexity. | \note Linear time complexity. | |||
*/ | */ | |||
bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd( ); } | bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd( ); } | |||
skipping to change at line 952 | skipping to change at line 1172 | |||
template <typename SourceAllocator> ConstMemberIterator FindMember(const Gen ericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericVal ue&>(*this).FindMember(name); } | template <typename SourceAllocator> ConstMemberIterator FindMember(const Gen ericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericVal ue&>(*this).FindMember(name); } | |||
#if RAPIDJSON_HAS_STDSTRING | #if RAPIDJSON_HAS_STDSTRING | |||
//! Find member by string object name. | //! Find member by string object name. | |||
/*! | /*! | |||
\param name Member name to be searched. | \param name Member name to be searched. | |||
\pre IsObject() == true | \pre IsObject() == true | |||
\return Iterator to member, if it exists. | \return Iterator to member, if it exists. | |||
Otherwise returns \ref MemberEnd(). | Otherwise returns \ref MemberEnd(). | |||
*/ | */ | |||
MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMe | MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMe | |||
mber(StringRef(name)); } | mber(GenericValue(StringRef(name))); } | |||
ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { re | ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { re | |||
turn FindMember(StringRef(name)); } | turn FindMember(GenericValue(StringRef(name))); } | |||
#endif | #endif | |||
//! 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. | |||
\param value Value of any type. | \param value Value of any type. | |||
\param allocator Allocator for reallocating memory. It must be the sa me one as used before. Commonly use GenericDocument::GetAllocator(). | \param allocator Allocator for reallocating memory. It must be the sa me one as used before. Commonly use GenericDocument::GetAllocator(). | |||
\return The value itself for fluent API. | \return The value itself for fluent API. | |||
\note The ownership of \c name and \c value will be transferred to this object on success. | \note The ownership of \c name and \c value will be transferred to this object on success. | |||
\pre IsObject() && name.IsString() | \pre IsObject() && name.IsString() | |||
\post name.IsNull() && value.IsNull() | \post name.IsNull() && value.IsNull() | |||
\note Amortized Constant time complexity. | \note Amortized Constant time complexity. | |||
*/ | */ | |||
GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { | GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { | |||
RAPIDJSON_ASSERT(IsObject()); | RAPIDJSON_ASSERT(IsObject()); | |||
RAPIDJSON_ASSERT(name.IsString()); | RAPIDJSON_ASSERT(name.IsString()); | |||
Object& o = data_.o; | ObjectData& o = data_.o; | |||
if (o.size >= o.capacity) { | if (o.size >= o.capacity) { | |||
if (o.capacity == 0) { | if (o.capacity == 0) { | |||
o.capacity = kDefaultObjectCapacity; | o.capacity = kDefaultObjectCapacity; | |||
o.members = reinterpret_cast<Member*>(allocator.Malloc(o.capacit y * sizeof(Member))); | SetMembersPointer(reinterpret_cast<Member*>(allocator.Malloc(o.c apacity * sizeof(Member)))); | |||
} | } | |||
else { | else { | |||
SizeType oldCapacity = o.capacity; | SizeType oldCapacity = o.capacity; | |||
o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 | o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 | |||
o.members = reinterpret_cast<Member*>(allocator.Realloc(o.member s, oldCapacity * sizeof(Member), o.capacity * sizeof(Member))); | SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(Ge tMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member)))); | |||
} | } | |||
} | } | |||
o.members[o.size].name.RawAssign(name); | Member* members = GetMembersPointer(); | |||
o.members[o.size].value.RawAssign(value); | members[o.size].name.RawAssign(name); | |||
members[o.size].value.RawAssign(value); | ||||
o.size++; | o.size++; | |||
return *this; | return *this; | |||
} | } | |||
//! Add a constant string value as member (name-value pair) to the object. | //! Add a constant string value as 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. | |||
\param value constant string reference as value of member. | \param value constant string reference as value of member. | |||
\param allocator Allocator for reallocating memory. It must be the sa me one as used before. Commonly use GenericDocument::GetAllocator(). | \param allocator Allocator for reallocating memory. It must be the sa me one as used before. Commonly use GenericDocument::GetAllocator(). | |||
\return The value itself for fluent API. | \return The value itself for fluent API. | |||
\pre IsObject() | \pre IsObject() | |||
skipping to change at line 1161 | skipping to change at line 1382 | |||
/*! \param m member iterator (obtained by FindMember() or MemberBegin()). | /*! \param m member iterator (obtained by FindMember() or MemberBegin()). | |||
\return the new iterator after removal. | \return the new iterator after removal. | |||
\note This function may reorder the object members. Use \ref | \note This function may reorder the object members. Use \ref | |||
EraseMember(ConstMemberIterator) if you need to preserve the | EraseMember(ConstMemberIterator) if you need to preserve the | |||
relative order of the remaining members. | relative order of the remaining members. | |||
\note Constant time complexity. | \note Constant time complexity. | |||
*/ | */ | |||
MemberIterator RemoveMember(MemberIterator m) { | MemberIterator RemoveMember(MemberIterator m) { | |||
RAPIDJSON_ASSERT(IsObject()); | RAPIDJSON_ASSERT(IsObject()); | |||
RAPIDJSON_ASSERT(data_.o.size > 0); | RAPIDJSON_ASSERT(data_.o.size > 0); | |||
RAPIDJSON_ASSERT(data_.o.members != 0); | RAPIDJSON_ASSERT(GetMembersPointer() != 0); | |||
RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); | RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); | |||
MemberIterator last(data_.o.members + (data_.o.size - 1)); | MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); | |||
if (data_.o.size > 1 && m != last) { | if (data_.o.size > 1 && m != last) | |||
// Move the last one to this place | *m = *last; // Move the last one to this place | |||
*m = *last; | else | |||
} | m->~Member(); // Only one left, just destroy | |||
else { | ||||
// Only one left, just destroy | ||||
m->~Member(); | ||||
} | ||||
--data_.o.size; | --data_.o.size; | |||
return m; | return m; | |||
} | } | |||
//! Remove a member from an object by iterator. | //! Remove a member from an object by iterator. | |||
/*! \param pos iterator to the member to remove | /*! \param pos iterator to the member to remove | |||
\pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd () | \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd () | |||
\return Iterator following the removed element. | \return Iterator following the removed element. | |||
If the iterator \c pos refers to the last element, the \ref MemberEn d() iterator is returned. | If the iterator \c pos refers to the last element, the \ref MemberEn d() iterator is returned. | |||
\note This function preserves the relative order of the remaining object | \note This function preserves the relative order of the remaining object | |||
skipping to change at line 1202 | skipping to change at line 1419 | |||
\param last iterator following the last member to remove | \param last iterator following the last member to remove | |||
\pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() | \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() | |||
\return Iterator following the last removed element. | \return Iterator following the last removed element. | |||
\note This function preserves the relative order of the remaining object | \note This function preserves the relative order of the remaining object | |||
members. | members. | |||
\note Linear time complexity. | \note Linear time complexity. | |||
*/ | */ | |||
MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator la st) { | MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator la st) { | |||
RAPIDJSON_ASSERT(IsObject()); | RAPIDJSON_ASSERT(IsObject()); | |||
RAPIDJSON_ASSERT(data_.o.size > 0); | RAPIDJSON_ASSERT(data_.o.size > 0); | |||
RAPIDJSON_ASSERT(data_.o.members != 0); | RAPIDJSON_ASSERT(GetMembersPointer() != 0); | |||
RAPIDJSON_ASSERT(first >= MemberBegin()); | RAPIDJSON_ASSERT(first >= MemberBegin()); | |||
RAPIDJSON_ASSERT(first <= last); | RAPIDJSON_ASSERT(first <= last); | |||
RAPIDJSON_ASSERT(last <= MemberEnd()); | RAPIDJSON_ASSERT(last <= MemberEnd()); | |||
MemberIterator pos = MemberBegin() + (first - MemberBegin()); | MemberIterator pos = MemberBegin() + (first - MemberBegin()); | |||
for (MemberIterator itr = pos; itr != last; ++itr) | for (MemberIterator itr = pos; itr != last; ++itr) | |||
itr->~Member(); | itr->~Member(); | |||
std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member)); | std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * si | |||
data_.o.size -= (last - first); | zeof(Member)); | |||
data_.o.size -= static_cast<SizeType>(last - first); | ||||
return pos; | return pos; | |||
} | } | |||
//! Erase a member in object by its name. | ||||
/*! \param name Name of member to be removed. | ||||
\return Whether the member existed. | ||||
\note Linear time complexity. | ||||
*/ | ||||
bool EraseMember(const Ch* name) { | ||||
GenericValue n(StringRef(name)); | ||||
return EraseMember(n); | ||||
} | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(Gen | ||||
ericValue(StringRef(name))); } | ||||
#endif | ||||
template <typename SourceAllocator> | ||||
bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) { | ||||
MemberIterator m = FindMember(name); | ||||
if (m != MemberEnd()) { | ||||
EraseMember(m); | ||||
return true; | ||||
} | ||||
else | ||||
return false; | ||||
} | ||||
Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } | ||||
ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstOb | ||||
ject(*this); } | ||||
//@} | //@} | |||
//!@name Array | //!@name Array | |||
//@{ | //@{ | |||
//! Set this value as an empty array. | //! Set this value as an empty array. | |||
/*! \post IsArray == true */ | /*! \post IsArray == true */ | |||
GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(k ArrayType); return *this; } | GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kA rrayType); return *this; } | |||
//! Get the number of elements in array. | //! Get the number of elements in array. | |||
SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } | SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } | |||
//! Get the capacity of array. | //! Get the capacity of array. | |||
SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capa city; } | SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capa city; } | |||
//! Check whether the array is empty. | //! Check whether the array is empty. | |||
bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } | bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } | |||
//! Remove all elements in the array. | //! Remove all elements in the array. | |||
/*! This function do not deallocate memory in the array, i.e. the capacity i s unchanged. | /*! This function do not deallocate memory in the array, i.e. the capacity i s unchanged. | |||
\note Linear time complexity. | \note Linear time complexity. | |||
*/ | */ | |||
void Clear() { | void Clear() { | |||
RAPIDJSON_ASSERT(IsArray()); | RAPIDJSON_ASSERT(IsArray()); | |||
for (SizeType i = 0; i < data_.a.size; ++i) | GenericValue* e = GetElementsPointer(); | |||
data_.a.elements[i].~GenericValue(); | for (GenericValue* v = e; v != e + data_.a.size; ++v) | |||
v->~GenericValue(); | ||||
data_.a.size = 0; | data_.a.size = 0; | |||
} | } | |||
//! Get an element from array by index. | //! Get an element from array by index. | |||
/*! \pre IsArray() == true | /*! \pre IsArray() == true | |||
\param index Zero-based index of element. | \param index Zero-based index of element. | |||
\see operator[](T*) | \see operator[](T*) | |||
*/ | */ | |||
GenericValue& operator[](SizeType index) { | GenericValue& operator[](SizeType index) { | |||
RAPIDJSON_ASSERT(IsArray()); | RAPIDJSON_ASSERT(IsArray()); | |||
RAPIDJSON_ASSERT(index < data_.a.size); | RAPIDJSON_ASSERT(index < data_.a.size); | |||
return data_.a.elements[index]; | return GetElementsPointer()[index]; | |||
} | } | |||
const GenericValue& operator[](SizeType index) const { return const_cast<Gen ericValue&>(*this)[index]; } | const GenericValue& operator[](SizeType index) const { return const_cast<Gen ericValue&>(*this)[index]; } | |||
//! Element iterator | //! Element iterator | |||
/*! \pre IsArray() == true */ | /*! \pre IsArray() == true */ | |||
ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements ; } | ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPoint er(); } | |||
//! \em Past-the-end element iterator | //! \em Past-the-end element iterator | |||
/*! \pre IsArray() == true */ | /*! \pre IsArray() == true */ | |||
ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; } | ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer () + data_.a.size; } | |||
//! Constant element iterator | //! Constant element iterator | |||
/*! \pre IsArray() == true */ | /*! \pre IsArray() == true */ | |||
ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).B egin(); } | ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).B egin(); } | |||
//! Constant \em past-the-end element iterator | //! Constant \em past-the-end element iterator | |||
/*! \pre IsArray() == true */ | /*! \pre IsArray() == true */ | |||
ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End (); } | ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End (); } | |||
//! Request the array to have enough capacity to store elements. | //! Request the array to have enough capacity to store elements. | |||
/*! \param newCapacity The capacity that the array at least need to have. | /*! \param newCapacity The capacity that the array at least need to have. | |||
\param allocator Allocator for reallocating memory. It must be the sa me one as used before. Commonly use GenericDocument::GetAllocator(). | \param allocator Allocator for reallocating memory. It must be the sa me one as used before. Commonly use GenericDocument::GetAllocator(). | |||
\return The value itself for fluent API. | \return The value itself for fluent API. | |||
\note Linear time complexity. | \note Linear time complexity. | |||
*/ | */ | |||
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { | GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { | |||
RAPIDJSON_ASSERT(IsArray()); | RAPIDJSON_ASSERT(IsArray()); | |||
if (newCapacity > data_.a.capacity) { | if (newCapacity > data_.a.capacity) { | |||
data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements , data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)); | SetElementsPointer(reinterpret_cast<GenericValue*>(allocator.Realloc (GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * si zeof(GenericValue)))); | |||
data_.a.capacity = newCapacity; | data_.a.capacity = newCapacity; | |||
} | } | |||
return *this; | return *this; | |||
} | } | |||
//! Append a GenericValue at the end of the array. | //! Append a GenericValue at the end of the array. | |||
/*! \param value Value to be appended. | /*! \param value Value to be appended. | |||
\param allocator Allocator for reallocating memory. It must be the sa me one as used before. Commonly use GenericDocument::GetAllocator(). | \param allocator Allocator for reallocating memory. It must be the sa me one as used before. Commonly use GenericDocument::GetAllocator(). | |||
\pre IsArray() == true | \pre IsArray() == true | |||
\post value.IsNull() == true | \post value.IsNull() == true | |||
\return The value itself for fluent API. | \return The value itself for fluent API. | |||
\note The ownership of \c value will be transferred to this array on suc cess. | \note The ownership of \c value will be transferred to this array on suc cess. | |||
\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. | \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. | |||
\note Amortized constant time complexity. | \note Amortized constant time complexity. | |||
*/ | */ | |||
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.cap acity + (data_.a.capacity + 1) / 2), allocator); | Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.cap acity + (data_.a.capacity + 1) / 2), allocator); | |||
data_.a.elements[data_.a.size++].RawAssign(value); | GetElementsPointer()[data_.a.size++].RawAssign(value); | |||
return *this; | return *this; | |||
} | } | |||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS | |||
GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { | GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { | |||
return PushBack(value, allocator); | return PushBack(value, allocator); | |||
} | } | |||
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS | #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. | |||
skipping to change at line 1352 | skipping to change at line 1598 | |||
return PushBack(v, allocator); | return PushBack(v, allocator); | |||
} | } | |||
//! Remove the last element in the array. | //! Remove the last element in the array. | |||
/*! | /*! | |||
\note Constant time complexity. | \note Constant time complexity. | |||
*/ | */ | |||
GenericValue& PopBack() { | GenericValue& PopBack() { | |||
RAPIDJSON_ASSERT(IsArray()); | RAPIDJSON_ASSERT(IsArray()); | |||
RAPIDJSON_ASSERT(!Empty()); | RAPIDJSON_ASSERT(!Empty()); | |||
data_.a.elements[--data_.a.size].~GenericValue(); | GetElementsPointer()[--data_.a.size].~GenericValue(); | |||
return *this; | return *this; | |||
} | } | |||
//! Remove an element of array by iterator. | //! Remove an element of array by iterator. | |||
/*! | /*! | |||
\param pos iterator to the element to remove | \param pos iterator to the element to remove | |||
\pre IsArray() == true && \ref Begin() <= \c pos < \ref End() | \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() | |||
\return Iterator following the removed element. If the iterator pos refe rs to the last element, the End() iterator is returned. | \return Iterator following the removed element. If the iterator pos refe rs to the last element, the End() iterator is returned. | |||
\note Linear time complexity. | \note Linear time complexity. | |||
*/ | */ | |||
skipping to change at line 1378 | skipping to change at line 1624 | |||
/*! | /*! | |||
\param first iterator to the first element to remove | \param first iterator to the first element to remove | |||
\param last iterator following the last element to remove | \param last iterator following the last element to remove | |||
\pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref En d() | \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref En d() | |||
\return Iterator following the last removed element. | \return Iterator following the last removed element. | |||
\note Linear time complexity. | \note Linear time complexity. | |||
*/ | */ | |||
ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { | ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { | |||
RAPIDJSON_ASSERT(IsArray()); | RAPIDJSON_ASSERT(IsArray()); | |||
RAPIDJSON_ASSERT(data_.a.size > 0); | RAPIDJSON_ASSERT(data_.a.size > 0); | |||
RAPIDJSON_ASSERT(data_.a.elements != 0); | RAPIDJSON_ASSERT(GetElementsPointer() != 0); | |||
RAPIDJSON_ASSERT(first >= Begin()); | RAPIDJSON_ASSERT(first >= Begin()); | |||
RAPIDJSON_ASSERT(first <= last); | RAPIDJSON_ASSERT(first <= last); | |||
RAPIDJSON_ASSERT(last <= End()); | RAPIDJSON_ASSERT(last <= End()); | |||
ValueIterator pos = Begin() + (first - Begin()); | ValueIterator pos = Begin() + (first - Begin()); | |||
for (ValueIterator itr = pos; itr != last; ++itr) | for (ValueIterator itr = pos; itr != last; ++itr) | |||
itr->~GenericValue(); | itr->~GenericValue(); | |||
std::memmove(pos, last, (End() - last) * sizeof(GenericValue)); | std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(Gener | |||
data_.a.size -= (last - first); | icValue)); | |||
data_.a.size -= static_cast<SizeType>(last - first); | ||||
return pos; | return pos; | |||
} | } | |||
Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } | ||||
ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray | ||||
(*this); } | ||||
//@} | //@} | |||
//!@name Number | //!@name Number | |||
//@{ | //@{ | |||
int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return | int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); | |||
data_.n.i.i; } | return data_.n.i.i; } | |||
unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return | unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); | |||
data_.n.u.u; } | return data_.n.u.u; } | |||
int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return | int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); | |||
data_.n.i64; } | return data_.n.i64; } | |||
uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return | uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); | |||
data_.n.u64; } | return data_.n.u64; } | |||
//! Get the value as double type. | ||||
/*! \note If the value is 64-bit integer type, it may lose precision. Use \c | ||||
IsLosslessDouble() to check whether the converison is lossless. | ||||
*/ | ||||
double GetDouble() const { | double GetDouble() const { | |||
RAPIDJSON_ASSERT(IsNumber()); | RAPIDJSON_ASSERT(IsNumber()); | |||
if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // e | if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; | |||
xact type, no conversion. | // exact type, no conversion. | |||
if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // i | if ((data_.f.flags & kIntFlag) != 0) return data_.n.i. | |||
nt -> double | i; // int -> double | |||
if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // u | if ((data_.f.flags & kUintFlag) != 0) return data_.n.u. | |||
nsigned -> double | u; // unsigned -> double | |||
if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i | if ((data_.f.flags & kInt64Flag) != 0) return static_cas | |||
64; // int64_t -> double (may lose precision) | t<double>(data_.n.i64); // int64_t -> double (may lose precision) | |||
RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u | RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cas | |||
64; // uint64_t -> double (may lose precision) | t<double>(data_.n.u64); // uint64_t -> double (may lose precision) | |||
} | ||||
//! Get the value as float type. | ||||
/*! \note If the value is 64-bit integer type, it may lose precision. Use \c | ||||
IsLosslessFloat() to check whether the converison is lossless. | ||||
*/ | ||||
float GetFloat() const { | ||||
return static_cast<float>(GetDouble()); | ||||
} | } | |||
GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } | GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } | |||
GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } | GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } | |||
GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } | GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } | |||
GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } | GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } | |||
GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } | GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } | |||
GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; } | ||||
//@} | //@} | |||
//!@name String | //!@name String | |||
//@{ | //@{ | |||
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? data_.ss.str : data_.s.str); } | const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f. flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } | |||
//! Get the length of string. | //! Get the length of string. | |||
/*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString ()) may not equal to v.GetStringLength(). | /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString ()) may not equal to v.GetStringLength(). | |||
*/ | */ | |||
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((fl ags_ & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } | SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((da ta_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } | |||
//! Set this value as a string without copying source string. | //! Set this value as a string without copying source string. | |||
/*! This version has better performance with supplied length, and also suppo rt string containing null character. | /*! This version has better performance with supplied length, and also suppo rt string containing null character. | |||
\param s source string pointer. | \param s source string pointer. | |||
\param length The length of source string, excluding the trailing null t erminator. | \param length The length of source string, excluding the trailing null t erminator. | |||
\return The value itself for fluent API. | \return The value itself for fluent API. | |||
\post IsString() == true && GetString() == s && GetStringLength() == len gth | \post IsString() == true && GetString() == s && GetStringLength() == len gth | |||
\see SetString(StringRefType) | \see SetString(StringRefType) | |||
*/ | */ | |||
GenericValue& SetString(const Ch* s, SizeType length) { return SetString(Str ingRef(s, length)); } | GenericValue& SetString(const Ch* s, SizeType length) { return SetString(Str ingRef(s, length)); } | |||
skipping to change at line 1475 | skipping to change at line 1735 | |||
\param allocator Allocator for allocating copied buffer. Commonly use Ge nericDocument::GetAllocator(). | \param allocator Allocator for allocating copied buffer. Commonly use Ge nericDocument::GetAllocator(). | |||
\return The value itself for fluent API. | \return The value itself for fluent API. | |||
\post IsString() == true && GetString() != s.data() && strcmp(GetString( ),s.data() == 0 && GetStringLength() == s.size() | \post IsString() == true && GetString() != s.data() && strcmp(GetString( ),s.data() == 0 && GetStringLength() == s.size() | |||
\note Requires the definition of the preprocessor symbol \ref RAPIDJSON_ HAS_STDSTRING. | \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_ HAS_STDSTRING. | |||
*/ | */ | |||
GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator ) { return SetString(s.data(), SizeType(s.size()), allocator); } | GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator ) { return SetString(s.data(), SizeType(s.size()), allocator); } | |||
#endif | #endif | |||
//@} | //@} | |||
//!@name Array | ||||
//@{ | ||||
//! Templated version for checking whether this value is type T. | ||||
/*! | ||||
\tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, | ||||
\c double, \c float, \c const \c char*, \c std::basic_string<Ch> | ||||
*/ | ||||
template <typename T> | ||||
bool Is() const { return internal::TypeHelper<ValueType, T>::Is(*this); } | ||||
template <typename T> | ||||
T Get() const { return internal::TypeHelper<ValueType, T>::Get(*this); } | ||||
template <typename T> | ||||
T Get() { return internal::TypeHelper<ValueType, T>::Get(*this); } | ||||
template<typename T> | ||||
ValueType& Set(const T& data) { return internal::TypeHelper<ValueType, T>::S | ||||
et(*this, data); } | ||||
template<typename T> | ||||
ValueType& Set(const T& data, AllocatorType& allocator) { return internal::T | ||||
ypeHelper<ValueType, T>::Set(*this, data, allocator); } | ||||
//@} | ||||
//! Generate events of this value to a Handler. | //! Generate events of this value to a Handler. | |||
/*! This function adopts the GoF visitor pattern. | /*! This function adopts the GoF visitor pattern. | |||
Typical usage is to output this JSON value as JSON text via Writer, whic h is a Handler. | Typical usage is to output this JSON value as JSON text via Writer, whic h is a Handler. | |||
It can also be used to deep clone this value via GenericDocument, which is also a Handler. | It can also be used to deep clone this value via GenericDocument, which is also a Handler. | |||
\tparam Handler type of handler. | \tparam Handler type of handler. | |||
\param handler An object implementing concept Handler. | \param handler An object implementing concept Handler. | |||
*/ | */ | |||
template <typename Handler> | template <typename Handler> | |||
bool Accept(Handler& handler) const { | bool Accept(Handler& handler) const { | |||
switch(GetType()) { | switch(GetType()) { | |||
case kNullType: return handler.Null(); | case kNullType: return handler.Null(); | |||
case kFalseType: return handler.Bool(false); | case kFalseType: return handler.Bool(false); | |||
case kTrueType: return handler.Bool(true); | case kTrueType: return handler.Bool(true); | |||
case kObjectType: | case kObjectType: | |||
if (!handler.StartObject()) | if (RAPIDJSON_UNLIKELY(!handler.StartObject())) | |||
return false; | return false; | |||
for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { | for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { | |||
RAPIDJSON_ASSERT(m->name.IsString()); // User may change the typ e of name by MemberIterator. | RAPIDJSON_ASSERT(m->name.IsString()); // User may change the typ e of name by MemberIterator. | |||
if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0)) | if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name .GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) | |||
return false; | return false; | |||
if (!m->value.Accept(handler)) | if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) | |||
return false; | return false; | |||
} | } | |||
return handler.EndObject(data_.o.size); | return handler.EndObject(data_.o.size); | |||
case kArrayType: | case kArrayType: | |||
if (!handler.StartArray()) | if (RAPIDJSON_UNLIKELY(!handler.StartArray())) | |||
return false; | return false; | |||
for (GenericValue* v = data_.a.elements; v != data_.a.elements + dat | for (const GenericValue* v = Begin(); v != End(); ++v) | |||
a_.a.size; ++v) | if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) | |||
if (!v->Accept(handler)) | ||||
return false; | return false; | |||
return handler.EndArray(data_.a.size); | return handler.EndArray(data_.a.size); | |||
case kStringType: | case kStringType: | |||
return handler.String(GetString(), GetStringLength(), (flags_ & kCop yFlag) != 0); | return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); | |||
default: | default: | |||
RAPIDJSON_ASSERT(GetType() == kNumberType); | RAPIDJSON_ASSERT(GetType() == kNumberType); | |||
if (IsInt()) return handler.Int(data_.n.i.i); | if (IsDouble()) return handler.Double(data_.n.d); | |||
else if (IsInt()) return handler.Int(data_.n.i.i); | ||||
else if (IsUint()) return handler.Uint(data_.n.u.u); | else if (IsUint()) return handler.Uint(data_.n.u.u); | |||
else if (IsInt64()) return handler.Int64(data_.n.i64); | else if (IsInt64()) return handler.Int64(data_.n.i64); | |||
else if (IsUint64()) return handler.Uint64(data_.n.u64); | else return handler.Uint64(data_.n.u64); | |||
else return handler.Double(data_.n.d); | ||||
} | } | |||
} | } | |||
private: | private: | |||
template <typename, typename> friend class GenericValue; | template <typename, typename> friend class GenericValue; | |||
template <typename, typename, typename> friend class GenericDocument; | template <typename, typename, typename> friend class GenericDocument; | |||
enum { | enum { | |||
kBoolFlag = 0x100, | kBoolFlag = 0x0008, | |||
kNumberFlag = 0x200, | kNumberFlag = 0x0010, | |||
kIntFlag = 0x400, | kIntFlag = 0x0020, | |||
kUintFlag = 0x800, | kUintFlag = 0x0040, | |||
kInt64Flag = 0x1000, | kInt64Flag = 0x0080, | |||
kUint64Flag = 0x2000, | kUint64Flag = 0x0100, | |||
kDoubleFlag = 0x4000, | kDoubleFlag = 0x0200, | |||
kStringFlag = 0x100000, | kStringFlag = 0x0400, | |||
kCopyFlag = 0x200000, | kCopyFlag = 0x0800, | |||
kInlineStrFlag = 0x400000, | kInlineStrFlag = 0x1000, | |||
// Initial flags of different types. | // Initial flags of different types. | |||
kNullFlag = kNullType, | kNullFlag = kNullType, | |||
kTrueFlag = kTrueType | kBoolFlag, | kTrueFlag = kTrueType | kBoolFlag, | |||
kFalseFlag = kFalseType | kBoolFlag, | kFalseFlag = kFalseType | kBoolFlag, | |||
kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, | kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, | |||
kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, | kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, | |||
kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, | kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, | |||
kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, | kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, | |||
kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, | kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, | |||
kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUi ntFlag | kUint64Flag | kDoubleFlag, | kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUi ntFlag | kUint64Flag | kDoubleFlag, | |||
kConstStringFlag = kStringType | kStringFlag, | kConstStringFlag = kStringType | kStringFlag, | |||
kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, | kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, | |||
kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFla g, | kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFla g, | |||
kObjectFlag = kObjectType, | kObjectFlag = kObjectType, | |||
kArrayFlag = kArrayType, | kArrayFlag = kArrayType, | |||
kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler | kTypeMask = 0x07 | |||
}; | }; | |||
static const SizeType kDefaultArrayCapacity = 16; | static const SizeType kDefaultArrayCapacity = 16; | |||
static const SizeType kDefaultObjectCapacity = 16; | static const SizeType kDefaultObjectCapacity = 16; | |||
struct Flag { | ||||
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION | ||||
char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-b | ||||
it pointer | ||||
#elif RAPIDJSON_64BIT | ||||
char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding byt | ||||
es | ||||
#else | ||||
char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding byt | ||||
es | ||||
#endif | ||||
uint16_t flags; | ||||
}; | ||||
struct String { | struct String { | |||
const Ch* str; | ||||
SizeType length; | SizeType length; | |||
unsigned hashcode; //!< reserved | SizeType hashcode; //!< reserved | |||
const Ch* str; | ||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode | }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode | |||
// implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars | // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars | |||
// (excluding the terminating zero) and store a value to determine the lengt h of the contained | // (excluding the terminating zero) and store a value to determine the lengt h of the contained | |||
// string in the last character str[LenPos] by storing "MaxSize - length" th ere. If the string | // string in the last character str[LenPos] by storing "MaxSize - length" th ere. If the string | |||
// to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as | // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as | |||
// the string terminator as well. For getting the string length back from th at value just use | // the string terminator as well. For getting the string length back from th at value just use | |||
// "MaxSize - str[LenPos]". | // "MaxSize - str[LenPos]". | |||
// This allows to store 11-chars strings in 32-bit mode and 15-chars strings | // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in | |||
in 64-bit mode | 64-bit mode, | |||
// inline (for `UTF8`-encoded strings). | // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `U | |||
TF8`-encoded strings). | ||||
struct ShortString { | struct ShortString { | |||
enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, L enPos = MaxSize }; | enum { MaxChars = sizeof(static_cast<Flag*>(0)->payload) / sizeof(Ch), M axSize = MaxChars - 1, LenPos = MaxSize }; | |||
Ch str[MaxChars]; | Ch str[MaxChars]; | |||
inline static bool Usable(SizeType len) { return (MaxSize >= | inline static bool Usable(SizeType len) { return ( | |||
len); } | MaxSize >= len); } | |||
inline void SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - | inline void SetLength(SizeType len) { str[LenPos] = static_cast<Ch>( | |||
len); } | MaxSize - len); } | |||
inline SizeType GetLength() const { return (SizeType)(MaxSize - | inline SizeType GetLength() const { return static_cast<SizeType>( | |||
str[LenPos]); } | MaxSize - str[LenPos]); } | |||
}; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 1 6 bytes in 64-bit mode | }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 1 6 bytes in 64-bit mode | |||
// By using proper binary layout, retrieval of different integer types do no t need conversions. | // By using proper binary layout, retrieval of different integer types do no t need conversions. | |||
union Number { | union Number { | |||
#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN | #if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN | |||
struct I { | struct I { | |||
int i; | int i; | |||
char padding[4]; | char padding[4]; | |||
}i; | }i; | |||
struct U { | struct U { | |||
skipping to change at line 1609 | skipping to change at line 1904 | |||
struct U { | struct U { | |||
char padding2[4]; | char padding2[4]; | |||
unsigned u; | unsigned u; | |||
}u; | }u; | |||
#endif | #endif | |||
int64_t i64; | int64_t i64; | |||
uint64_t u64; | uint64_t u64; | |||
double d; | double d; | |||
}; // 8 bytes | }; // 8 bytes | |||
struct Object { | struct ObjectData { | |||
Member* members; | ||||
SizeType size; | SizeType size; | |||
SizeType capacity; | SizeType capacity; | |||
Member* members; | ||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode | }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode | |||
struct Array { | struct ArrayData { | |||
GenericValue* elements; | ||||
SizeType size; | SizeType size; | |||
SizeType capacity; | SizeType capacity; | |||
GenericValue* elements; | ||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode | }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode | |||
union Data { | union Data { | |||
String s; | String s; | |||
ShortString ss; | ShortString ss; | |||
Number n; | Number n; | |||
Object o; | ObjectData o; | |||
Array a; | ArrayData a; | |||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode | Flag f; | |||
}; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit | ||||
with RAPIDJSON_48BITPOINTER_OPTIMIZATION | ||||
RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_ | ||||
GETPOINTER(Ch, data_.s.str); } | ||||
RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAP | ||||
IDJSON_SETPOINTER(Ch, data_.s.str, str); } | ||||
RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPI | ||||
DJSON_GETPOINTER(GenericValue, data_.a.elements); } | ||||
RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* element | ||||
s) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } | ||||
RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_G | ||||
ETPOINTER(Member, data_.o.members); } | ||||
RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RA | ||||
PIDJSON_SETPOINTER(Member, data_.o.members, members); } | ||||
// Initialize this value as array with initial data, without calling destruc tor. | // Initialize this value as array with initial data, without calling destruc tor. | |||
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { | void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { | |||
flags_ = kArrayFlag; | data_.f.flags = kArrayFlag; | |||
if (count) { | if (count) { | |||
data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(Ge | GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count | |||
nericValue)); | * sizeof(GenericValue))); | |||
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue)); | SetElementsPointer(e); | |||
std::memcpy(e, values, count * sizeof(GenericValue)); | ||||
} | } | |||
else | else | |||
data_.a.elements = NULL; | SetElementsPointer(0); | |||
data_.a.size = data_.a.capacity = count; | data_.a.size = data_.a.capacity = count; | |||
} | } | |||
//! Initialize this value as object with initial data, without calling destr uctor. | //! Initialize this value as object with initial data, without calling destr uctor. | |||
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { | void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { | |||
flags_ = kObjectFlag; | data_.f.flags = kObjectFlag; | |||
if (count) { | if (count) { | |||
data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member)); | Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Mem | |||
std::memcpy(data_.o.members, members, count * sizeof(Member)); | ber))); | |||
SetMembersPointer(m); | ||||
std::memcpy(m, members, count * sizeof(Member)); | ||||
} | } | |||
else | else | |||
data_.o.members = NULL; | SetMembersPointer(0); | |||
data_.o.size = data_.o.capacity = count; | data_.o.size = data_.o.capacity = count; | |||
} | } | |||
//! Initialize this value as constant string, without calling destructor. | //! Initialize this value as constant string, without calling destructor. | |||
void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { | void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { | |||
flags_ = kConstStringFlag; | data_.f.flags = kConstStringFlag; | |||
data_.s.str = s; | SetStringPointer(s); | |||
data_.s.length = s.length; | data_.s.length = s.length; | |||
} | } | |||
//! Initialize this value as copy string with initial data, without calling destructor. | //! Initialize this value as copy string with initial data, without calling destructor. | |||
void SetStringRaw(StringRefType s, Allocator& allocator) { | void SetStringRaw(StringRefType s, Allocator& allocator) { | |||
Ch* str = NULL; | Ch* str = 0; | |||
if(ShortString::Usable(s.length)) { | if (ShortString::Usable(s.length)) { | |||
flags_ = kShortStringFlag; | data_.f.flags = kShortStringFlag; | |||
data_.ss.SetLength(s.length); | data_.ss.SetLength(s.length); | |||
str = data_.ss.str; | str = data_.ss.str; | |||
} else { | } else { | |||
flags_ = kCopyStringFlag; | data_.f.flags = kCopyStringFlag; | |||
data_.s.length = s.length; | data_.s.length = s.length; | |||
str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch)); | str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch) | |||
data_.s.str = str; | )); | |||
SetStringPointer(str); | ||||
} | } | |||
std::memcpy(str, s, s.length * sizeof(Ch)); | std::memcpy(str, s, s.length * sizeof(Ch)); | |||
str[s.length] = '\0'; | str[s.length] = '\0'; | |||
} | } | |||
//! Assignment without calling destructor | //! Assignment without calling destructor | |||
void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { | void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { | |||
data_ = rhs.data_; | data_ = rhs.data_; | |||
flags_ = rhs.flags_; | // data_.f.flags = rhs.data_.f.flags; | |||
rhs.flags_ = kNullFlag; | rhs.data_.f.flags = kNullFlag; | |||
} | } | |||
template <typename SourceAllocator> | template <typename SourceAllocator> | |||
bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const { | bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const { | |||
RAPIDJSON_ASSERT(IsString()); | RAPIDJSON_ASSERT(IsString()); | |||
RAPIDJSON_ASSERT(rhs.IsString()); | RAPIDJSON_ASSERT(rhs.IsString()); | |||
const SizeType len1 = GetStringLength(); | const SizeType len1 = GetStringLength(); | |||
const SizeType len2 = rhs.GetStringLength(); | const SizeType len2 = rhs.GetStringLength(); | |||
if(len1 != len2) { return false; } | if(len1 != len2) { return false; } | |||
const Ch* const str1 = GetString(); | const Ch* const str1 = GetString(); | |||
const Ch* const str2 = rhs.GetString(); | const Ch* const str2 = rhs.GetString(); | |||
if(str1 == str2) { return true; } // fast path for constant string | if(str1 == str2) { return true; } // fast path for constant string | |||
return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); | return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); | |||
} | } | |||
Data data_; | Data data_; | |||
unsigned flags_; | ||||
}; | }; | |||
//! GenericValue with UTF8 encoding | //! GenericValue with UTF8 encoding | |||
typedef GenericValue<UTF8<> > Value; | typedef GenericValue<UTF8<> > Value; | |||
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | |||
// GenericDocument | // GenericDocument | |||
//! A document for parsing JSON text as DOM. | //! A document for parsing JSON text as DOM. | |||
/*! | /*! | |||
skipping to change at line 1726 | skipping to change at line 2030 | |||
\warning Although GenericDocument inherits from GenericValue, the API does \ b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a Gene ricValue. | \warning Although GenericDocument inherits from GenericValue, the API does \ b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a Gene ricValue. | |||
*/ | */ | |||
template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typenam e StackAllocator = CrtAllocator> | template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typenam e StackAllocator = CrtAllocator> | |||
class GenericDocument : public GenericValue<Encoding, Allocator> { | class GenericDocument : public GenericValue<Encoding, Allocator> { | |||
public: | public: | |||
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. | typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. | |||
typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of t he document. | typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of t he document. | |||
typedef Allocator AllocatorType; //!< Allocator type from template parameter. | typedef Allocator AllocatorType; //!< Allocator type from template parameter. | |||
//! Constructor | //! Constructor | |||
/*! \param allocator Optional allocator for allocating memory. | /*! Creates an empty document of specified type. | |||
\param type Mandatory type of object to create. | ||||
\param allocator Optional allocator for allocating memory. | ||||
\param stackCapacity Optional initial capacity of stack in bytes. | ||||
\param stackAllocator Optional allocator for allocating memory for sta | ||||
ck. | ||||
*/ | ||||
explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCa | ||||
pacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : | ||||
GenericValue<Encoding, Allocator>(type), allocator_(allocator), ownAllo | ||||
cator_(0), stack_(stackAllocator, stackCapacity), parseResult_() | ||||
{ | ||||
if (!allocator_) | ||||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); | ||||
} | ||||
//! Constructor | ||||
/*! Creates an empty document which type is Null. | ||||
\param allocator Optional allocator for allocating memory. | ||||
\param stackCapacity Optional initial capacity of stack in bytes. | \param stackCapacity Optional initial capacity of stack in bytes. | |||
\param stackAllocator Optional allocator for allocating memory for sta ck. | \param stackAllocator Optional allocator for allocating memory for sta ck. | |||
*/ | */ | |||
GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultSta ckCapacity, StackAllocator* stackAllocator = 0) : | GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultSta ckCapacity, StackAllocator* stackAllocator = 0) : | |||
allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCap acity), parseResult_() | allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCap acity), parseResult_() | |||
{ | { | |||
if (!allocator_) | if (!allocator_) | |||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); | ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); | |||
} | } | |||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS | |||
//! Move constructor in C++11 | //! Move constructor in C++11 | |||
GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT | GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT | |||
: ValueType(std::move(rhs)), | : ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid pro hibited move from Document | |||
allocator_(rhs.allocator_), | allocator_(rhs.allocator_), | |||
ownAllocator_(rhs.ownAllocator_), | ownAllocator_(rhs.ownAllocator_), | |||
stack_(std::move(rhs.stack_)), | stack_(std::move(rhs.stack_)), | |||
parseResult_(rhs.parseResult_) | parseResult_(rhs.parseResult_) | |||
{ | { | |||
rhs.allocator_ = 0; | rhs.allocator_ = 0; | |||
rhs.ownAllocator_ = 0; | rhs.ownAllocator_ = 0; | |||
rhs.parseResult_ = ParseResult(); | rhs.parseResult_ = ParseResult(); | |||
} | } | |||
#endif | #endif | |||
skipping to change at line 1780 | skipping to change at line 2099 | |||
parseResult_ = rhs.parseResult_; | parseResult_ = rhs.parseResult_; | |||
rhs.allocator_ = 0; | rhs.allocator_ = 0; | |||
rhs.ownAllocator_ = 0; | rhs.ownAllocator_ = 0; | |||
rhs.parseResult_ = ParseResult(); | rhs.parseResult_ = ParseResult(); | |||
return *this; | return *this; | |||
} | } | |||
#endif | #endif | |||
//! Exchange the contents of this document with those of another. | ||||
/*! | ||||
\param rhs Another document. | ||||
\note Constant complexity. | ||||
\see GenericValue::Swap | ||||
*/ | ||||
GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { | ||||
ValueType::Swap(rhs); | ||||
stack_.Swap(rhs.stack_); | ||||
internal::Swap(allocator_, rhs.allocator_); | ||||
internal::Swap(ownAllocator_, rhs.ownAllocator_); | ||||
internal::Swap(parseResult_, rhs.parseResult_); | ||||
return *this; | ||||
} | ||||
//! free-standing swap function helper | ||||
/*! | ||||
Helper function to enable support for common swap implementation pattern | ||||
based on \c std::swap: | ||||
\code | ||||
void swap(MyClass& a, MyClass& b) { | ||||
using std::swap; | ||||
swap(a.doc, b.doc); | ||||
// ... | ||||
} | ||||
\endcode | ||||
\see Swap() | ||||
*/ | ||||
friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NO | ||||
EXCEPT { a.Swap(b); } | ||||
//! Populate this document by a generator which produces SAX events. | ||||
/*! \tparam Generator A functor with <tt>bool f(Handler)</tt> prototype. | ||||
\param g Generator functor which sends SAX events to the parameter. | ||||
\return The document itself for fluent API. | ||||
*/ | ||||
template <typename Generator> | ||||
GenericDocument& Populate(Generator& g) { | ||||
ClearStackOnExit scope(*this); | ||||
if (g(*this)) { | ||||
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one | ||||
and only one root object | ||||
ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move val | ||||
ue from stack to document | ||||
} | ||||
return *this; | ||||
} | ||||
//!@name Parse from stream | //!@name Parse from stream | |||
//!@{ | //!@{ | |||
//! Parse JSON text from an input stream (with Encoding conversion) | //! Parse JSON text from an input stream (with Encoding conversion) | |||
/*! \tparam parseFlags Combination of \ref ParseFlag. | /*! \tparam parseFlags Combination of \ref ParseFlag. | |||
\tparam SourceEncoding Encoding of input stream | \tparam SourceEncoding Encoding of input stream | |||
\tparam InputStream Type of input stream, implementing Stream concept | \tparam InputStream Type of input stream, implementing Stream concept | |||
\param is Input stream to be parsed. | \param is Input stream to be parsed. | |||
\return The document itself for fluent API. | \return The document itself for fluent API. | |||
*/ | */ | |||
template <unsigned parseFlags, typename SourceEncoding, typename InputStream > | template <unsigned parseFlags, typename SourceEncoding, typename InputStream > | |||
GenericDocument& ParseStream(InputStream& is) { | GenericDocument& ParseStream(InputStream& is) { | |||
ValueType::SetNull(); // Remove existing root if exist | GenericReader<SourceEncoding, Encoding, StackAllocator> reader( | |||
GenericReader<SourceEncoding, Encoding, StackAllocator> reader(&stack_.G | stack_.HasAllocator() ? &stack_.GetAllocator() : 0); | |||
etAllocator()); | ||||
ClearStackOnExit scope(*this); | ClearStackOnExit scope(*this); | |||
parseResult_ = reader.template Parse<parseFlags>(is, *this); | parseResult_ = reader.template Parse<parseFlags>(is, *this); | |||
if (parseResult_) { | if (parseResult_) { | |||
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object | RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object | |||
this->RawAssign(*stack_.template Pop<ValueType>(1)); // Add this- > to prevent issue 13. | ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move val ue from stack to document | |||
} | } | |||
return *this; | return *this; | |||
} | } | |||
//! Parse JSON text from an input stream | //! Parse JSON text from an input stream | |||
/*! \tparam parseFlags Combination of \ref ParseFlag. | /*! \tparam parseFlags Combination of \ref ParseFlag. | |||
\tparam InputStream Type of input stream, implementing Stream concept | \tparam InputStream Type of input stream, implementing Stream concept | |||
\param is Input stream to be parsed. | \param is Input stream to be parsed. | |||
\return The document itself for fluent API. | \return The document itself for fluent API. | |||
*/ | */ | |||
skipping to change at line 1857 | skipping to change at line 2220 | |||
//!@name Parse from read-only string | //!@name Parse from read-only string | |||
//!@{ | //!@{ | |||
//! Parse JSON text from a read-only string (with Encoding conversion) | //! Parse JSON text from a read-only string (with Encoding conversion) | |||
/*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). | /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). | |||
\tparam SourceEncoding Transcoding from input Encoding | \tparam SourceEncoding Transcoding from input Encoding | |||
\param str Read-only zero-terminated string to be parsed. | \param str Read-only zero-terminated string to be parsed. | |||
*/ | */ | |||
template <unsigned parseFlags, typename SourceEncoding> | template <unsigned parseFlags, typename SourceEncoding> | |||
GenericDocument& Parse(const Ch* str) { | GenericDocument& Parse(const typename SourceEncoding::Ch* str) { | |||
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); | RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); | |||
GenericStringStream<SourceEncoding> s(str); | GenericStringStream<SourceEncoding> s(str); | |||
return ParseStream<parseFlags, SourceEncoding>(s); | return ParseStream<parseFlags, SourceEncoding>(s); | |||
} | } | |||
//! Parse JSON text from a read-only string | //! Parse JSON text from a read-only string | |||
/*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). | /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). | |||
\param str Read-only zero-terminated string to be parsed. | \param str Read-only zero-terminated string to be parsed. | |||
*/ | */ | |||
template <unsigned parseFlags> | template <unsigned parseFlags> | |||
GenericDocument& Parse(const Ch* str) { | GenericDocument& Parse(const Ch* str) { | |||
return Parse<parseFlags, Encoding>(str); | return Parse<parseFlags, Encoding>(str); | |||
} | } | |||
//! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) | //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) | |||
/*! \param str Read-only zero-terminated string to be parsed. | /*! \param str Read-only zero-terminated string to be parsed. | |||
*/ | */ | |||
GenericDocument& Parse(const Ch* str) { | GenericDocument& Parse(const Ch* str) { | |||
return Parse<kParseDefaultFlags>(str); | return Parse<kParseDefaultFlags>(str); | |||
} | } | |||
template <unsigned parseFlags, typename SourceEncoding> | ||||
GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length | ||||
) { | ||||
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); | ||||
MemoryStream ms(static_cast<const char*>(str), length * sizeof(typename | ||||
SourceEncoding::Ch)); | ||||
EncodedInputStream<SourceEncoding, MemoryStream> is(ms); | ||||
ParseStream<parseFlags, SourceEncoding>(is); | ||||
return *this; | ||||
} | ||||
template <unsigned parseFlags> | ||||
GenericDocument& Parse(const Ch* str, size_t length) { | ||||
return Parse<parseFlags, Encoding>(str, length); | ||||
} | ||||
GenericDocument& Parse(const Ch* str, size_t length) { | ||||
return Parse<kParseDefaultFlags>(str, length); | ||||
} | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
template <unsigned parseFlags, typename SourceEncoding> | ||||
GenericDocument& Parse(const std::basic_string<typename SourceEncoding::Ch>& | ||||
str) { | ||||
// c_str() is constant complexity according to standard. Should be faste | ||||
r than Parse(const char*, size_t) | ||||
return Parse<parseFlags, SourceEncoding>(str.c_str()); | ||||
} | ||||
template <unsigned parseFlags> | ||||
GenericDocument& Parse(const std::basic_string<Ch>& str) { | ||||
return Parse<parseFlags, Encoding>(str.c_str()); | ||||
} | ||||
GenericDocument& Parse(const std::basic_string<Ch>& str) { | ||||
return Parse<kParseDefaultFlags>(str); | ||||
} | ||||
#endif // RAPIDJSON_HAS_STDSTRING | ||||
//!@} | //!@} | |||
//!@name Handling parse errors | //!@name Handling parse errors | |||
//!@{ | //!@{ | |||
//! Whether a parse error has occured in the last parsing. | //! Whether a parse error has occured in the last parsing. | |||
bool HasParseError() const { return parseResult_.IsError(); } | bool HasParseError() const { return parseResult_.IsError(); } | |||
//! Get the \ref ParseErrorCode of last parsing. | //! Get the \ref ParseErrorCode of last parsing. | |||
ParseErrorCode GetParseError() const { return parseResult_.Code(); } | ParseErrorCode GetParseError() const { return parseResult_.Code(); } | |||
//! Get the position of last parsing error in input, 0 otherwise. | //! Get the position of last parsing error in input, 0 otherwise. | |||
size_t GetErrorOffset() const { return parseResult_.Offset(); } | size_t GetErrorOffset() const { return parseResult_.Offset(); } | |||
//! Implicit conversion to get the last parse result | ||||
#ifndef __clang // -Wdocumentation | ||||
/*! \return \ref ParseResult of the last parse operation | ||||
\code | ||||
Document doc; | ||||
ParseResult ok = doc.Parse(json); | ||||
if (!ok) | ||||
printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), | ||||
ok.Offset()); | ||||
\endcode | ||||
*/ | ||||
#endif | ||||
operator ParseResult() const { return parseResult_; } | ||||
//!@} | //!@} | |||
//! Get the allocator of this document. | //! Get the allocator of this document. | |||
Allocator& GetAllocator() { return *allocator_; } | Allocator& GetAllocator() { | |||
RAPIDJSON_ASSERT(allocator_); | ||||
return *allocator_; | ||||
} | ||||
//! Get the capacity of stack in bytes. | //! Get the capacity of stack in bytes. | |||
size_t GetStackCapacity() const { return stack_.GetCapacity(); } | size_t GetStackCapacity() const { return stack_.GetCapacity(); } | |||
private: | private: | |||
// clear stack on any exit from ParseStream, e.g. due to exception | // clear stack on any exit from ParseStream, e.g. due to exception | |||
struct ClearStackOnExit { | struct ClearStackOnExit { | |||
explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} | explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} | |||
~ClearStackOnExit() { d_.ClearStack(); } | ~ClearStackOnExit() { d_.ClearStack(); } | |||
private: | private: | |||
ClearStackOnExit(const ClearStackOnExit&); | ClearStackOnExit(const ClearStackOnExit&); | |||
ClearStackOnExit& operator=(const ClearStackOnExit&); | ClearStackOnExit& operator=(const ClearStackOnExit&); | |||
GenericDocument& d_; | GenericDocument& d_; | |||
}; | }; | |||
// callers of the following private Handler functions | // callers of the following private Handler functions | |||
template <typename,typename,typename> friend class GenericReader; // for par sing | // template <typename,typename,typename> friend class GenericReader; // for parsing | |||
template <typename, typename> friend class GenericValue; // for deep copying | template <typename, typename> friend class GenericValue; // for deep copying | |||
public: | ||||
// Implementation of Handler | // Implementation of Handler | |||
bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return tr ue; } | bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return tr ue; } | |||
bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); re turn true; } | bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); re turn true; } | |||
bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); retu rn true; } | bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); retu rn true; } | |||
bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i) ; return true; } | bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i) ; return true; } | |||
bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i) ; return true; } | bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i) ; return true; } | |||
bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType( i); return true; } | bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType( i); return true; } | |||
bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d) ; return true; } | bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d) ; return true; } | |||
bool RawNumber(const Ch* str, SizeType length, bool copy) { | ||||
if (copy) | ||||
new (stack_.template Push<ValueType>()) ValueType(str, length, GetAl | ||||
locator()); | ||||
else | ||||
new (stack_.template Push<ValueType>()) ValueType(str, length); | ||||
return true; | ||||
} | ||||
bool String(const Ch* str, SizeType length, bool copy) { | bool String(const Ch* str, SizeType length, bool copy) { | |||
if (copy) | if (copy) | |||
new (stack_.template Push<ValueType>()) ValueType(str, length, GetAl locator()); | new (stack_.template Push<ValueType>()) ValueType(str, length, GetAl locator()); | |||
else | else | |||
new (stack_.template Push<ValueType>()) ValueType(str, length); | new (stack_.template Push<ValueType>()) ValueType(str, length); | |||
return true; | return true; | |||
} | } | |||
bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObje ctType); return true; } | bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObje ctType); return true; } | |||
bool Key(const Ch* str, SizeType length, bool copy) { return String(str, len gth, copy); } | bool Key(const Ch* str, SizeType length, bool copy) { return String(str, len gth, copy); } | |||
bool EndObject(SizeType memberCount) { | bool EndObject(SizeType memberCount) { | |||
typename ValueType::Member* members = stack_.template Pop<typename Value Type::Member>(memberCount); | typename ValueType::Member* members = stack_.template Pop<typename Value Type::Member>(memberCount); | |||
stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)member Count, GetAllocator()); | stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, Get Allocator()); | |||
return true; | return true; | |||
} | } | |||
bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArray Type); return true; } | bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArray Type); return true; } | |||
bool EndArray(SizeType elementCount) { | bool EndArray(SizeType elementCount) { | |||
ValueType* elements = stack_.template Pop<ValueType>(elementCount); | ValueType* elements = stack_.template Pop<ValueType>(elementCount); | |||
stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, Ge tAllocator()); | stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, Ge tAllocator()); | |||
return true; | return true; | |||
} | } | |||
skipping to change at line 1994 | skipping to change at line 2418 | |||
{ | { | |||
switch (rhs.GetType()) { | switch (rhs.GetType()) { | |||
case kObjectType: | case kObjectType: | |||
case kArrayType: { // perform deep copy via SAX Handler | case kArrayType: { // perform deep copy via SAX Handler | |||
GenericDocument<Encoding,Allocator> d(&allocator); | GenericDocument<Encoding,Allocator> d(&allocator); | |||
rhs.Accept(d); | rhs.Accept(d); | |||
RawAssign(*d.stack_.template Pop<GenericValue>(1)); | RawAssign(*d.stack_.template Pop<GenericValue>(1)); | |||
} | } | |||
break; | break; | |||
case kStringType: | case kStringType: | |||
if (rhs.flags_ == kConstStringFlag) { | if (rhs.data_.f.flags == kConstStringFlag) { | |||
flags_ = rhs.flags_; | data_.f.flags = rhs.data_.f.flags; | |||
data_ = *reinterpret_cast<const Data*>(&rhs.data_); | data_ = *reinterpret_cast<const Data*>(&rhs.data_); | |||
} else { | } else { | |||
SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allo cator); | SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allo cator); | |||
} | } | |||
break; | break; | |||
default: // kNumberType, kTrueType, kFalseType, kNullType | default: | |||
flags_ = rhs.flags_; | data_.f.flags = rhs.data_.f.flags; | |||
data_ = *reinterpret_cast<const Data*>(&rhs.data_); | data_ = *reinterpret_cast<const Data*>(&rhs.data_); | |||
break; | ||||
} | } | |||
} | } | |||
RAPIDJSON_NAMESPACE_END | //! Helper class for accessing Value of array type. | |||
/*! | ||||
Instance of this helper class is obtained by \c GenericValue::GetArray(). | ||||
In addition to all APIs for array type, it provides range-based for loop if | ||||
\c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. | ||||
*/ | ||||
template <bool Const, typename ValueT> | ||||
class GenericArray { | ||||
public: | ||||
typedef GenericArray<true, ValueT> ConstArray; | ||||
typedef GenericArray<false, ValueT> Array; | ||||
typedef ValueT PlainType; | ||||
typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType; | ||||
typedef ValueType* ValueIterator; // This may be const or non-const iterato | ||||
r | ||||
typedef const ValueT* ConstValueIterator; | ||||
typedef typename ValueType::AllocatorType AllocatorType; | ||||
typedef typename ValueType::StringRefType StringRefType; | ||||
template <typename, typename> | ||||
friend class GenericValue; | ||||
GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} | ||||
GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; retu | ||||
rn *this; } | ||||
~GenericArray() {} | ||||
SizeType Size() const { return value_.Size(); } | ||||
SizeType Capacity() const { return value_.Capacity(); } | ||||
bool Empty() const { return value_.Empty(); } | ||||
void Clear() const { value_.Clear(); } | ||||
ValueType& operator[](SizeType index) const { return value_[index]; } | ||||
ValueIterator Begin() const { return value_.Begin(); } | ||||
ValueIterator End() const { return value_.End(); } | ||||
GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { | ||||
value_.Reserve(newCapacity, allocator); return *this; } | ||||
GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { va | ||||
lue_.PushBack(value, allocator); return *this; } | ||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||
GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { v | ||||
alue_.PushBack(value, allocator); return *this; } | ||||
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||
GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { | ||||
value_.PushBack(value, allocator); return *this; } | ||||
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal: | ||||
:IsPointer<T>, internal::IsGenericValue<T> >), (const GenericArray&)) PushBack(T | ||||
value, AllocatorType& allocator) const { value_.PushBack(value, allocator); ret | ||||
urn *this; } | ||||
GenericArray PopBack() const { value_.PopBack(); return *this; } | ||||
ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos) | ||||
; } | ||||
ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const | ||||
{ return value_.Erase(first, last); } | ||||
#if RAPIDJSON_HAS_CXX11_RANGE_FOR | ||||
ValueIterator begin() const { return value_.Begin(); } | ||||
ValueIterator end() const { return value_.End(); } | ||||
#endif | ||||
#if defined(_MSC_VER) || defined(__GNUC__) | private: | |||
RAPIDJSON_DIAG_POP | GenericArray(); | |||
GenericArray(ValueType& value) : value_(value) {} | ||||
ValueType& value_; | ||||
}; | ||||
//! Helper class for accessing Value of object type. | ||||
/*! | ||||
Instance of this helper class is obtained by \c GenericValue::GetObject(). | ||||
In addition to all APIs for array type, it provides range-based for loop if | ||||
\c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. | ||||
*/ | ||||
template <bool Const, typename ValueT> | ||||
class GenericObject { | ||||
public: | ||||
typedef GenericObject<true, ValueT> ConstObject; | ||||
typedef GenericObject<false, ValueT> Object; | ||||
typedef ValueT PlainType; | ||||
typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType; | ||||
typedef GenericMemberIterator<Const, typename ValueT::EncodingType, typename | ||||
ValueT::AllocatorType> MemberIterator; // This may be const or non-const itera | ||||
tor | ||||
typedef GenericMemberIterator<true, typename ValueT::EncodingType, typename | ||||
ValueT::AllocatorType> ConstMemberIterator; | ||||
typedef typename ValueType::AllocatorType AllocatorType; | ||||
typedef typename ValueType::StringRefType StringRefType; | ||||
typedef typename ValueType::EncodingType EncodingType; | ||||
typedef typename ValueType::Ch Ch; | ||||
template <typename, typename> | ||||
friend class GenericValue; | ||||
GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} | ||||
GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; re | ||||
turn *this; } | ||||
~GenericObject() {} | ||||
SizeType MemberCount() const { return value_.MemberCount(); } | ||||
bool ObjectEmpty() const { return value_.ObjectEmpty(); } | ||||
template <typename T> ValueType& operator[](T* name) const { return value_[n | ||||
ame]; } | ||||
template <typename SourceAllocator> ValueType& operator[](const GenericValue | ||||
<EncodingType, SourceAllocator>& name) const { return value_[name]; } | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
ValueType& operator[](const std::basic_string<Ch>& name) const { return valu | ||||
e_[name]; } | ||||
#endif | ||||
MemberIterator MemberBegin() const { return value_.MemberBegin(); } | ||||
MemberIterator MemberEnd() const { return value_.MemberEnd(); } | ||||
bool HasMember(const Ch* name) const { return value_.HasMember(name); } | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasM | ||||
ember(name); } | ||||
#endif | ||||
template <typename SourceAllocator> bool HasMember(const GenericValue<Encodi | ||||
ngType, SourceAllocator>& name) const { return value_.HasMember(name); } | ||||
MemberIterator FindMember(const Ch* name) const { return value_.FindMember(n | ||||
ame); } | ||||
template <typename SourceAllocator> MemberIterator FindMember(const GenericV | ||||
alue<EncodingType, SourceAllocator>& name) const { return value_.FindMember(name | ||||
); } | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
MemberIterator FindMember(const std::basic_string<Ch>& name) const { return | ||||
value_.FindMember(name); } | ||||
#endif | ||||
GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& al | ||||
locator) const { value_.AddMember(name, value, allocator); return *this; } | ||||
GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& | ||||
allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
GenericObject AddMember(ValueType& name, std::basic_string<Ch>& value, Alloc | ||||
atorType& allocator) const { value_.AddMember(name, value, allocator); return *t | ||||
his; } | ||||
#endif | #endif | |||
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal: | ||||
:IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) AddMember(ValueType | ||||
& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, | ||||
allocator); return *this; } | ||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||
GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& | ||||
allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||
GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& a | ||||
llocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||
GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& a | ||||
llocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||
GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType | ||||
& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||||
GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& | ||||
allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||
GenericObject AddMember(StringRefType name, StringRefType value, AllocatorTy | ||||
pe& allocator) const { value_.AddMember(name, value, allocator); return *this; } | ||||
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal: | ||||
:IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(String | ||||
RefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, | ||||
value, allocator); return *this; } | ||||
void RemoveAllMembers() { return value_.RemoveAllMembers(); } | ||||
bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); | ||||
} | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.R | ||||
emoveMember(name); } | ||||
#endif | ||||
template <typename SourceAllocator> bool RemoveMember(const GenericValue<Enc | ||||
odingType, SourceAllocator>& name) const { return value_.RemoveMember(name); } | ||||
MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMe | ||||
mber(m); } | ||||
MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.Er | ||||
aseMember(pos); } | ||||
MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator la | ||||
st) const { return value_.EraseMember(first, last); } | ||||
bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
bool EraseMember(const std::basic_string<Ch>& name) const { return EraseMemb | ||||
er(ValueType(StringRef(name))); } | ||||
#endif | ||||
template <typename SourceAllocator> bool EraseMember(const GenericValue<Enco | ||||
dingType, SourceAllocator>& name) const { return value_.EraseMember(name); } | ||||
#if RAPIDJSON_HAS_CXX11_RANGE_FOR | ||||
MemberIterator begin() const { return value_.MemberBegin(); } | ||||
MemberIterator end() const { return value_.MemberEnd(); } | ||||
#endif | ||||
private: | ||||
GenericObject(); | ||||
GenericObject(ValueType& value) : value_(value) {} | ||||
ValueType& value_; | ||||
}; | ||||
RAPIDJSON_NAMESPACE_END | ||||
RAPIDJSON_DIAG_POP | ||||
#endif // RAPIDJSON_DOCUMENT_H_ | #endif // RAPIDJSON_DOCUMENT_H_ | |||
End of changes. 145 change blocks. | ||||
223 lines changed or deleted | 897 lines changed or added |