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