diff options
Diffstat (limited to 'external/rapidjson/document.h')
-rw-r--r-- | external/rapidjson/document.h | 527 |
1 files changed, 397 insertions, 130 deletions
diff --git a/external/rapidjson/document.h b/external/rapidjson/document.h index ea161ceed..095aa406b 100644 --- a/external/rapidjson/document.h +++ b/external/rapidjson/document.h @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip
+// 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.
//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
+// 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
//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
+// http://opensource.org/licenses/MIT
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
+// 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.
#ifndef RAPIDJSON_DOCUMENT_H_
#define RAPIDJSON_DOCUMENT_H_
@@ -26,50 +20,41 @@ #include "reader.h"
#include "internal/meta.h"
#include "internal/strfunc.h"
-#include "memorystream.h"
-#include "encodedstream.h"
#include <new> // placement new
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
-#elif defined(__GNUC__)
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(effc++)
#endif
-///////////////////////////////////////////////////////////////////////////////
-// RAPIDJSON_HAS_STDSTRING
-
-#ifndef RAPIDJSON_HAS_STDSTRING
-#ifdef RAPIDJSON_DOXYGEN_RUNNING
-#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
-#else
-#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
#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
-*/
-#include <string>
-#endif // RAPIDJSON_HAS_STDSTRING
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
#include <iterator> // std::iterator, std::random_access_iterator_tag
#endif
-namespace rapidjson {
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
// 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.
/*!
This class was internal to GenericValue. It used to be a inner struct.
@@ -258,6 +243,7 @@ struct GenericStringRef { typedef CharType Ch; //!< character type of the string
//! Create string reference from \c const character array
+#ifndef __clang__ // -Wdocumentation
/*!
This constructor implicitly creates a constant string reference from
a \c const character array. It has better performance than
@@ -280,11 +266,13 @@ struct GenericStringRef { In such cases, the referenced string should be \b copied to the
GenericValue instead.
*/
+#endif
template<SizeType N>
GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
: s(str), length(N-1) {}
//! Explicitly create string reference from \c const character pointer
+#ifndef __clang__ // -Wdocumentation
/*!
This constructor can be used to \b explicitly create a reference to
a constant string pointer.
@@ -303,16 +291,19 @@ struct GenericStringRef { In such cases, the referenced string should be \b copied to the
GenericValue instead.
*/
+#endif
explicit GenericStringRef(const CharType* str)
: s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); }
//! Create constant string reference from pointer and length
+#ifndef __clang__ // -Wdocumentation
/*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
\param len length of the string, excluding the trailing NULL terminator
\post \ref s == str && \ref length == len
\note Constant complexity.
*/
+#endif
GenericStringRef(const CharType* str, SizeType len)
: s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); }
@@ -428,6 +419,7 @@ public: typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object.
typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
+ typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of itself.
//!@name Constructors and destructor.
//@{
@@ -446,6 +438,16 @@ 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.
@@ -453,13 +455,17 @@ public: \param type Type of the value.
\note Default content for number is zero.
*/
- GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() {
+ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() {
static const unsigned defaultFlags[7] = {
- kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag,
+ 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)
@@ -637,7 +643,7 @@ public: */
template <typename SourceAllocator>
GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
- RAPIDJSON_ASSERT((void*)this != (void const*)&rhs);
+ RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs));
this->~GenericValue();
new (this) GenericValue(rhs, allocator);
return *this;
@@ -656,6 +662,20 @@ public: 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
/*! \return *this */
GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
@@ -697,12 +717,15 @@ public: return StringEqual(rhs);
case kNumberType:
- if (IsDouble() || rhs.IsDouble())
- return GetDouble() == rhs.GetDouble(); // May convert one operand from integer to double.
+ 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;
- default: // kTrueType, kFalseType, kNullType
+ default:
return true;
}
}
@@ -797,22 +820,32 @@ public: //! Check whether the object is empty.
bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
- //! Get the value associated with the name.
- /*!
+ //! Get a value from an object associated with the name.
+ /*! \pre IsObject() == true
+ \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType))
\note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.
Since 0.2, if the name is not correct, it will assert.
If user is unsure whether a member exists, user should use HasMember() first.
A better approach is to use FindMember().
\note Linear time complexity.
*/
- GenericValue& operator[](const Ch* name) {
+ 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];
}
- const GenericValue& operator[](const Ch* name) const { return const_cast<GenericValue&>(*this)[name]; }
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+ //! Get a value from an object associated with the name.
+ /*! \pre IsObject() == true
+ \tparam SourceAllocator Allocator of the \c name value
- // This version is faster because it does not need a StrLen().
- // It can also handle string with null character.
+ \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen().
+ And it can also handle strings with embedded null characters.
+
+ \note Linear time complexity.
+ */
template <typename SourceAllocator>
GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator member = FindMember(name);
@@ -820,13 +853,25 @@ public: return member->value;
else {
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>
const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }
+#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
+
//! Const member iterator
/*! \pre IsObject() == true */
ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); }
@@ -850,6 +895,18 @@ public: */
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.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ 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.
/*!
This version is faster because it does not need a StrLen(). It can also handle string with null character.
@@ -906,6 +963,18 @@ public: }
template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+#if RAPIDJSON_HAS_STDSTRING
+ //! Find member by string object name.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+ */
+ MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(StringRef(name)); }
+ ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(StringRef(name)); }
+#endif
+
//! Add a member (name-value pair) to the object.
/*! \param name A string value as name of member.
\param value Value of any type.
@@ -938,6 +1007,60 @@ public: return *this;
}
+ //! Add a constant string value as member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ 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.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ 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
+ \param name A string value as name of member.
+ \param value Value of primitive type \c T as value of member
+ \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+ AddMember(StringRefType, StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized Constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+ AddMember(GenericValue& name, T value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {
return AddMember(name, value, allocator);
@@ -1005,8 +1128,7 @@ public: RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
AddMember(StringRefType name, T value, Allocator& allocator) {
GenericValue n(name);
- GenericValue v(value);
- return AddMember(n, v, allocator);
+ return AddMember(n, value, allocator);
}
//! Remove all members in the object.
@@ -1023,7 +1145,9 @@ public: //! Remove a member in object by its name.
/*! \param name Name of member to be removed.
\return Whether the member existed.
- \note Removing member is implemented by moving the last member. So the ordering of members is changed.
+ \note This function may reorder the object members. Use \ref
+ EraseMember(ConstMemberIterator) if you need to preserve the
+ relative order of the remaining members.
\note Linear time complexity.
*/
bool RemoveMember(const Ch* name) {
@@ -1031,6 +1155,10 @@ public: return RemoveMember(n);
}
+#if RAPIDJSON_HAS_STDSTRING
+ bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }
+#endif
+
template <typename SourceAllocator>
bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator m = FindMember(name);
@@ -1045,8 +1173,9 @@ public: //! Remove a member in object by iterator.
/*! \param m member iterator (obtained by FindMember() or MemberBegin()).
\return the new iterator after removal.
- \note Removing member is implemented by moving the last member. So the ordering of members is changed.
- \note Use \ref EraseMember(ConstMemberIterator) instead, if you need to rely on a stable member ordering.
+ \note This function may reorder the object members. Use \ref
+ EraseMember(ConstMemberIterator) if you need to preserve the
+ relative order of the remaining members.
\note Constant time complexity.
*/
MemberIterator RemoveMember(MemberIterator m) {
@@ -1073,7 +1202,8 @@ public: \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd()
\return Iterator following the removed element.
If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned.
- \note Other than \ref RemoveMember(MemberIterator), this function preserves the ordering of the members.
+ \note This function preserves the relative order of the remaining object
+ members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator).
\note Linear time complexity.
*/
MemberIterator EraseMember(ConstMemberIterator pos) {
@@ -1085,7 +1215,8 @@ public: \param last iterator following the last member to remove
\pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd()
\return Iterator following the last removed element.
- \note Other than \ref RemoveMember(MemberIterator), this function preserves the ordering of the members.
+ \note This function preserves the relative order of the remaining object
+ members.
\note Linear time complexity.
*/
MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
@@ -1099,11 +1230,36 @@ public: MemberIterator pos = MemberBegin() + (first - MemberBegin());
for (MemberIterator itr = pos; itr != last; ++itr)
itr->~Member();
- std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member));
- data_.o.size -= (last - first);
+ std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
+ data_.o.size -= static_cast<SizeType>(last - first);
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(GenericValue(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;
+ }
+
//@}
//!@name Array
@@ -1134,14 +1290,9 @@ public: }
//! Get an element from array by index.
- /*! \param index Zero-based index of element.
-\code
-Value a(kArrayType);
-a.PushBack(123);
-int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type.
-int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work.
-int z = a[0u].GetInt(); // This works too.
-\endcode
+ /*! \pre IsArray() == true
+ \param index Zero-based index of element.
+ \see operator[](T*)
*/
GenericValue& operator[](SizeType index) {
RAPIDJSON_ASSERT(IsArray());
@@ -1172,7 +1323,7 @@ int z = a[0u].GetInt(); // This works too. 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.elements = static_cast<GenericValue*>(allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)));
data_.a.capacity = newCapacity;
}
return *this;
@@ -1279,8 +1430,8 @@ int z = a[0u].GetInt(); // This works too. 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);
+ std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
+ data_.a.size -= static_cast<SizeType>(last - first);
return pos;
}
@@ -1299,8 +1450,8 @@ int z = a[0u].GetInt(); // This works too. if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double
if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
- if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision)
- RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision)
+ if ((flags_ & kInt64Flag) != 0) return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
+ RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
}
GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
@@ -1364,7 +1515,7 @@ int z = a[0u].GetInt(); // This works too. \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.
*/
- GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), s.size(), allocator); }
+ GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
#endif
//@}
@@ -1387,6 +1538,7 @@ int z = a[0u].GetInt(); // This works too. if (!handler.StartObject())
return false;
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))
return false;
if (!m->value.Accept(handler))
@@ -1405,17 +1557,14 @@ int z = a[0u].GetInt(); // This works too. case kStringType:
return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0);
- case kNumberType:
+ default:
+ RAPIDJSON_ASSERT(GetType() == kNumberType);
if (IsInt()) return handler.Int(data_.n.i.i);
else if (IsUint()) return handler.Uint(data_.n.u.u);
else if (IsInt64()) return handler.Int64(data_.n.i64);
else if (IsUint64()) return handler.Uint64(data_.n.u64);
else return handler.Double(data_.n.d);
-
- default:
- RAPIDJSON_ASSERT(false);
}
- return false;
}
private:
@@ -1474,9 +1623,9 @@ private: enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
Ch str[MaxChars];
- inline static bool Usable(SizeType len) { return (MaxSize >= len); }
- inline void SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - len); }
- inline SizeType GetLength() const { return (SizeType)(MaxSize - str[LenPos]); }
+ inline static bool Usable(SizeType len) { return (MaxSize >= len); }
+ inline void SetLength(SizeType len) { str[LenPos] = static_cast<Ch>(MaxSize - len); }
+ inline SizeType GetLength() const { return static_cast<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.
@@ -1528,16 +1677,24 @@ private: // Initialize this value as array with initial data, without calling destructor.
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
flags_ = kArrayFlag;
- data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue));
- std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
+ if (count) {
+ data_.a.elements = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
+ std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
+ }
+ else
+ data_.a.elements = NULL;
data_.a.size = data_.a.capacity = count;
}
//! Initialize this value as object with initial data, without calling destructor.
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
flags_ = kObjectFlag;
- data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member));
- std::memcpy(data_.o.members, members, count * sizeof(Member));
+ if (count) {
+ data_.o.members = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
+ std::memcpy(data_.o.members, members, count * sizeof(Member));
+ }
+ else
+ data_.o.members = NULL;
data_.o.size = data_.o.capacity = count;
}
@@ -1558,7 +1715,7 @@ private: } else {
flags_ = kCopyStringFlag;
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;
}
std::memcpy(str, s, s.length * sizeof(Ch));
@@ -1614,7 +1771,22 @@ public: typedef Allocator AllocatorType; //!< Allocator type from template parameter.
//! 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 stack.
+ */
+ explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
+ GenericValue<Encoding, Allocator>(type), allocator_(allocator), ownAllocator_(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 stackAllocator Optional allocator for allocating memory for stack.
*/
@@ -1622,13 +1794,81 @@ public: allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
{
if (!allocator_)
- ownAllocator_ = allocator_ = new Allocator();
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
}
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
+ : ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document
+ allocator_(rhs.allocator_),
+ ownAllocator_(rhs.ownAllocator_),
+ stack_(std::move(rhs.stack_)),
+ parseResult_(rhs.parseResult_)
+ {
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.parseResult_ = ParseResult();
+ }
+#endif
+
~GenericDocument() {
- delete ownAllocator_;
+ Destroy();
}
+#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();
+
+ allocator_ = rhs.allocator_;
+ ownAllocator_ = rhs.ownAllocator_;
+ stack_ = std::move(rhs.stack_);
+ parseResult_ = rhs.parseResult_;
+
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.parseResult_ = ParseResult();
+
+ return *this;
+ }
+#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_NOEXCEPT { a.Swap(b); }
+
//!@name Parse from stream
//!@{
@@ -1641,13 +1881,13 @@ public: */
template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
GenericDocument& ParseStream(InputStream& is) {
- ValueType::SetNull(); // Remove existing root if exist
- GenericReader<SourceEncoding, Encoding, Allocator> reader(&GetAllocator());
+ 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
- this->RawAssign(*stack_.template Pop<ValueType>(1)); // Add this-> to prevent issue 13.
+ ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
}
return *this;
}
@@ -1660,7 +1900,7 @@ public: */
template <unsigned parseFlags, typename InputStream>
GenericDocument& ParseStream(InputStream& is) {
- return ParseStream<parseFlags,Encoding,InputStream>(is);
+ return ParseStream<parseFlags, Encoding, InputStream>(is);
}
//! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
@@ -1677,18 +1917,6 @@ public: //!@name Parse in-place from mutable string
//!@{
- //! Parse JSON text from a mutable string (with Encoding conversion)
- /*! \tparam parseFlags Combination of \ref ParseFlag.
- \tparam SourceEncoding Transcoding from input Encoding
- \param str Mutable zero-terminated string to be parsed.
- \return The document itself for fluent API.
- */
- template <unsigned parseFlags, typename SourceEncoding>
- GenericDocument& ParseInsitu(Ch* str) {
- GenericInsituStringStream<Encoding> s(str);
- return ParseStream<parseFlags | kParseInsituFlag, SourceEncoding>(s);
- }
-
//! Parse JSON text from a mutable string
/*! \tparam parseFlags Combination of \ref ParseFlag.
\param str Mutable zero-terminated string to be parsed.
@@ -1696,7 +1924,8 @@ public: */
template <unsigned parseFlags>
GenericDocument& ParseInsitu(Ch* str) {
- return ParseInsitu<parseFlags, Encoding>(str);
+ GenericInsituStringStream<Encoding> s(str);
+ return ParseStream<parseFlags | kParseInsituFlag>(s);
}
//! Parse JSON text from a mutable string (with \ref kParseDefaultFlags)
@@ -1704,7 +1933,7 @@ public: \return The document itself for fluent API.
*/
GenericDocument& ParseInsitu(Ch* str) {
- return ParseInsitu<kParseDefaultFlags, Encoding>(str);
+ return ParseInsitu<kParseDefaultFlags>(str);
}
//!@}
@@ -1717,7 +1946,7 @@ public: \param str Read-only zero-terminated string to be parsed.
*/
template <unsigned parseFlags, typename SourceEncoding>
- GenericDocument& Parse(const Ch* str) {
+ GenericDocument& Parse(const typename SourceEncoding::Ch* str) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<SourceEncoding> s(str);
return ParseStream<parseFlags, SourceEncoding>(s);
@@ -1738,16 +1967,6 @@ public: GenericDocument& Parse(const Ch* str) {
return Parse<kParseDefaultFlags>(str);
}
-
- GenericDocument& Parse(const Ch * str, size_t sz) {
- const char* buf = (const char*) str;
- size_t bufsz = sz * sizeof(Ch);
- MemoryStream ms(buf, bufsz);
- EncodedInputStream<Encoding, MemoryStream> is(ms);
- ParseStream(is);
- return *this;
- }
-
//!@}
//!@name Handling parse errors
@@ -1762,10 +1981,26 @@ public: //! Get the position of last parsing error in input, 0 otherwise.
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.
- Allocator& GetAllocator() { return *allocator_; }
+ Allocator& GetAllocator() {
+ RAPIDJSON_ASSERT(allocator_);
+ return *allocator_;
+ }
//! Get the capacity of stack in bytes.
size_t GetStackCapacity() const { return stack_.GetCapacity(); }
@@ -1808,7 +2043,7 @@ private: bool EndObject(SizeType memberCount) {
typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
- stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
+ stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, GetAllocator());
return true;
}
@@ -1821,6 +2056,8 @@ private: }
private:
+ //! Prohibit copying
+ GenericDocument(const GenericDocument&);
//! Prohibit assignment
GenericDocument& operator=(const GenericDocument&);
@@ -1833,6 +2070,10 @@ private: stack_.ShrinkToFit();
}
+ void Destroy() {
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
static const size_t kDefaultStackCapacity = 1024;
Allocator* allocator_;
Allocator* ownAllocator_;
@@ -1849,14 +2090,40 @@ template <typename SourceAllocator> inline
GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)
{
- GenericDocument<Encoding,Allocator> d(&allocator);
- rhs.Accept(d);
- RawAssign(*d.stack_.template Pop<GenericValue>(1));
+ switch (rhs.GetType()) {
+ case kObjectType:
+ case kArrayType: { // perform deep copy via SAX Handler
+ GenericDocument<Encoding,Allocator> d(&allocator);
+ rhs.Accept(d);
+ RawAssign(*d.stack_.template Pop<GenericValue>(1));
+ }
+ break;
+ case kStringType:
+ if (rhs.flags_ == kConstStringFlag) {
+ flags_ = rhs.flags_;
+ data_ = *reinterpret_cast<const Data*>(&rhs.data_);
+ } else {
+ SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
+ }
+ break;
+ default:
+ flags_ = rhs.flags_;
+ data_ = *reinterpret_cast<const Data*>(&rhs.data_);
+ break;
+ }
}
-} // namespace rapidjson
+RAPIDJSON_NAMESPACE_END
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
-#if defined(_MSC_VER) || defined(__GNUC__)
+#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
|