pointer.h
Engine/source/persistence/rapidjson/pointer.h
Classes:
class
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
class
A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.
class
A token is the basic units of internal representation.
Helper functions for GenericPointer
DocumentType::ValueType &
CreateValueByPointer(DocumentType & document, const CharType(&) source)
DocumentType::ValueType &
CreateValueByPointer(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer)
T::ValueType &
CreateValueByPointer(T & root, const CharType(&) source, typename T::AllocatorType & a)
T::ValueType &
CreateValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer, typename T::AllocatorType & a)
bool
EraseValueByPointer(T & root, const CharType(&) source)
bool
EraseValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer)
const T::ValueType *
GetValueByPointer(const T & root, const CharType(&) source, size_t * unresolvedTokenIndex)
const T::ValueType *
GetValueByPointer(const T & root, const GenericPointer< typename T::ValueType > & pointer, size_t * unresolvedTokenIndex)
T::ValueType *
GetValueByPointer(T & root, const CharType(&) source, size_t * unresolvedTokenIndex)
T::ValueType *
GetValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer, size_t * unresolvedTokenIndex)
DocumentType::ValueType &
GetValueByPointerWithDefault(DocumentType & document, const CharType(&) source, const typename DocumentType::Ch * defaultValue)
DocumentType::ValueType &
GetValueByPointerWithDefault(DocumentType & document, const CharType(&) source, const typename DocumentType::ValueType & defaultValue)
DocumentType::ValueType &
GetValueByPointerWithDefault(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer, const typename DocumentType::Ch * defaultValue)
DocumentType::ValueType &
GetValueByPointerWithDefault(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer, const typename DocumentType::ValueType & defaultValue)
T::ValueType &
GetValueByPointerWithDefault(T & root, const CharType(&) source, const typename T::Ch * defaultValue, typename T::AllocatorType & a)
T::ValueType &
GetValueByPointerWithDefault(T & root, const CharType(&) source, const typename T::ValueType & defaultValue, typename T::AllocatorType & a)
T::ValueType &
GetValueByPointerWithDefault(T & root, const GenericPointer< typename T::ValueType > & pointer, const typename T::Ch * defaultValue, typename T::AllocatorType & a)
T::ValueType &
GetValueByPointerWithDefault(T & root, const GenericPointer< typename T::ValueType > & pointer, const typename T::ValueType & defaultValue, typename T::AllocatorType & a)
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr< internal::IsPointer< T2 >, internal::IsGenericValue< T2 > >) , (typename DocumentType::ValueType &) )
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr< internal::IsPointer< T2 >, internal::IsGenericValue< T2 > >) , (typename DocumentType::ValueType &) )
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr< internal::IsPointer< T2 >, internal::IsGenericValue< T2 > >) , (typename T::ValueType &) )
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr< internal::IsPointer< T2 >, internal::IsGenericValue< T2 > >) , (typename T::ValueType &) )
DocumentType::ValueType &
SetValueByPointer(DocumentType & document, const CharType(&) source, const typename DocumentType::Ch * value)
DocumentType::ValueType &
SetValueByPointer(DocumentType & document, const CharType(&) source, const typename DocumentType::ValueType & value)
DocumentType::ValueType &
SetValueByPointer(DocumentType & document, const CharType(&) source, typename DocumentType::ValueType & value)
DocumentType::ValueType &
SetValueByPointer(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer, const typename DocumentType::Ch * value)
DocumentType::ValueType &
SetValueByPointer(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer, const typename DocumentType::ValueType & value)
DocumentType::ValueType &
SetValueByPointer(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer, typename DocumentType::ValueType & value)
T::ValueType &
SetValueByPointer(T & root, const CharType(&) source, const typename T::Ch * value, typename T::AllocatorType & a)
T::ValueType &
SetValueByPointer(T & root, const CharType(&) source, const typename T::ValueType & value, typename T::AllocatorType & a)
T::ValueType &
SetValueByPointer(T & root, const CharType(&) source, typename T::ValueType & value, typename T::AllocatorType & a)
T::ValueType &
SetValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer, const typename T::Ch * value, typename T::AllocatorType & a)
T::ValueType &
SetValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer, const typename T::ValueType & value, typename T::AllocatorType & a)
T::ValueType &
SetValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer, typename T::ValueType & value, typename T::AllocatorType & a)
DocumentType::ValueType &
SwapValueByPointer(DocumentType & document, const CharType(&) source, typename DocumentType::ValueType & value)
DocumentType::ValueType &
SwapValueByPointer(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer, typename DocumentType::ValueType & value)
T::ValueType &
SwapValueByPointer(T & root, const CharType(&) source, typename T::ValueType & value, typename T::AllocatorType & a)
T::ValueType &
SwapValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer, typename T::ValueType & value, typename T::AllocatorType & a)
const GenericPointer< typename T::ValueType > T2 T::AllocatorType &
const GenericPointer< typename T::ValueType > T2
const GenericPointer< typename T::ValueType > &
const GenericPointer< typename T::ValueType > T2
Public Enumerations
enum
PointerParseErrorCode { kPointerParseErrorNone = 0 kPointerParseErrorTokenMustBeginWithSolidus kPointerParseErrorInvalidEscape kPointerParseErrorInvalidPercentEncoding kPointerParseErrorCharacterMustPercentEncode }
Error code of parsing.
Public Typedefs
Pointer
GenericPointer for Value (UTF-8, default allocator).
Public Variables
Represents an invalid index in GenericPointer::Token.
Detailed Description
Helper functions for GenericPointer
CreateValueByPointer(DocumentType & document, const CharType(&) source)
CreateValueByPointer(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer)
CreateValueByPointer(T & root, const CharType(&) source, typename T::AllocatorType & a)
CreateValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer, typename T::AllocatorType & a)
EraseValueByPointer(T & root, const CharType(&) source)
EraseValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer)
GetValueByPointer(const T & root, const CharType(&) source, size_t * unresolvedTokenIndex)
GetValueByPointer(const T & root, const GenericPointer< typename T::ValueType > & pointer, size_t * unresolvedTokenIndex)
GetValueByPointer(T & root, const CharType(&) source, size_t * unresolvedTokenIndex)
GetValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer, size_t * unresolvedTokenIndex)
GetValueByPointerWithDefault(DocumentType & document, const CharType(&) source, const typename DocumentType::Ch * defaultValue)
GetValueByPointerWithDefault(DocumentType & document, const CharType(&) source, const typename DocumentType::ValueType & defaultValue)
GetValueByPointerWithDefault(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer, const typename DocumentType::Ch * defaultValue)
GetValueByPointerWithDefault(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer, const typename DocumentType::ValueType & defaultValue)
GetValueByPointerWithDefault(T & root, const CharType(&) source, const typename T::Ch * defaultValue, typename T::AllocatorType & a)
GetValueByPointerWithDefault(T & root, const CharType(&) source, const typename T::ValueType & defaultValue, typename T::AllocatorType & a)
GetValueByPointerWithDefault(T & root, const GenericPointer< typename T::ValueType > & pointer, const typename T::Ch * defaultValue, typename T::AllocatorType & a)
GetValueByPointerWithDefault(T & root, const GenericPointer< typename T::ValueType > & pointer, const typename T::ValueType & defaultValue, typename T::AllocatorType & a)
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr< internal::IsPointer< T2 >, internal::IsGenericValue< T2 > >) , (typename DocumentType::ValueType &) )
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr< internal::IsPointer< T2 >, internal::IsGenericValue< T2 > >) , (typename DocumentType::ValueType &) )
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr< internal::IsPointer< T2 >, internal::IsGenericValue< T2 > >) , (typename T::ValueType &) )
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr< internal::IsPointer< T2 >, internal::IsGenericValue< T2 > >) , (typename T::ValueType &) )
SetValueByPointer(DocumentType & document, const CharType(&) source, const typename DocumentType::Ch * value)
SetValueByPointer(DocumentType & document, const CharType(&) source, const typename DocumentType::ValueType & value)
SetValueByPointer(DocumentType & document, const CharType(&) source, typename DocumentType::ValueType & value)
SetValueByPointer(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer, const typename DocumentType::Ch * value)
SetValueByPointer(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer, const typename DocumentType::ValueType & value)
SetValueByPointer(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer, typename DocumentType::ValueType & value)
SetValueByPointer(T & root, const CharType(&) source, const typename T::Ch * value, typename T::AllocatorType & a)
SetValueByPointer(T & root, const CharType(&) source, const typename T::ValueType & value, typename T::AllocatorType & a)
SetValueByPointer(T & root, const CharType(&) source, typename T::ValueType & value, typename T::AllocatorType & a)
SetValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer, const typename T::Ch * value, typename T::AllocatorType & a)
SetValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer, const typename T::ValueType & value, typename T::AllocatorType & a)
SetValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer, typename T::ValueType & value, typename T::AllocatorType & a)
SwapValueByPointer(DocumentType & document, const CharType(&) source, typename DocumentType::ValueType & value)
SwapValueByPointer(DocumentType & document, const GenericPointer< typename DocumentType::ValueType > & pointer, typename DocumentType::ValueType & value)
SwapValueByPointer(T & root, const CharType(&) source, typename T::ValueType & value, typename T::AllocatorType & a)
SwapValueByPointer(T & root, const GenericPointer< typename T::ValueType > & pointer, typename T::ValueType & value, typename T::AllocatorType & a)
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
const GenericPointer< typename T::ValueType > T2 defaultValue
const GenericPointer< typename T::ValueType > & pointer
const CharType(& source )[N]
const GenericPointer< typename T::ValueType > T2 value
Public Enumerations
PointerParseErrorCode
Enumerator
- kPointerParseErrorNone = 0
The parse is successful.
- kPointerParseErrorTokenMustBeginWithSolidus
A token must begin with a '/'.
- kPointerParseErrorInvalidEscape
Invalid escape.
- kPointerParseErrorInvalidPercentEncoding
Invalid percent encoding in URI fragment.
- kPointerParseErrorCharacterMustPercentEncode
A character must percent encoded in URI fragment.
Error code of parsing.
see:
GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
Public Typedefs
typedef GenericPointer< Value > Pointer
GenericPointer for Value (UTF-8, default allocator).
Public Variables
RAPIDJSON_NAMESPACE_BEGIN const SizeType kPointerInvalidIndex
Represents an invalid index in GenericPointer::Token.
1 2// Tencent is pleased to support the open source community by making RapidJSON available. 3// 4// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 5// 6// Licensed under the MIT License (the "License"); you may not use this file except 7// in compliance with the License. You may obtain a copy of the License at 8// 9// http://opensource.org/licenses/MIT 10// 11// Unless required by applicable law or agreed to in writing, software distributed 12// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13// CONDITIONS OF ANY KIND, either express or implied. See the License for the 14// specific language governing permissions and limitations under the License. 15 16#ifndef RAPIDJSON_POINTER_H_ 17#define RAPIDJSON_POINTER_H_ 18 19#include "document.h" 20#include "internal/itoa.h" 21 22#ifdef __clang__ 23RAPIDJSON_DIAG_PUSH 24RAPIDJSON_DIAG_OFF(switch-enum) 25#elif defined(_MSC_VER) 26RAPIDJSON_DIAG_PUSH 27RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated 28#endif 29 30RAPIDJSON_NAMESPACE_BEGIN 31 32static const SizeType kPointerInvalidIndex = ~<a href="/coding/file/rapidjson_8h/#rapidjson_8h_1a5ed6e6e67250fadbd041127e6386dcb5">SizeType</a>(0); //!< Represents an invalid index in GenericPointer::Token 33 34//! Error code of parsing. 35/*! \ingroup RAPIDJSON_ERRORS 36 \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode 37*/ 38enum PointerParseErrorCode { 39 kPointerParseErrorNone = 0, //!< The parse is successful 40 41 kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' 42 kPointerParseErrorInvalidEscape, //!< Invalid escape 43 kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment 44 kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment 45}; 46 47/////////////////////////////////////////////////////////////////////////////// 48// GenericPointer 49 50//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. 51/*! 52 This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" 53 (https://tools.ietf.org/html/rfc6901). 54 55 A JSON pointer is for identifying a specific value in a JSON document 56 (GenericDocument). It can simplify coding of DOM tree manipulation, because it 57 can access multiple-level depth of DOM tree with single API call. 58 59 After it parses a string representation (e.g. "/foo/0" or URI fragment 60 representation (e.g. "#/foo/0") into its internal representation (tokens), 61 it can be used to resolve a specific value in multiple documents, or sub-tree 62 of documents. 63 64 Contrary to GenericValue, Pointer can be copy constructed and copy assigned. 65 Apart from assignment, a Pointer cannot be modified after construction. 66 67 Although Pointer is very convenient, please aware that constructing Pointer 68 involves parsing and dynamic memory allocation. A special constructor with user- 69 supplied tokens eliminates these. 70 71 GenericPointer depends on GenericDocument and GenericValue. 72 73 \tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> > 74 \tparam Allocator The allocator type for allocating memory for internal representation. 75 76 \note GenericPointer uses same encoding of ValueType. 77 However, Allocator of GenericPointer is independent of Allocator of Value. 78*/ 79template <typename ValueType, typename Allocator = CrtAllocator> 80class GenericPointer { 81public: 82 typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value 83 typedef typename ValueType::Ch Ch; //!< Character type from Value 84 85 //! A token is the basic units of internal representation. 86 /*! 87 A JSON pointer string representation "/foo/123" is parsed to two tokens: 88 "foo" and 123. 123 will be represented in both numeric form and string form. 89 They are resolved according to the actual value type (object or array). 90 91 For token that are not numbers, or the numeric value is out of bound 92 (greater than limits of SizeType), they are only treated as string form 93 (i.e. the token's index will be equal to kPointerInvalidIndex). 94 95 This struct is public so that user can create a Pointer without parsing and 96 allocation, using a special constructor. 97 */ 98 struct Token { 99 const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. 100 SizeType length; //!< Length of the name. 101 SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. 102 }; 103 104 //!@name Constructors and destructor. 105 //@{ 106 107 //! Default constructor. 108 GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} 109 110 //! Constructor that parses a string or URI fragment representation. 111 /*! 112 \param source A null-terminated, string or URI fragment representation of JSON pointer. 113 \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. 114 */ 115 explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { 116 Parse(source, internal::StrLen(source)); 117 } 118 119#if RAPIDJSON_HAS_STDSTRING 120 //! Constructor that parses a string or URI fragment representation. 121 /*! 122 \param source A string or URI fragment representation of JSON pointer. 123 \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. 124 \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. 125 */ 126 explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { 127 Parse(source.c_str(), source.size()); 128 } 129#endif 130 131 //! Constructor that parses a string or URI fragment representation, with length of the source string. 132 /*! 133 \param source A string or URI fragment representation of JSON pointer. 134 \param length Length of source. 135 \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. 136 \note Slightly faster than the overload without length. 137 */ 138 GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { 139 Parse(source, length); 140 } 141 142 //! Constructor with user-supplied tokens. 143 /*! 144 This constructor let user supplies const array of tokens. 145 This prevents the parsing process and eliminates allocation. 146 This is preferred for memory constrained environments. 147 148 \param tokens An constant array of tokens representing the JSON pointer. 149 \param tokenCount Number of tokens. 150 151 \b Example 152 \code 153 #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } 154 #define INDEX(i) { #i, sizeof(#i) - 1, i } 155 156 static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; 157 static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); 158 // Equivalent to static const Pointer p("/foo/123"); 159 160 #undef NAME 161 #undef INDEX 162 \endcode 163 */ 164 GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} 165 166 //! Copy constructor. 167 GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { 168 *this = rhs; 169 } 170 171 //! Copy constructor. 172 GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { 173 *this = rhs; 174 } 175 176 //! Destructor. 177 ~GenericPointer() { 178 if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. 179 Allocator::Free(tokens_); 180 RAPIDJSON_DELETE(ownAllocator_); 181 } 182 183 //! Assignment operator. 184 GenericPointer& operator=(const GenericPointer& rhs) { 185 if (this != &rhs) { 186 // Do not delete ownAllcator 187 if (nameBuffer_) 188 Allocator::Free(tokens_); 189 190 tokenCount_ = rhs.tokenCount_; 191 parseErrorOffset_ = rhs.parseErrorOffset_; 192 parseErrorCode_ = rhs.parseErrorCode_; 193 194 if (rhs.nameBuffer_) 195 CopyFromRaw(rhs); // Normally parsed tokens. 196 else { 197 tokens_ = rhs.tokens_; // User supplied const tokens. 198 nameBuffer_ = 0; 199 } 200 } 201 return *this; 202 } 203 204 //! Swap the content of this pointer with an other. 205 /*! 206 \param other The pointer to swap with. 207 \note Constant complexity. 208 */ 209 GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT { 210 internal::Swap(allocator_, other.allocator_); 211 internal::Swap(ownAllocator_, other.ownAllocator_); 212 internal::Swap(nameBuffer_, other.nameBuffer_); 213 internal::Swap(tokens_, other.tokens_); 214 internal::Swap(tokenCount_, other.tokenCount_); 215 internal::Swap(parseErrorOffset_, other.parseErrorOffset_); 216 internal::Swap(parseErrorCode_, other.parseErrorCode_); 217 return *this; 218 } 219 220 //! free-standing swap function helper 221 /*! 222 Helper function to enable support for common swap implementation pattern based on \c std::swap: 223 \code 224 void swap(MyClass& a, MyClass& b) { 225 using std::swap; 226 swap(a.pointer, b.pointer); 227 // ... 228 } 229 \endcode 230 \see Swap() 231 */ 232 friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } 233 234 //@} 235 236 //!@name Append token 237 //@{ 238 239 //! Append a token and return a new Pointer 240 /*! 241 \param token Token to be appended. 242 \param allocator Allocator for the newly return Pointer. 243 \return A new Pointer with appended token. 244 */ 245 GenericPointer Append(const Token& token, Allocator* allocator = 0) const { 246 GenericPointer r; 247 r.allocator_ = allocator; 248 Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); 249 std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); 250 r.tokens_[tokenCount_].name = p; 251 r.tokens_[tokenCount_].length = token.length; 252 r.tokens_[tokenCount_].index = token.index; 253 return r; 254 } 255 256 //! Append a name token with length, and return a new Pointer 257 /*! 258 \param name Name to be appended. 259 \param length Length of name. 260 \param allocator Allocator for the newly return Pointer. 261 \return A new Pointer with appended token. 262 */ 263 GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const { 264 Token token = { name, length, kPointerInvalidIndex }; 265 return Append(token, allocator); 266 } 267 268 //! Append a name token without length, and return a new Pointer 269 /*! 270 \param name Name (const Ch*) to be appended. 271 \param allocator Allocator for the newly return Pointer. 272 \return A new Pointer with appended token. 273 */ 274 template <typename T> 275 RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer)) 276 Append(T* name, Allocator* allocator = 0) const { 277 return Append(name, internal::StrLen(name), allocator); 278 } 279 280#if RAPIDJSON_HAS_STDSTRING 281 //! Append a name token, and return a new Pointer 282 /*! 283 \param name Name to be appended. 284 \param allocator Allocator for the newly return Pointer. 285 \return A new Pointer with appended token. 286 */ 287 GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const { 288 return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator); 289 } 290#endif 291 292 //! Append a index token, and return a new Pointer 293 /*! 294 \param index Index to be appended. 295 \param allocator Allocator for the newly return Pointer. 296 \return A new Pointer with appended token. 297 */ 298 GenericPointer Append(SizeType index, Allocator* allocator = 0) const { 299 char buffer[21]; 300 char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); 301 SizeType length = static_cast<SizeType>(end - buffer); 302 buffer[length] = '\0'; 303 304 if (sizeof(Ch) == 1) { 305 Token token = { reinterpret_cast<Ch*>(buffer), length, index }; 306 return Append(token, allocator); 307 } 308 else { 309 Ch name[21]; 310 for (size_t i = 0; i <= length; i++) 311 name[i] = static_cast<Ch>(buffer[i]); 312 Token token = { name, length, index }; 313 return Append(token, allocator); 314 } 315 } 316 317 //! Append a token by value, and return a new Pointer 318 /*! 319 \param token token to be appended. 320 \param allocator Allocator for the newly return Pointer. 321 \return A new Pointer with appended token. 322 */ 323 GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const { 324 if (token.IsString()) 325 return Append(token.GetString(), token.GetStringLength(), allocator); 326 else { 327 RAPIDJSON_ASSERT(token.IsUint64()); 328 RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); 329 return Append(static_cast<SizeType>(token.GetUint64()), allocator); 330 } 331 } 332 333 //!@name Handling Parse Error 334 //@{ 335 336 //! Check whether this is a valid pointer. 337 bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; } 338 339 //! Get the parsing error offset in code unit. 340 size_t GetParseErrorOffset() const { return parseErrorOffset_; } 341 342 //! Get the parsing error code. 343 PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } 344 345 //@} 346 347 //! Get the allocator of this pointer. 348 Allocator& GetAllocator() { return *allocator_; } 349 350 //!@name Tokens 351 //@{ 352 353 //! Get the token array (const version only). 354 const Token* GetTokens() const { return tokens_; } 355 356 //! Get the number of tokens. 357 size_t GetTokenCount() const { return tokenCount_; } 358 359 //@} 360 361 //!@name Equality/inequality operators 362 //@{ 363 364 //! Equality operator. 365 /*! 366 \note When any pointers are invalid, always returns false. 367 */ 368 bool operator==(const GenericPointer& rhs) const { 369 if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) 370 return false; 371 372 for (size_t i = 0; i < tokenCount_; i++) { 373 if (tokens_[i].index != rhs.tokens_[i].index || 374 tokens_[i].length != rhs.tokens_[i].length || 375 (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) 376 { 377 return false; 378 } 379 } 380 381 return true; 382 } 383 384 //! Inequality operator. 385 /*! 386 \note When any pointers are invalid, always returns true. 387 */ 388 bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } 389 390 //! Less than operator. 391 /*! 392 \note Invalid pointers are always greater than valid ones. 393 */ 394 bool operator<(const GenericPointer& rhs) const { 395 if (!IsValid()) 396 return false; 397 if (!rhs.IsValid()) 398 return true; 399 400 if (tokenCount_ != rhs.tokenCount_) 401 return tokenCount_ < rhs.tokenCount_; 402 403 for (size_t i = 0; i < tokenCount_; i++) { 404 if (tokens_[i].index != rhs.tokens_[i].index) 405 return tokens_[i].index < rhs.tokens_[i].index; 406 407 if (tokens_[i].length != rhs.tokens_[i].length) 408 return tokens_[i].length < rhs.tokens_[i].length; 409 410 if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length)) 411 return cmp < 0; 412 } 413 414 return false; 415 } 416 417 //@} 418 419 //!@name Stringify 420 //@{ 421 422 //! Stringify the pointer into string representation. 423 /*! 424 \tparam OutputStream Type of output stream. 425 \param os The output stream. 426 */ 427 template<typename OutputStream> 428 bool Stringify(OutputStream& os) const { 429 return Stringify<false, OutputStream>(os); 430 } 431 432 //! Stringify the pointer into URI fragment representation. 433 /*! 434 \tparam OutputStream Type of output stream. 435 \param os The output stream. 436 */ 437 template<typename OutputStream> 438 bool StringifyUriFragment(OutputStream& os) const { 439 return Stringify<true, OutputStream>(os); 440 } 441 442 //@} 443 444 //!@name Create value 445 //@{ 446 447 //! Create a value in a subtree. 448 /*! 449 If the value is not exist, it creates all parent values and a JSON Null value. 450 So it always succeed and return the newly created or existing value. 451 452 Remind that it may change types of parents according to tokens, so it 453 potentially removes previously stored values. For example, if a document 454 was an array, and "/foo" is used to create a value, then the document 455 will be changed to an object, and all existing array elements are lost. 456 457 \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. 458 \param allocator Allocator for creating the values if the specified value or its parents are not exist. 459 \param alreadyExist If non-null, it stores whether the resolved value is already exist. 460 \return The resolved newly created (a JSON Null value), or already exists value. 461 */ 462 ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const { 463 RAPIDJSON_ASSERT(IsValid()); 464 ValueType* v = &root; 465 bool exist = true; 466 for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { 467 if (v->IsArray() && t->name[0] == '-' && t->length == 1) { 468 v->PushBack(ValueType().Move(), allocator); 469 v = &((*v)[v->Size() - 1]); 470 exist = false; 471 } 472 else { 473 if (t->index == kPointerInvalidIndex) { // must be object name 474 if (!v->IsObject()) 475 v->SetObject(); // Change to Object 476 } 477 else { // object name or array index 478 if (!v->IsArray() && !v->IsObject()) 479 v->SetArray(); // Change to Array 480 } 481 482 if (v->IsArray()) { 483 if (t->index >= v->Size()) { 484 v->Reserve(t->index + 1, allocator); 485 while (t->index >= v->Size()) 486 v->PushBack(ValueType().Move(), allocator); 487 exist = false; 488 } 489 v = &((*v)[t->index]); 490 } 491 else { 492 typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length)); 493 if (m == v->MemberEnd()) { 494 v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); 495 v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end 496 exist = false; 497 } 498 else 499 v = &m->value; 500 } 501 } 502 } 503 504 if (alreadyExist) 505 *alreadyExist = exist; 506 507 return *v; 508 } 509 510 //! Creates a value in a document. 511 /*! 512 \param document A document to be resolved. 513 \param alreadyExist If non-null, it stores whether the resolved value is already exist. 514 \return The resolved newly created, or already exists value. 515 */ 516 template <typename stackAllocator> 517 ValueType& Create(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, bool* alreadyExist = 0) const { 518 return Create(document, document.GetAllocator(), alreadyExist); 519 } 520 521 //@} 522 523 //!@name Query value 524 //@{ 525 526 //! Query a value in a subtree. 527 /*! 528 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. 529 \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. 530 \return Pointer to the value if it can be resolved. Otherwise null. 531 532 \note 533 There are only 3 situations when a value cannot be resolved: 534 1. A value in the path is not an array nor object. 535 2. An object value does not contain the token. 536 3. A token is out of range of an array value. 537 538 Use unresolvedTokenIndex to retrieve the token index. 539 */ 540 ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { 541 RAPIDJSON_ASSERT(IsValid()); 542 ValueType* v = &root; 543 for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { 544 switch (v->GetType()) { 545 case kObjectType: 546 { 547 typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length)); 548 if (m == v->MemberEnd()) 549 break; 550 v = &m->value; 551 } 552 continue; 553 case kArrayType: 554 if (t->index == kPointerInvalidIndex || t->index >= v->Size()) 555 break; 556 v = &((*v)[t->index]); 557 continue; 558 default: 559 break; 560 } 561 562 // Error: unresolved token 563 if (unresolvedTokenIndex) 564 *unresolvedTokenIndex = static_cast<size_t>(t - tokens_); 565 return 0; 566 } 567 return v; 568 } 569 570 //! Query a const value in a const subtree. 571 /*! 572 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. 573 \return Pointer to the value if it can be resolved. Otherwise null. 574 */ 575 const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { 576 return Get(const_cast<ValueType&>(root), unresolvedTokenIndex); 577 } 578 579 //@} 580 581 //!@name Query a value with default 582 //@{ 583 584 //! Query a value in a subtree with default value. 585 /*! 586 Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. 587 So that this function always succeed. 588 589 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. 590 \param defaultValue Default value to be cloned if the value was not exists. 591 \param allocator Allocator for creating the values if the specified value or its parents are not exist. 592 \see Create() 593 */ 594 ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { 595 bool alreadyExist; 596 ValueType& v = Create(root, allocator, &alreadyExist); 597 return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); 598 } 599 600 //! Query a value in a subtree with default null-terminated string. 601 ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { 602 bool alreadyExist; 603 ValueType& v = Create(root, allocator, &alreadyExist); 604 return alreadyExist ? v : v.SetString(defaultValue, allocator); 605 } 606 607#if RAPIDJSON_HAS_STDSTRING 608 //! Query a value in a subtree with default std::basic_string. 609 ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const { 610 bool alreadyExist; 611 ValueType& v = Create(root, allocator, &alreadyExist); 612 return alreadyExist ? v : v.SetString(defaultValue, allocator); 613 } 614#endif 615 616 //! Query a value in a subtree with default primitive value. 617 /*! 618 \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool 619 */ 620 template <typename T> 621 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) 622 GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { 623 return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); 624 } 625 626 //! Query a value in a document with default value. 627 template <typename stackAllocator> 628 ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& defaultValue) const { 629 return GetWithDefault(document, defaultValue, document.GetAllocator()); 630 } 631 632 //! Query a value in a document with default null-terminated string. 633 template <typename stackAllocator> 634 ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const { 635 return GetWithDefault(document, defaultValue, document.GetAllocator()); 636 } 637 638#if RAPIDJSON_HAS_STDSTRING 639 //! Query a value in a document with default std::basic_string. 640 template <typename stackAllocator> 641 ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const { 642 return GetWithDefault(document, defaultValue, document.GetAllocator()); 643 } 644#endif 645 646 //! Query a value in a document with default primitive value. 647 /*! 648 \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool 649 */ 650 template <typename T, typename stackAllocator> 651 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) 652 GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const { 653 return GetWithDefault(document, defaultValue, document.GetAllocator()); 654 } 655 656 //@} 657 658 //!@name Set a value 659 //@{ 660 661 //! Set a value in a subtree, with move semantics. 662 /*! 663 It creates all parents if they are not exist or types are different to the tokens. 664 So this function always succeeds but potentially remove existing values. 665 666 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. 667 \param value Value to be set. 668 \param allocator Allocator for creating the values if the specified value or its parents are not exist. 669 \see Create() 670 */ 671 ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { 672 return Create(root, allocator) = value; 673 } 674 675 //! Set a value in a subtree, with copy semantics. 676 ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const { 677 return Create(root, allocator).CopyFrom(value, allocator); 678 } 679 680 //! Set a null-terminated string in a subtree. 681 ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const { 682 return Create(root, allocator) = ValueType(value, allocator).Move(); 683 } 684 685#if RAPIDJSON_HAS_STDSTRING 686 //! Set a std::basic_string in a subtree. 687 ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const { 688 return Create(root, allocator) = ValueType(value, allocator).Move(); 689 } 690#endif 691 692 //! Set a primitive value in a subtree. 693 /*! 694 \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool 695 */ 696 template <typename T> 697 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) 698 Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { 699 return Create(root, allocator) = ValueType(value).Move(); 700 } 701 702 //! Set a value in a document, with move semantics. 703 template <typename stackAllocator> 704 ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const { 705 return Create(document) = value; 706 } 707 708 //! Set a value in a document, with copy semantics. 709 template <typename stackAllocator> 710 ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& value) const { 711 return Create(document).CopyFrom(value, document.GetAllocator()); 712 } 713 714 //! Set a null-terminated string in a document. 715 template <typename stackAllocator> 716 ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* value) const { 717 return Create(document) = ValueType(value, document.GetAllocator()).Move(); 718 } 719 720#if RAPIDJSON_HAS_STDSTRING 721 //! Sets a std::basic_string in a document. 722 template <typename stackAllocator> 723 ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const { 724 return Create(document) = ValueType(value, document.GetAllocator()).Move(); 725 } 726#endif 727 728 //! Set a primitive value in a document. 729 /*! 730 \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool 731 */ 732 template <typename T, typename stackAllocator> 733 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) 734 Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const { 735 return Create(document) = value; 736 } 737 738 //@} 739 740 //!@name Swap a value 741 //@{ 742 743 //! Swap a value with a value in a subtree. 744 /*! 745 It creates all parents if they are not exist or types are different to the tokens. 746 So this function always succeeds but potentially remove existing values. 747 748 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. 749 \param value Value to be swapped. 750 \param allocator Allocator for creating the values if the specified value or its parents are not exist. 751 \see Create() 752 */ 753 ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { 754 return Create(root, allocator).Swap(value); 755 } 756 757 //! Swap a value with a value in a document. 758 template <typename stackAllocator> 759 ValueType& Swap(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const { 760 return Create(document).Swap(value); 761 } 762 763 //@} 764 765 //! Erase a value in a subtree. 766 /*! 767 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. 768 \return Whether the resolved value is found and erased. 769 770 \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. 771 */ 772 bool Erase(ValueType& root) const { 773 RAPIDJSON_ASSERT(IsValid()); 774 if (tokenCount_ == 0) // Cannot erase the root 775 return false; 776 777 ValueType* v = &root; 778 const Token* last = tokens_ + (tokenCount_ - 1); 779 for (const Token *t = tokens_; t != last; ++t) { 780 switch (v->GetType()) { 781 case kObjectType: 782 { 783 typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length)); 784 if (m == v->MemberEnd()) 785 return false; 786 v = &m->value; 787 } 788 break; 789 case kArrayType: 790 if (t->index == kPointerInvalidIndex || t->index >= v->Size()) 791 return false; 792 v = &((*v)[t->index]); 793 break; 794 default: 795 return false; 796 } 797 } 798 799 switch (v->GetType()) { 800 case kObjectType: 801 return v->EraseMember(GenericStringRef<Ch>(last->name, last->length)); 802 case kArrayType: 803 if (last->index == kPointerInvalidIndex || last->index >= v->Size()) 804 return false; 805 v->Erase(v->Begin() + last->index); 806 return true; 807 default: 808 return false; 809 } 810 } 811 812private: 813 //! Clone the content from rhs to this. 814 /*! 815 \param rhs Source pointer. 816 \param extraToken Extra tokens to be allocated. 817 \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. 818 \return Start of non-occupied name buffer, for storing extra names. 819 */ 820 Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { 821 if (!allocator_) // allocator is independently owned. 822 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); 823 824 size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens 825 for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) 826 nameBufferSize += t->length; 827 828 tokenCount_ = rhs.tokenCount_ + extraToken; 829 tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); 830 nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_); 831 if (rhs.tokenCount_ > 0) { 832 std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); 833 } 834 if (nameBufferSize > 0) { 835 std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); 836 } 837 838 // Adjust pointers to name buffer 839 std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; 840 for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) 841 t->name += diff; 842 843 return nameBuffer_ + nameBufferSize; 844 } 845 846 //! Check whether a character should be percent-encoded. 847 /*! 848 According to RFC 3986 2.3 Unreserved Characters. 849 \param c The character (code unit) to be tested. 850 */ 851 bool NeedPercentEncode(Ch c) const { 852 return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); 853 } 854 855 //! Parse a JSON String or its URI fragment representation into tokens. 856#ifndef __clang__ // -Wdocumentation 857 /*! 858 \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. 859 \param length Length of the source string. 860 \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. 861 */ 862#endif 863 void Parse(const Ch* source, size_t length) { 864 RAPIDJSON_ASSERT(source != NULL); 865 RAPIDJSON_ASSERT(nameBuffer_ == 0); 866 RAPIDJSON_ASSERT(tokens_ == 0); 867 868 // Create own allocator if user did not supply. 869 if (!allocator_) 870 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); 871 872 // Count number of '/' as tokenCount 873 tokenCount_ = 0; 874 for (const Ch* s = source; s != source + length; s++) 875 if (*s == '/') 876 tokenCount_++; 877 878 Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); 879 Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_); 880 size_t i = 0; 881 882 // Detect if it is a URI fragment 883 bool uriFragment = false; 884 if (source[i] == '#') { 885 uriFragment = true; 886 i++; 887 } 888 889 if (i != length && source[i] != '/') { 890 parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; 891 goto error; 892 } 893 894 while (i < length) { 895 RAPIDJSON_ASSERT(source[i] == '/'); 896 i++; // consumes '/' 897 898 token->name = name; 899 bool isNumber = true; 900 901 while (i < length && source[i] != '/') { 902 Ch c = source[i]; 903 if (uriFragment) { 904 // Decoding percent-encoding for URI fragment 905 if (c == '%') { 906 PercentDecodeStream is(&source[i], source + length); 907 GenericInsituStringStream<EncodingType> os(name); 908 Ch* begin = os.PutBegin(); 909 if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) || !is.IsValid()) { 910 parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; 911 goto error; 912 } 913 size_t len = os.PutEnd(begin); 914 i += is.Tell() - 1; 915 if (len == 1) 916 c = *name; 917 else { 918 name += len; 919 isNumber = false; 920 i++; 921 continue; 922 } 923 } 924 else if (NeedPercentEncode(c)) { 925 parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; 926 goto error; 927 } 928 } 929 930 i++; 931 932 // Escaping "~0" -> '~', "~1" -> '/' 933 if (c == '~') { 934 if (i < length) { 935 c = source[i]; 936 if (c == '0') c = '~'; 937 else if (c == '1') c = '/'; 938 else { 939 parseErrorCode_ = kPointerParseErrorInvalidEscape; 940 goto error; 941 } 942 i++; 943 } 944 else { 945 parseErrorCode_ = kPointerParseErrorInvalidEscape; 946 goto error; 947 } 948 } 949 950 // First check for index: all of characters are digit 951 if (c < '0' || c > '9') 952 isNumber = false; 953 954 *name++ = c; 955 } 956 token->length = static_cast<SizeType>(name - token->name); 957 if (token->length == 0) 958 isNumber = false; 959 *name++ = '\0'; // Null terminator 960 961 // Second check for index: more than one digit cannot have leading zero 962 if (isNumber && token->length > 1 && token->name[0] == '0') 963 isNumber = false; 964 965 // String to SizeType conversion 966 SizeType n = 0; 967 if (isNumber) { 968 for (size_t j = 0; j < token->length; j++) { 969 SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0'); 970 if (m < n) { // overflow detection 971 isNumber = false; 972 break; 973 } 974 n = m; 975 } 976 } 977 978 token->index = isNumber ? n : kPointerInvalidIndex; 979 token++; 980 } 981 982 RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer 983 parseErrorCode_ = kPointerParseErrorNone; 984 return; 985 986 error: 987 Allocator::Free(tokens_); 988 nameBuffer_ = 0; 989 tokens_ = 0; 990 tokenCount_ = 0; 991 parseErrorOffset_ = i; 992 return; 993 } 994 995 //! Stringify to string or URI fragment representation. 996 /*! 997 \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. 998 \tparam OutputStream type of output stream. 999 \param os The output stream. 1000 */ 1001 template<bool uriFragment, typename OutputStream> 1002 bool Stringify(OutputStream& os) const { 1003 RAPIDJSON_ASSERT(IsValid()); 1004 1005 if (uriFragment) 1006 os.Put('#'); 1007 1008 for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { 1009 os.Put('/'); 1010 for (size_t j = 0; j < t->length; j++) { 1011 Ch c = t->name[j]; 1012 if (c == '~') { 1013 os.Put('~'); 1014 os.Put('0'); 1015 } 1016 else if (c == '/') { 1017 os.Put('~'); 1018 os.Put('1'); 1019 } 1020 else if (uriFragment && NeedPercentEncode(c)) { 1021 // Transcode to UTF8 sequence 1022 GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]); 1023 PercentEncodeStream<OutputStream> target(os); 1024 if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target)) 1025 return false; 1026 j += source.Tell() - 1; 1027 } 1028 else 1029 os.Put(c); 1030 } 1031 } 1032 return true; 1033 } 1034 1035 //! A helper stream for decoding a percent-encoded sequence into code unit. 1036 /*! 1037 This stream decodes %XY triplet into code unit (0-255). 1038 If it encounters invalid characters, it sets output code unit as 0 and 1039 mark invalid, and to be checked by IsValid(). 1040 */ 1041 class PercentDecodeStream { 1042 public: 1043 typedef typename ValueType::Ch Ch; 1044 1045 //! Constructor 1046 /*! 1047 \param source Start of the stream 1048 \param end Past-the-end of the stream. 1049 */ 1050 PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {} 1051 1052 Ch Take() { 1053 if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet 1054 valid_ = false; 1055 return 0; 1056 } 1057 src_++; 1058 Ch c = 0; 1059 for (int j = 0; j < 2; j++) { 1060 c = static_cast<Ch>(c << 4); 1061 Ch h = *src_; 1062 if (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0'); 1063 else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10); 1064 else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10); 1065 else { 1066 valid_ = false; 1067 return 0; 1068 } 1069 src_++; 1070 } 1071 return c; 1072 } 1073 1074 size_t Tell() const { return static_cast<size_t>(src_ - head_); } 1075 bool IsValid() const { return valid_; } 1076 1077 private: 1078 const Ch* src_; //!< Current read position. 1079 const Ch* head_; //!< Original head of the string. 1080 const Ch* end_; //!< Past-the-end position. 1081 bool valid_; //!< Whether the parsing is valid. 1082 }; 1083 1084 //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. 1085 template <typename OutputStream> 1086 class PercentEncodeStream { 1087 public: 1088 PercentEncodeStream(OutputStream& os) : os_(os) {} 1089 void Put(char c) { // UTF-8 must be byte 1090 unsigned char u = static_cast<unsigned char>(c); 1091 static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 1092 os_.Put('%'); 1093 os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u >> 4])); 1094 os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u & 15])); 1095 } 1096 private: 1097 OutputStream& os_; 1098 }; 1099 1100 Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. 1101 Allocator* ownAllocator_; //!< Allocator owned by this Pointer. 1102 Ch* nameBuffer_; //!< A buffer containing all names in tokens. 1103 Token* tokens_; //!< A list of tokens. 1104 size_t tokenCount_; //!< Number of tokens in tokens_. 1105 size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. 1106 PointerParseErrorCode parseErrorCode_; //!< Parsing error code. 1107}; 1108 1109//! GenericPointer for Value (UTF-8, default allocator). 1110typedef GenericPointer<Value> Pointer; 1111 1112//!@name Helper functions for GenericPointer 1113//@{ 1114 1115////////////////////////////////////////////////////////////////////////////// 1116 1117template <typename T> 1118typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) { 1119 return pointer.Create(root, a); 1120} 1121 1122template <typename T, typename CharType, size_t N> 1123typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { 1124 return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a); 1125} 1126 1127// No allocator parameter 1128 1129template <typename DocumentType> 1130typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) { 1131 return pointer.Create(document); 1132} 1133 1134template <typename DocumentType, typename CharType, size_t N> 1135typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { 1136 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document); 1137} 1138 1139////////////////////////////////////////////////////////////////////////////// 1140 1141template <typename T> 1142typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) { 1143 return pointer.Get(root, unresolvedTokenIndex); 1144} 1145 1146template <typename T> 1147const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) { 1148 return pointer.Get(root, unresolvedTokenIndex); 1149} 1150 1151template <typename T, typename CharType, size_t N> 1152typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) { 1153 return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex); 1154} 1155 1156template <typename T, typename CharType, size_t N> 1157const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { 1158 return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex); 1159} 1160 1161////////////////////////////////////////////////////////////////////////////// 1162 1163template <typename T> 1164typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { 1165 return pointer.GetWithDefault(root, defaultValue, a); 1166} 1167 1168template <typename T> 1169typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) { 1170 return pointer.GetWithDefault(root, defaultValue, a); 1171} 1172 1173#if RAPIDJSON_HAS_STDSTRING 1174template <typename T> 1175typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) { 1176 return pointer.GetWithDefault(root, defaultValue, a); 1177} 1178#endif 1179 1180template <typename T, typename T2> 1181RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&)) 1182GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) { 1183 return pointer.GetWithDefault(root, defaultValue, a); 1184} 1185 1186template <typename T, typename CharType, size_t N> 1187typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { 1188 return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a); 1189} 1190 1191template <typename T, typename CharType, size_t N> 1192typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { 1193 return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a); 1194} 1195 1196#if RAPIDJSON_HAS_STDSTRING 1197template <typename T, typename CharType, size_t N> 1198typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) { 1199 return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a); 1200} 1201#endif 1202 1203template <typename T, typename CharType, size_t N, typename T2> 1204RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&)) 1205GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { 1206 return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a); 1207} 1208 1209// No allocator parameter 1210 1211template <typename DocumentType> 1212typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) { 1213 return pointer.GetWithDefault(document, defaultValue); 1214} 1215 1216template <typename DocumentType> 1217typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) { 1218 return pointer.GetWithDefault(document, defaultValue); 1219} 1220 1221#if RAPIDJSON_HAS_STDSTRING 1222template <typename DocumentType> 1223typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) { 1224 return pointer.GetWithDefault(document, defaultValue); 1225} 1226#endif 1227 1228template <typename DocumentType, typename T2> 1229RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&)) 1230GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) { 1231 return pointer.GetWithDefault(document, defaultValue); 1232} 1233 1234template <typename DocumentType, typename CharType, size_t N> 1235typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { 1236 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue); 1237} 1238 1239template <typename DocumentType, typename CharType, size_t N> 1240typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { 1241 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue); 1242} 1243 1244#if RAPIDJSON_HAS_STDSTRING 1245template <typename DocumentType, typename CharType, size_t N> 1246typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) { 1247 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue); 1248} 1249#endif 1250 1251template <typename DocumentType, typename CharType, size_t N, typename T2> 1252RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&)) 1253GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { 1254 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue); 1255} 1256 1257////////////////////////////////////////////////////////////////////////////// 1258 1259template <typename T> 1260typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { 1261 return pointer.Set(root, value, a); 1262} 1263 1264template <typename T> 1265typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) { 1266 return pointer.Set(root, value, a); 1267} 1268 1269template <typename T> 1270typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* value, typename T::AllocatorType& a) { 1271 return pointer.Set(root, value, a); 1272} 1273 1274#if RAPIDJSON_HAS_STDSTRING 1275template <typename T> 1276typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) { 1277 return pointer.Set(root, value, a); 1278} 1279#endif 1280 1281template <typename T, typename T2> 1282RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&)) 1283SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) { 1284 return pointer.Set(root, value, a); 1285} 1286 1287template <typename T, typename CharType, size_t N> 1288typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { 1289 return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); 1290} 1291 1292template <typename T, typename CharType, size_t N> 1293typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { 1294 return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); 1295} 1296 1297template <typename T, typename CharType, size_t N> 1298typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { 1299 return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); 1300} 1301 1302#if RAPIDJSON_HAS_STDSTRING 1303template <typename T, typename CharType, size_t N> 1304typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) { 1305 return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); 1306} 1307#endif 1308 1309template <typename T, typename CharType, size_t N, typename T2> 1310RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&)) 1311SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { 1312 return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); 1313} 1314 1315// No allocator parameter 1316 1317template <typename DocumentType> 1318typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) { 1319 return pointer.Set(document, value); 1320} 1321 1322template <typename DocumentType> 1323typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) { 1324 return pointer.Set(document, value); 1325} 1326 1327template <typename DocumentType> 1328typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) { 1329 return pointer.Set(document, value); 1330} 1331 1332#if RAPIDJSON_HAS_STDSTRING 1333template <typename DocumentType> 1334typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) { 1335 return pointer.Set(document, value); 1336} 1337#endif 1338 1339template <typename DocumentType, typename T2> 1340RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&)) 1341SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) { 1342 return pointer.Set(document, value); 1343} 1344 1345template <typename DocumentType, typename CharType, size_t N> 1346typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { 1347 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); 1348} 1349 1350template <typename DocumentType, typename CharType, size_t N> 1351typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { 1352 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); 1353} 1354 1355template <typename DocumentType, typename CharType, size_t N> 1356typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { 1357 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); 1358} 1359 1360#if RAPIDJSON_HAS_STDSTRING 1361template <typename DocumentType, typename CharType, size_t N> 1362typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) { 1363 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); 1364} 1365#endif 1366 1367template <typename DocumentType, typename CharType, size_t N, typename T2> 1368RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&)) 1369SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { 1370 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); 1371} 1372 1373////////////////////////////////////////////////////////////////////////////// 1374 1375template <typename T> 1376typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { 1377 return pointer.Swap(root, value, a); 1378} 1379 1380template <typename T, typename CharType, size_t N> 1381typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { 1382 return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a); 1383} 1384 1385template <typename DocumentType> 1386typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) { 1387 return pointer.Swap(document, value); 1388} 1389 1390template <typename DocumentType, typename CharType, size_t N> 1391typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { 1392 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value); 1393} 1394 1395////////////////////////////////////////////////////////////////////////////// 1396 1397template <typename T> 1398bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) { 1399 return pointer.Erase(root); 1400} 1401 1402template <typename T, typename CharType, size_t N> 1403bool EraseValueByPointer(T& root, const CharType(&source)[N]) { 1404 return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root); 1405} 1406 1407//@} 1408 1409RAPIDJSON_NAMESPACE_END 1410 1411#if defined(__clang__) || defined(_MSC_VER) 1412RAPIDJSON_DIAG_POP 1413#endif 1414 1415#endif // RAPIDJSON_POINTER_H_ 1416