@ -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 , k Cons tStringFlag,
kNullFlag , kFalseFlag , kTrueFlag , kObjectFlag , kArrayFlag , k Shor tStringFlag,
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.1 x , 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__)
# if def __GNUC__
RAPIDJSON_DIAG_POP
# endif