// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License.
// Forward declaration. template <typename Encoding, typename Allocator> class GenericValue;
template <typename Encoding, typename Allocator, typename StackAllocator> class GenericDocument;
//! Name-value pair in a JSON object value. /*! ThisclasswasinternaltoGenericValue.Itusedtobeainnerstruct. Butacompiler(IBMXLC/C++forAIX)havereportedtohaveproblemwiththatsoitmovedasanamespacescopestruct. https://code.google.com/p/rapidjson/issues/detail?id=64
*/ template <typename Encoding, typename Allocator> struct GenericMember {
GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
GenericValue<Encoding, Allocator> value; //!< value of member.
};
//! (Constant) member iterator for a JSON object value /*! \tparamConstIsthisaconstantiterator? \tparamEncodingEncodingofthevalue.(Evennon-stringvaluesneedtohavethesameencodinginadocument) \tparamAllocatorAllocatortypeforallocatingmemoryofobject,arrayandstring.
\bExample \code Valuev("foo");// ok, no need to copy & calculate length constcharfoo[]="foo"; v.SetString(foo);// ok
constchar*bar=foo; // Value x(bar); // not ok, can't rely on bar's lifetime Valuex(StringRef(bar));// lifetime explicitly guaranteed by user Valuey(StringRef(bar,3));// ok, explicitly pass length \endcode
\seeStringRef,GenericValue::SetString
*/ template<typename CharType> struct GenericStringRef { typedef CharType Ch; //!< character type of the string
//! Create string reference from \c const character array /*! Thisconstructorimplicitlycreatesaconstantstringreferencefrom a\cconstcharacterarray.Ithasbetterperformancethan \refStringRef(constCharType*)byinferringthestring\reflength fromthearraylength,andalsosupportsstringscontainingnull characters.
//! Create constant string reference from pointer and length /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \paramlenlengthofthestring,excludingthetrailingNULLterminator
//! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function canbeusedtoavoidcopyingacharacterstringtobereferencedasa valueinaJSONGenericValueobject,ifthestring'slifetimeisknown tobevalidlongenough. \tparamCharTypeCharactertypeofthestring \paramstrConstantstring,lifetimeassumedtobelongerthantheuseofthestringine.g.aGenericValue \returnGenericStringRefstringreferenceobject \relatesalsoGenericStringRef
//! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function canbeusedtoavoidcopyingacharacterstringtobereferencedasa valueinaJSONGenericValueobject,ifthestring'slifetimeisknown tobevalidlongenough.
#if RAPIDJSON_HAS_STDSTRING //! Mark a string object as constant string /*! Mark a string object (e.g. \c std::string) as a "string literal". Thisfunctioncanbeusedtoavoidcopyingastringtobereferencedasa valueinaJSONGenericValueobject,ifthestring'slifetimeisknown tobevalidlongenough.
//! Represents a JSON value. Use Value for UTF8 encoding and default allocator. /*! AJSONvaluecanbeoneof7types.Thisclassisavarianttypesupporting thesetypes.
UsetheValueifUTF8anddefaultallocator
\tparamEncodingEncodingofthevalue.(Evennon-stringvaluesneedtohavethesameencodinginadocument) \tparamAllocatorAllocatortypeforallocatingmemoryofobject,arrayandstring.
*/ template <typename Encoding, typename Allocator = MemoryPoolAllocator<> > class GenericValue { public: //! Name-value pair in an object. typedef GenericMember<Encoding, Allocator> Member; typedef Encoding EncodingType; //!< Encoding type from template parameter. typedef Allocator AllocatorType; //!< Allocator type from template parameter. typedeftypename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericStringRef<Ch> StringRefType; //!< Reference to a constant string typedeftypename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; //!< Member iterator for iterating in object. typedeftypename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. typedefconst GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of itself.
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11
GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) {
rhs.flags_ = kNullFlag; // give up contents
} #endif
private: //! Copy constructor is not permitted.
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:
//! Constructor with JSON value type. /*! This creates a Value of specified type with default content. \paramtypeTypeofthevalue. \noteDefaultcontentfornumberiszero.
*/ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() { staticconstunsigned defaultFlags[7] = {
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
kNumberAnyFlag
};
RAPIDJSON_ASSERT(type <= kNumberType);
flags_ = defaultFlags[type];
// Use ShortString to store empty string. if (type == kStringType)
data_.ss.SetLength(0);
}
//! Explicit copy constructor (with allocator) /*! Creates a copy of a Value by using the given Allocator \tparamSourceAllocatorallocatorof\crhs \paramrhsValuetocopyfrom(read-only) \paramallocatorAllocatorforallocatingcopiedelementsandbuffers.CommonlyuseGenericDocument::GetAllocator(). \seeCopyFrom()
*/ template< typename SourceAllocator >
GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
//! Constructor for boolean value. /*! \param b Boolean value \noteThisconstructorislimitedto\emrealbooleanvaluesandrejects implicitlyconvertedtypeslikearbitrarypointers.Useanexplicitcast to\cbool,ifyouwanttoconstructabooleanJSONvalueinsuchcases.
*/ #ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen template <typename T> explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>))) RAPIDJSON_NOEXCEPT #else explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT #endif
: data_(), flags_(b ? kTrueFlag : kFalseFlag) { // safe-guard against failing SFINAE
RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
}
//! Constructor for int value. explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) {
data_.n.i64 = i; if (i >= 0)
flags_ |= kUintFlag | kUint64Flag;
}
//! Constructor for constant string (i.e. do not make a copy of string)
GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(StringRef(s, length)); }
//! Constructor for constant string (i.e. do not make a copy of string) explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(s); }
//! Constructor for copy-string (i.e. do make a copy of string)
GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); }
//! Constructor for copy-string (i.e. do make a copy of string)
GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
#if RAPIDJSON_HAS_STDSTRING //! Constructor for copy-string from a string object (i.e. do make a copy of string) /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
*/
GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } #endif
//! Destructor. /*! Need to destruct elements of array, members of object, or copy-string.
*/
~GenericValue() { if (Allocator::kNeedFree) { // Shortcut by Allocator's trait switch(flags_) { case kArrayFlag: for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
v->~GenericValue();
Allocator::Free(data_.a.elements); break;
case kObjectFlag: for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
m->~Member();
Allocator::Free(data_.o.members); break;
case kCopyStringFlag:
Allocator::Free(const_cast<Ch*>(data_.s.str)); break;
default: break; // Do nothing for other types.
}
}
}
//@}
//!@name Assignment operators //@{
//! Assignment with move semantics. /*! \param rhs Source of the assignment. It will become a null value after assignment.
*/
GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
RAPIDJSON_ASSERT(this != &rhs); this->~GenericValue();
RawAssign(rhs); return *this;
}
//! Deep-copy assignment from Value /*! Assigns a \b copy of the Value to the current Value object \tparamSourceAllocatorAllocatortypeof\crhs \paramrhsValuetocopyfrom(read-only) \paramallocatorAllocatortouseforcopying
*/ template <typename SourceAllocator>
GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
RAPIDJSON_ASSERT((void*)this != (voidconst*)&rhs); this->~GenericValue(); new (this) GenericValue(rhs, allocator); return *this;
}
//! Exchange the contents of this value with those of other. /*! \paramotherAnothervalue. \noteConstantcomplexity.
*/
GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {
GenericValue temp;
temp.RawAssign(*this);
RawAssign(other);
other.RawAssign(temp); return *this;
}
//! free-standing swap function helper /*! Helperfunctiontoenablesupportforcommonswapimplementationpatternbasedon\cstd::swap: \code voidswap(MyClass&a,MyClass&b){ usingstd::swap; swap(a.value,b.value); // ... } \endcode \seeSwap()
*/ friendinlinevoid swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
//! Prepare Value for move semantics /*! \return *this */
GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } //@}
switch (GetType()) { case kObjectType: // Warning: O(n^2) inner-loop if (data_.o.size != rhs.data_.o.size) returnfalse; for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) returnfalse;
} returntrue;
case kArrayType: if (data_.a.size != rhs.data_.a.size) returnfalse; for (SizeType i = 0; i < data_.a.size; i++) if ((*this)[i] != rhs[i]) returnfalse; returntrue;
case kStringType: return StringEqual(rhs);
case kNumberType: if (IsDouble() || rhs.IsDouble()) { double a = GetDouble(); // May convert from integer to double. double b = rhs.GetDouble(); // Ditto return a >= b && a <= b; // Prevent -Wfloat-equal
} else return data_.n.u64 == rhs.data_.n.u64;
GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
//@}
//!@name Bool //@{
bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; } //!< Set boolean value /*! \post IsBool() == true */
GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
//@}
//!@name Object //@{
//! Set this value as an empty object. /*! \post IsObject() == true */
GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
//! Get the number of members in the object.
SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
//! Check whether the object is empty. bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
//! Get a value from an object associated with the name. /*! \pre IsObject() == true \tparamTEither\cChor\cconst\cCh(templateusedfordisambiguationwith\refoperator[](SizeType)) \noteInversion0.1x,ifthememberisnotfound,thisfunctionreturnsanullvalue.Thismakesissue7. Since0.2,ifthenameisnotcorrect,itwillassert. Ifuserisunsurewhetheramemberexists,usershoulduseHasMember()first. AbetterapproachistouseFindMember(). \noteLineartimecomplexity.
*/ template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) {
GenericValue n(StringRef(name)); return (*this)[n];
} template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { returnconst_cast<GenericValue&>(*this)[name]; }
//! Get a value from an object associated with the name. /*! \pre IsObject() == true \tparamSourceAllocatorAllocatorofthe\cnamevalue
#if RAPIDJSON_HAS_STDSTRING //! Get a value from an object associated with name (string object).
GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; } const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; } #endif
//! Check whether a member exists in the object. /*! \paramnameMembernametobesearched. \preIsObject()==true \returnWhetheramemberwiththatnameexists. \noteItisbettertouseFindMember()directlyifyouneedtheobtainthevalueaswell. \noteLineartimecomplexity.
*/ bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
#if RAPIDJSON_HAS_STDSTRING //! Check whether a member exists in the object with string object. /*! \paramnameMembernametobesearched. \preIsObject()==true \returnWhetheramemberwiththatnameexists. \noteItisbettertouseFindMember()directlyifyouneedtheobtainthevalueaswell. \noteLineartimecomplexity.
*/ bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); } #endif
//! Check whether a member exists in the object with GenericValue name. /*! ThisversionisfasterbecauseitdoesnotneedaStrLen().Itcanalsohandlestringwithnullcharacter. \paramnameMembernametobesearched. \preIsObject()==true \returnWhetheramemberwiththatnameexists. \noteItisbettertouseFindMember()directlyifyouneedtheobtainthevalueaswell. \noteLineartimecomplexity.
*/ template <typename SourceAllocator> bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }
//! Find member by name. /*! \paramnameMembernametobesearched. \preIsObject()==true \returnIteratortomember,ifitexists. Otherwisereturns\refMemberEnd().
//! Add a member (name-value pair) to the object. /*! \param name A string value as name of member. \paramvalueValueofanytype. \paramallocatorAllocatorforreallocatingmemory.Itmustbethesameoneasusedbefore.CommonlyuseGenericDocument::GetAllocator(). \returnThevalueitselfforfluentAPI. \noteTheownershipof\cnameand\cvaluewillbetransferredtothisobjectonsuccess. \preIsObject()&&name.IsString() \postname.IsNull()&&value.IsNull() \noteAmortizedConstanttimecomplexity.
*/
GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(name.IsString());
//! Add a constant string value as member (name-value pair) to the object. /*! \param name A string value as name of member. \paramvalueconstantstringreferenceasvalueofmember. \paramallocatorAllocatorforreallocatingmemory.Itmustbethesameoneasusedbefore.CommonlyuseGenericDocument::GetAllocator(). \returnThevalueitselfforfluentAPI. \preIsObject() \noteThisoverloadisneededtoavoidclasheswiththegenericprimitivetypeAddMember(GenericValue&,T,Allocator&)overloadbelow. \noteAmortizedConstanttimecomplexity.
*/
GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {
GenericValue v(value); return AddMember(name, v, allocator);
}
#if RAPIDJSON_HAS_STDSTRING //! Add a string object as member (name-value pair) to the object. /*! \param name A string value as name of member. \paramvalueconstantstringreferenceasvalueofmember. \paramallocatorAllocatorforreallocatingmemory.Itmustbethesameoneasusedbefore.CommonlyuseGenericDocument::GetAllocator(). \returnThevalueitselfforfluentAPI. \preIsObject() \noteThisoverloadisneededtoavoidclasheswiththegenericprimitivetypeAddMember(GenericValue&,T,Allocator&)overloadbelow. \noteAmortizedConstanttimecomplexity.
*/
GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {
GenericValue v(value, allocator); return AddMember(name, v, allocator);
} #endif
//! Add any primitive value as member (name-value pair) to the object. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \paramnameAstringvalueasnameofmember. \paramvalueValueofprimitivetype\cTasvalueofmember \paramallocatorAllocatorforreallocatingmemory.CommonlyuseGenericDocument::GetAllocator(). \returnThevalueitselfforfluentAPI. \preIsObject()
//! Add a member (name-value pair) to the object. /*! \param name A constant string reference as name of member. \paramvalueValueofanytype. \paramallocatorAllocatorforreallocatingmemory.Itmustbethesameoneasusedbefore.CommonlyuseGenericDocument::GetAllocator(). \returnThevalueitselfforfluentAPI. \noteTheownershipof\cvaluewillbetransferredtothisobjectonsuccess. \preIsObject() \postvalue.IsNull() \noteAmortizedConstanttimecomplexity.
*/
GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {
GenericValue n(name); return AddMember(n, value, allocator);
}
//! Add a constant string value as member (name-value pair) to the object. /*! \param name A constant string reference as name of member. \paramvalueconstantstringreferenceasvalueofmember. \paramallocatorAllocatorforreallocatingmemory.Itmustbethesameoneasusedbefore.CommonlyuseGenericDocument::GetAllocator(). \returnThevalueitselfforfluentAPI. \preIsObject() \noteThisoverloadisneededtoavoidclasheswiththegenericprimitivetypeAddMember(StringRefType,T,Allocator&)overloadbelow. \noteAmortizedConstanttimecomplexity.
*/
GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {
GenericValue v(value); return AddMember(name, v, allocator);
}
//! Add any primitive value as member (name-value pair) to the object. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \paramnameAconstantstringreferenceasnameofmember. \paramvalueValueofprimitivetype\cTasvalueofmember \paramallocatorAllocatorforreallocatingmemory.CommonlyuseGenericDocument::GetAllocator(). \returnThevalueitselfforfluentAPI. \preIsObject()
//! Remove all members in the object. /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. \noteLineartimecomplexity.
*/ void RemoveAllMembers() {
RAPIDJSON_ASSERT(IsObject()); for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
m->~Member();
data_.o.size = 0;
}
//! Remove a member in object by its name. /*! \param name Name of member to be removed. \returnWhetherthememberexisted. \noteThisfunctionmayreordertheobjectmembers.Use\ref EraseMember(ConstMemberIterator)ifyouneedtopreservethe relativeorderoftheremainingmembers. \noteLineartimecomplexity.
*/ bool RemoveMember(const Ch* name) {
GenericValue n(StringRef(name)); return RemoveMember(n);
}
//! Remove a member in object by iterator. /*! \param m member iterator (obtained by FindMember() or MemberBegin()). \returnthenewiteratorafterremoval. \noteThisfunctionmayreordertheobjectmembers.Use\ref EraseMember(ConstMemberIterator)ifyouneedtopreservethe relativeorderoftheremainingmembers. \noteConstanttimecomplexity.
*/
MemberIterator RemoveMember(MemberIterator m) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(data_.o.size > 0);
RAPIDJSON_ASSERT(data_.o.members != 0);
RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
MemberIterator last(data_.o.members + (data_.o.size - 1)); if (data_.o.size > 1 && m != last) { // Move the last one to this place
*m = *last;
} else { // Only one left, just destroy
m->~Member();
}
--data_.o.size; return m;
}
//! Remove a member from an object by iterator. /*! \param pos iterator to the member to remove \preIsObject()==true&&\refMemberBegin()<=\cpos<\refMemberEnd() \returnIteratorfollowingtheremovedelement. Iftheiterator\cposreferstothelastelement,the\refMemberEnd()iteratorisreturned. \noteThisfunctionpreservestherelativeorderoftheremainingobject members.Ifyoudonotneedthis,usethemoreefficient\refRemoveMember(MemberIterator). \noteLineartimecomplexity.
*/
MemberIterator EraseMember(ConstMemberIterator pos) { return EraseMember(pos, pos +1);
}
//! Remove members in the range [first, last) from an object. /*! \param first iterator to the first member to remove \paramlastiteratorfollowingthelastmembertoremove \preIsObject()==true&&\refMemberBegin()<=\cfirst<=\clast<=\refMemberEnd() \returnIteratorfollowingthelastremovedelement. \noteThisfunctionpreservestherelativeorderoftheremainingobject members. \noteLineartimecomplexity.
*/
MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(data_.o.size > 0);
RAPIDJSON_ASSERT(data_.o.members != 0);
RAPIDJSON_ASSERT(first >= MemberBegin());
RAPIDJSON_ASSERT(first <= last);
RAPIDJSON_ASSERT(last <= MemberEnd());
//! Erase a member in object by its name. /*! \param name Name of member to be removed. \returnWhetherthememberexisted. \noteLineartimecomplexity.
*/ bool EraseMember(const Ch* name) {
GenericValue n(StringRef(name)); return EraseMember(n);
}
//! Set this value as an empty array. /*! \post IsArray == true */
GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
//! Get the number of elements in array.
SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
//! Get the capacity of array.
SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
//! Check whether the array is empty. bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
//! Remove all elements in the array. /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. \noteLineartimecomplexity.
*/ void Clear() {
RAPIDJSON_ASSERT(IsArray()); for (SizeType i = 0; i < data_.a.size; ++i)
data_.a.elements[i].~GenericValue();
data_.a.size = 0;
}
//! Get an element from array by index. /*! \pre IsArray() == true \paramindexZero-basedindexofelement. \seeoperator[](T*)
*/
GenericValue& operator[](SizeType index) {
RAPIDJSON_ASSERT(IsArray());
RAPIDJSON_ASSERT(index < data_.a.size); return data_.a.elements[index];
} const GenericValue& operator[](SizeType index) const { returnconst_cast<GenericValue&>(*this)[index]; }
//! Request the array to have enough capacity to store elements. /*! \param newCapacity The capacity that the array at least need to have. \paramallocatorAllocatorforreallocatingmemory.Itmustbethesameoneasusedbefore.CommonlyuseGenericDocument::GetAllocator(). \returnThevalueitselfforfluentAPI. \noteLineartimecomplexity.
*/
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
RAPIDJSON_ASSERT(IsArray()); if (newCapacity > data_.a.capacity) {
data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue));
data_.a.capacity = newCapacity;
} return *this;
}
//! Append a GenericValue at the end of the array. /*! \param value Value to be appended. \paramallocatorAllocatorforreallocatingmemory.Itmustbethesameoneasusedbefore.CommonlyuseGenericDocument::GetAllocator(). \preIsArray()==true \postvalue.IsNull()==true \returnThevalueitselfforfluentAPI. \noteTheownershipof\cvaluewillbetransferredtothisarrayonsuccess. \noteIfthenumberofelementstobeappendedisknown,callsReserve()oncefirstmaybemoreefficient. \noteAmortizedconstanttimecomplexity.
*/
GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
RAPIDJSON_ASSERT(IsArray()); if (data_.a.size >= data_.a.capacity)
Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);
data_.a.elements[data_.a.size++].RawAssign(value); return *this;
}
//! Append a constant string reference at the end of the array. /*! \param value Constant string reference to be appended. \paramallocatorAllocatorforreallocatingmemory.Itmustbethesameoneusedpreviously.CommonlyuseGenericDocument::GetAllocator(). \preIsArray()==true \returnThevalueitselfforfluentAPI. \noteIfthenumberofelementstobeappendedisknown,callsReserve()oncefirstmaybemoreefficient. \noteAmortizedconstanttimecomplexity. \seeGenericStringRef
*/
GenericValue& PushBack(StringRefType value, Allocator& allocator) { return (*this).template PushBack<StringRefType>(value, allocator);
}
//! Append a primitive value at the end of the array. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \paramvalueValueofprimitivetypeTtobeappended. \paramallocatorAllocatorforreallocatingmemory.Itmustbethesameoneasusedbefore.CommonlyuseGenericDocument::GetAllocator(). \preIsArray()==true \returnThevalueitselfforfluentAPI. \noteIfthenumberofelementstobeappendedisknown,callsReserve()oncefirstmaybemoreefficient.
//! Remove the last element in the array. /*! \noteConstanttimecomplexity.
*/
GenericValue& PopBack() {
RAPIDJSON_ASSERT(IsArray());
RAPIDJSON_ASSERT(!Empty());
data_.a.elements[--data_.a.size].~GenericValue(); return *this;
}
//! Remove an element of array by iterator. /*! \parampositeratortotheelementtoremove \preIsArray()==true&&\refBegin()<=\cpos<\refEnd() \returnIteratorfollowingtheremovedelement.Iftheiteratorposreferstothelastelement,theEnd()iteratorisreturned. \noteLineartimecomplexity.
*/
ValueIterator Erase(ConstValueIterator pos) { return Erase(pos, pos + 1);
}
//! Remove elements in the range [first, last) of the array. /*! \paramfirstiteratortothefirstelementtoremove \paramlastiteratorfollowingthelastelementtoremove \preIsArray()==true&&\refBegin()<=\cfirst<=\clast<=\refEnd() \returnIteratorfollowingthelastremovedelement. \noteLineartimecomplexity.
*/
ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
RAPIDJSON_ASSERT(IsArray());
RAPIDJSON_ASSERT(data_.a.size > 0);
RAPIDJSON_ASSERT(data_.a.elements != 0);
RAPIDJSON_ASSERT(first >= Begin());
RAPIDJSON_ASSERT(first <= last);
RAPIDJSON_ASSERT(last <= End());
ValueIterator pos = Begin() + (first - Begin()); for (ValueIterator itr = pos; itr != last; ++itr)
itr->~GenericValue();
std::memmove(pos, last, (End() - last) * sizeof(GenericValue));
data_.a.size -= (last - first); return pos;
}
//! Get the length of string. /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
*/
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
//! Set this value as a string without copying source string. /*! This version has better performance with supplied length, and also support string containing null character. \paramssourcestringpointer. \paramlengthThelengthofsourcestring,excludingthetrailingnullterminator. \returnThevalueitselfforfluentAPI. \postIsString()==true&&GetString()==s&&GetStringLength()==length \seeSetString(StringRefType)
*/
GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }
//! Set this value as a string without copying source string. /*! \param s source string reference \returnThevalueitselfforfluentAPI. \postIsString()==true&&GetString()==s&&GetStringLength()==s.length
*/
GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }
//! Set this value as a string by copying from source string. /*! This version has better performance with supplied length, and also support string containing null character. \paramssourcestring. \paramlengthThelengthofsourcestring,excludingthetrailingnullterminator. \paramallocatorAllocatorforallocatingcopiedbuffer.CommonlyuseGenericDocument::GetAllocator(). \returnThevalueitselfforfluentAPI. \postIsString()==true&&GetString()!=s&&strcmp(GetString(),s)==0&&GetStringLength()==length
*/
GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }
//! Set this value as a string by copying from source string. /*! \param s source string. \paramallocatorAllocatorforallocatingcopiedbuffer.CommonlyuseGenericDocument::GetAllocator(). \returnThevalueitselfforfluentAPI. \postIsString()==true&&GetString()!=s&&strcmp(GetString(),s)==0&&GetStringLength()==length
*/
GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
#if RAPIDJSON_HAS_STDSTRING //! Set this value as a string by copying from source string. /*! \param s source string. \paramallocatorAllocatorforallocatingcopiedbuffer.CommonlyuseGenericDocument::GetAllocator(). \returnThevalueitselfforfluentAPI. \postIsString()==true&&GetString()!=s.data()&&strcmp(GetString(),s.data()==0&&GetStringLength()==s.size() \noteRequiresthedefinitionofthepreprocessorsymbol\refRAPIDJSON_HAS_STDSTRING.
*/
GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); } #endif
//@}
//! Generate events of this value to a Handler. /*! This function adopts the GoF visitor pattern. TypicalusageistooutputthisJSONvalueasJSONtextviaWriter,whichisaHandler. ItcanalsobeusedtodeepclonethisvalueviaGenericDocument,whichisalsoaHandler. \tparamHandlertypeofhandler. \paramhandlerAnobjectimplementingconceptHandler.
*/ template <typename Handler> bool Accept(Handler& handler) const { switch(GetType()) { case kNullType: return handler.Null(); case kFalseType: return handler.Bool(false); case kTrueType: return handler.Bool(true);
case kObjectType: if (!handler.StartObject()) returnfalse; for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0)) returnfalse; if (!m->value.Accept(handler)) returnfalse;
} return handler.EndObject(data_.o.size);
case kArrayType: if (!handler.StartArray()) returnfalse; for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) if (!v->Accept(handler)) returnfalse; return handler.EndArray(data_.a.size);
case kStringType: return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0);
// implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars // (excluding the terminating zero) and store a value to determine the length of the contained // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as // the string terminator as well. For getting the string length back from that value just use // "MaxSize - str[LenPos]". // This allows to store 11-chars strings in 32-bit mode and 15-chars strings in 64-bit mode // inline (for `UTF8`-encoded strings). struct ShortString { enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
Ch str[MaxChars];
inlinestaticbool Usable(SizeType len) { return (MaxSize >= len); } inlinevoid SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - len); } inline SizeType GetLength() const { return (SizeType)(MaxSize - str[LenPos]); }
}; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
// By using proper binary layout, retrieval of different integer types do not need conversions. union Number { #if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN struct I { int i; char padding[4];
}i; struct U { unsigned u; char padding2[4];
}u; #else struct I { char padding[4]; int i;
}i; struct U { char padding2[4]; unsigned u;
}u; #endif
int64_t i64;
uint64_t u64; double d;
}; // 8 bytes
//! A document for parsing JSON text as DOM. /*! \noteimplementsHandlerconcept \tparamEncodingEncodingforbothparsingandstringstorage. \tparamAllocatorAllocatorforallocatingmemoryfortheDOM \tparamStackAllocatorAllocatorforallocatingmemoryforstackduringparsing. \warningAlthoughGenericDocumentinheritsfromGenericValue,theAPIdoes\bnotprovideanyvirtualfunctions,especiallynovirtualdestructor.Toavoidmemoryleaks,donot\cdeleteaGenericDocumentobjectviaapointertoaGenericValue.
*/ template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator> class GenericDocument : public GenericValue<Encoding, Allocator> { public: typedeftypename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document. typedef Allocator AllocatorType; //!< Allocator type from template parameter.
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move assignment in C++11
GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
{ // The cast to ValueType is necessary here, because otherwise it would // attempt to call GenericValue's templated assignment operator.
ValueType::operator=(std::forward<ValueType>(rhs));
// Calling the destructor here would prematurely call stack_'s destructor
Destroy();
//! Exchange the contents of this document with those of another. /*! \paramotherAnotherdocument. \noteConstantcomplexity. \seeGenericValue::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 /*! Helperfunctiontoenablesupportforcommonswapimplementationpatternbasedon\cstd::swap: \code voidswap(MyClass&a,MyClass&b){ usingstd::swap; swap(a.doc,b.doc); // ... } \endcode \seeSwap()
*/ friendinlinevoid swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
//!@name Parse from stream //!@{
//! Parse JSON text from an input stream (with Encoding conversion) /*! \tparam parseFlags Combination of \ref ParseFlag. \tparamSourceEncodingEncodingofinputstream \tparamInputStreamTypeofinputstream,implementingStreamconcept \paramisInputstreamtobeparsed. \returnThedocumentitselfforfluentAPI.
*/ template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
GenericDocument& ParseStream(InputStream& is) {
GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
ClearStackOnExit scope(*this);
parseResult_ = reader.template Parse<parseFlags>(is, *this); if (parseResult_) {
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
} return *this;
}
//! Parse JSON text from an input stream /*! \tparam parseFlags Combination of \ref ParseFlag. \tparamInputStreamTypeofinputstream,implementingStreamconcept \paramisInputstreamtobeparsed. \returnThedocumentitselfforfluentAPI.
*/ template <unsigned parseFlags, typename InputStream>
GenericDocument& ParseStream(InputStream& is) { return ParseStream<parseFlags, Encoding, InputStream>(is);
}
//! Parse JSON text from an input stream (with \ref kParseDefaultFlags) /*! \tparam InputStream Type of input stream, implementing Stream concept \paramisInputstreamtobeparsed. \returnThedocumentitselfforfluentAPI.
*/ template <typename InputStream>
GenericDocument& ParseStream(InputStream& is) { return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
} //!@}
//!@name Parse in-place from mutable string //!@{
//! Parse JSON text from a mutable string /*! \tparam parseFlags Combination of \ref ParseFlag. \paramstrMutablezero-terminatedstringtobeparsed. \returnThedocumentitselfforfluentAPI.
*/ template <unsigned parseFlags>
GenericDocument& ParseInsitu(Ch* str) {
GenericInsituStringStream<Encoding> s(str); return ParseStream<parseFlags | kParseInsituFlag>(s);
}
//! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) /*! \param str Mutable zero-terminated string to be parsed. \returnThedocumentitselfforfluentAPI.
*/
GenericDocument& ParseInsitu(Ch* str) { return ParseInsitu<kParseDefaultFlags>(str);
} //!@}
//!@name Parse from read-only string //!@{
//! Parse JSON text from a read-only string (with Encoding conversion) /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). \tparamSourceEncodingTranscodingfrominputEncoding \paramstrRead-onlyzero-terminatedstringtobeparsed.
*/ template <unsigned parseFlags, typename SourceEncoding>
GenericDocument& Parse(const Ch* str) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<SourceEncoding> s(str); return ParseStream<parseFlags, SourceEncoding>(s);
}
//! Parse JSON text from a read-only string /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). \paramstrRead-onlyzero-terminatedstringtobeparsed.
*/ template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) { return Parse<parseFlags, Encoding>(str);
}
//! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) /*! \param str Read-only zero-terminated string to be parsed.
*/
GenericDocument& Parse(const Ch* str) { return Parse<kParseDefaultFlags>(str);
} //!@}
//!@name Handling parse errors //!@{
//! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); }
//! Get the \ref ParseErrorCode of last parsing.
ParseErrorCode GetParseError() const { return parseResult_.Code(); }
//! Get the position of last parsing error in input, 0 otherwise.
size_t GetErrorOffset() const { return parseResult_.Offset(); }
//!@}
//! Get the allocator of this document.
Allocator& GetAllocator() {
RAPIDJSON_ASSERT(allocator_); return *allocator_;
}
//! Get the capacity of stack in bytes.
size_t GetStackCapacity() const { return stack_.GetCapacity(); }
private: // clear stack on any exit from ParseStream, e.g. due to exception struct ClearStackOnExit { explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}
~ClearStackOnExit() { d_.ClearStack(); } private:
ClearStackOnExit(const ClearStackOnExit&);
ClearStackOnExit& operator=(const ClearStackOnExit&);
GenericDocument& d_;
};
// callers of the following private Handler functions template <typename,typename,typename> friendclass GenericReader; // for parsing template <typename, typename> friendclass GenericValue; // for deep copying
// Implementation of Handler bool Null() { new (stack_.template Push<ValueType>()) ValueType(); returntrue; } boolBool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); returntrue; } boolInt(int i) { new (stack_.template Push<ValueType>()) ValueType(i); returntrue; } bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); returntrue; } bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); returntrue; } bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); returntrue; } boolDouble(double d) { new (stack_.template Push<ValueType>()) ValueType(d); returntrue; }
bool String(const Ch* str, SizeType length, bool copy) { if (copy) new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator()); else new (stack_.template Push<ValueType>()) ValueType(str, length); returntrue;
}
bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); returntrue; }
void ClearStack() { if (Allocator::kNeedFree) while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
(stack_.template Pop<ValueType>(1))->~ValueType(); else
stack_.Clear();
stack_.ShrinkToFit();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.