1 // Tencent is pleased to support the open source community by making RapidJSON available.
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
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
8 // http://opensource.org/licenses/MIT
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.
15 #ifndef RAPIDJSON_POINTER_H_
16 #define RAPIDJSON_POINTER_H_
19 #include "internal/itoa.h"
23 RAPIDJSON_DIAG_OFF(switch-enum)
24 #elif defined(_MSC_VER)
26 RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
29 RAPIDJSON_NAMESPACE_BEGIN
31 static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
33 //! Error code of parsing.
34 /*! \ingroup RAPIDJSON_ERRORS
35 \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
37 enum PointerParseErrorCode {
38 kPointerParseErrorNone = 0, //!< The parse is successful
40 kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
41 kPointerParseErrorInvalidEscape, //!< Invalid escape
42 kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
43 kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
46 ///////////////////////////////////////////////////////////////////////////////
49 //! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
51 This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer"
52 (https://tools.ietf.org/html/rfc6901).
54 A JSON pointer is for identifying a specific value in a JSON document
55 (GenericDocument). It can simplify coding of DOM tree manipulation, because it
56 can access multiple-level depth of DOM tree with single API call.
58 After it parses a string representation (e.g. "/foo/0" or URI fragment
59 representation (e.g. "#/foo/0") into its internal representation (tokens),
60 it can be used to resolve a specific value in multiple documents, or sub-tree
63 Contrary to GenericValue, Pointer can be copy constructed and copy assigned.
64 Apart from assignment, a Pointer cannot be modified after construction.
66 Although Pointer is very convenient, please aware that constructing Pointer
67 involves parsing and dynamic memory allocation. A special constructor with user-
68 supplied tokens eliminates these.
70 GenericPointer depends on GenericDocument and GenericValue.
72 \tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >
73 \tparam Allocator The allocator type for allocating memory for internal representation.
75 \note GenericPointer uses same encoding of ValueType.
76 However, Allocator of GenericPointer is independent of Allocator of Value.
78 template <typename ValueType, typename Allocator = CrtAllocator>
79 class GenericPointer {
81 typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
82 typedef typename ValueType::Ch Ch; //!< Character type from Value
84 //! A token is the basic units of internal representation.
86 A JSON pointer string representation "/foo/123" is parsed to two tokens:
87 "foo" and 123. 123 will be represented in both numeric form and string form.
88 They are resolved according to the actual value type (object or array).
90 For token that are not numbers, or the numeric value is out of bound
91 (greater than limits of SizeType), they are only treated as string form
92 (i.e. the token's index will be equal to kPointerInvalidIndex).
94 This struct is public so that user can create a Pointer without parsing and
95 allocation, using a special constructor.
98 const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character.
99 SizeType length; //!< Length of the name.
100 SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex.
103 //!@name Constructors and destructor.
106 //! Default constructor.
107 GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
109 //! Constructor that parses a string or URI fragment representation.
111 \param source A null-terminated, string or URI fragment representation of JSON pointer.
112 \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
114 explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
115 Parse(source, internal::StrLen(source));
118 #if RAPIDJSON_HAS_STDSTRING
119 //! Constructor that parses a string or URI fragment representation.
121 \param source A string or URI fragment representation of JSON pointer.
122 \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
123 \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
125 explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
126 Parse(source.c_str(), source.size());
130 //! Constructor that parses a string or URI fragment representation, with length of the source string.
132 \param source A string or URI fragment representation of JSON pointer.
133 \param length Length of source.
134 \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
135 \note Slightly faster than the overload without length.
137 GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
138 Parse(source, length);
141 //! Constructor with user-supplied tokens.
143 This constructor let user supplies const array of tokens.
144 This prevents the parsing process and eliminates allocation.
145 This is preferred for memory constrained environments.
147 \param tokens An constant array of tokens representing the JSON pointer.
148 \param tokenCount Number of tokens.
152 #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
153 #define INDEX(i) { #i, sizeof(#i) - 1, i }
155 static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
156 static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
157 // Equivalent to static const Pointer p("/foo/123");
163 GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
165 //! Copy constructor.
166 GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
170 //! Copy constructor.
171 GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
177 if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
178 Allocator::Free(tokens_);
179 RAPIDJSON_DELETE(ownAllocator_);
182 //! Assignment operator.
183 GenericPointer& operator=(const GenericPointer& rhs) {
185 // Do not delete ownAllcator
187 Allocator::Free(tokens_);
189 tokenCount_ = rhs.tokenCount_;
190 parseErrorOffset_ = rhs.parseErrorOffset_;
191 parseErrorCode_ = rhs.parseErrorCode_;
194 CopyFromRaw(rhs); // Normally parsed tokens.
196 tokens_ = rhs.tokens_; // User supplied const tokens.
203 //! Swap the content of this pointer with an other.
205 \param other The pointer to swap with.
206 \note Constant complexity.
208 GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT {
209 internal::Swap(allocator_, other.allocator_);
210 internal::Swap(ownAllocator_, other.ownAllocator_);
211 internal::Swap(nameBuffer_, other.nameBuffer_);
212 internal::Swap(tokens_, other.tokens_);
213 internal::Swap(tokenCount_, other.tokenCount_);
214 internal::Swap(parseErrorOffset_, other.parseErrorOffset_);
215 internal::Swap(parseErrorCode_, other.parseErrorCode_);
219 //! free-standing swap function helper
221 Helper function to enable support for common swap implementation pattern based on \c std::swap:
223 void swap(MyClass& a, MyClass& b) {
225 swap(a.pointer, b.pointer);
231 friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
235 //!@name Append token
238 //! Append a token and return a new Pointer
240 \param token Token to be appended.
241 \param allocator Allocator for the newly return Pointer.
242 \return A new Pointer with appended token.
244 GenericPointer Append(const Token& token, Allocator* allocator = 0) const {
246 r.allocator_ = allocator;
247 Ch *p = r.CopyFromRaw(*this, 1, token.length + 1);
248 std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));
249 r.tokens_[tokenCount_].name = p;
250 r.tokens_[tokenCount_].length = token.length;
251 r.tokens_[tokenCount_].index = token.index;
255 //! Append a name token with length, and return a new Pointer
257 \param name Name to be appended.
258 \param length Length of name.
259 \param allocator Allocator for the newly return Pointer.
260 \return A new Pointer with appended token.
262 GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {
263 Token token = { name, length, kPointerInvalidIndex };
264 return Append(token, allocator);
267 //! Append a name token without length, and return a new Pointer
269 \param name Name (const Ch*) to be appended.
270 \param allocator Allocator for the newly return Pointer.
271 \return A new Pointer with appended token.
273 template <typename T>
274 RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
275 Append(T* name, Allocator* allocator = 0) const {
276 return Append(name, internal::StrLen(name), allocator);
279 #if RAPIDJSON_HAS_STDSTRING
280 //! Append a name token, and return a new Pointer
282 \param name Name to be appended.
283 \param allocator Allocator for the newly return Pointer.
284 \return A new Pointer with appended token.
286 GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {
287 return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);
291 //! Append a index token, and return a new Pointer
293 \param index Index to be appended.
294 \param allocator Allocator for the newly return Pointer.
295 \return A new Pointer with appended token.
297 GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
299 char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);
300 SizeType length = static_cast<SizeType>(end - buffer);
301 buffer[length] = '\0';
303 if (sizeof(Ch) == 1) {
304 Token token = { reinterpret_cast<Ch*>(buffer), length, index };
305 return Append(token, allocator);
309 for (size_t i = 0; i <= length; i++)
310 name[i] = static_cast<Ch>(buffer[i]);
311 Token token = { name, length, index };
312 return Append(token, allocator);
316 //! Append a token by value, and return a new Pointer
318 \param token token to be appended.
319 \param allocator Allocator for the newly return Pointer.
320 \return A new Pointer with appended token.
322 GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const {
323 if (token.IsString())
324 return Append(token.GetString(), token.GetStringLength(), allocator);
326 RAPIDJSON_ASSERT(token.IsUint64());
327 RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));
328 return Append(static_cast<SizeType>(token.GetUint64()), allocator);
332 //!@name Handling Parse Error
335 //! Check whether this is a valid pointer.
336 bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }
338 //! Get the parsing error offset in code unit.
339 size_t GetParseErrorOffset() const { return parseErrorOffset_; }
341 //! Get the parsing error code.
342 PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
346 //! Get the allocator of this pointer.
347 Allocator& GetAllocator() { return *allocator_; }
352 //! Get the token array (const version only).
353 const Token* GetTokens() const { return tokens_; }
355 //! Get the number of tokens.
356 size_t GetTokenCount() const { return tokenCount_; }
360 //!@name Equality/inequality operators
363 //! Equality operator.
365 \note When any pointers are invalid, always returns false.
367 bool operator==(const GenericPointer& rhs) const {
368 if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)
371 for (size_t i = 0; i < tokenCount_; i++) {
372 if (tokens_[i].index != rhs.tokens_[i].index ||
373 tokens_[i].length != rhs.tokens_[i].length ||
374 (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))
383 //! Inequality operator.
385 \note When any pointers are invalid, always returns true.
387 bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
389 //! Less than operator.
391 \note Invalid pointers are always greater than valid ones.
393 bool operator<(const GenericPointer& rhs) const {
399 if (tokenCount_ != rhs.tokenCount_)
400 return tokenCount_ < rhs.tokenCount_;
402 for (size_t i = 0; i < tokenCount_; i++) {
403 if (tokens_[i].index != rhs.tokens_[i].index)
404 return tokens_[i].index < rhs.tokens_[i].index;
406 if (tokens_[i].length != rhs.tokens_[i].length)
407 return tokens_[i].length < rhs.tokens_[i].length;
409 if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length))
421 //! Stringify the pointer into string representation.
423 \tparam OutputStream Type of output stream.
424 \param os The output stream.
426 template<typename OutputStream>
427 bool Stringify(OutputStream& os) const {
428 return Stringify<false, OutputStream>(os);
431 //! Stringify the pointer into URI fragment representation.
433 \tparam OutputStream Type of output stream.
434 \param os The output stream.
436 template<typename OutputStream>
437 bool StringifyUriFragment(OutputStream& os) const {
438 return Stringify<true, OutputStream>(os);
443 //!@name Create value
446 //! Create a value in a subtree.
448 If the value is not exist, it creates all parent values and a JSON Null value.
449 So it always succeed and return the newly created or existing value.
451 Remind that it may change types of parents according to tokens, so it
452 potentially removes previously stored values. For example, if a document
453 was an array, and "/foo" is used to create a value, then the document
454 will be changed to an object, and all existing array elements are lost.
456 \param root Root value of a DOM subtree to be resolved. It can be any value other than document root.
457 \param allocator Allocator for creating the values if the specified value or its parents are not exist.
458 \param alreadyExist If non-null, it stores whether the resolved value is already exist.
459 \return The resolved newly created (a JSON Null value), or already exists value.
461 ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const {
462 RAPIDJSON_ASSERT(IsValid());
463 ValueType* v = &root;
465 for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
466 if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
467 v->PushBack(ValueType().Move(), allocator);
468 v = &((*v)[v->Size() - 1]);
472 if (t->index == kPointerInvalidIndex) { // must be object name
474 v->SetObject(); // Change to Object
476 else { // object name or array index
477 if (!v->IsArray() && !v->IsObject())
478 v->SetArray(); // Change to Array
482 if (t->index >= v->Size()) {
483 v->Reserve(t->index + 1, allocator);
484 while (t->index >= v->Size())
485 v->PushBack(ValueType().Move(), allocator);
488 v = &((*v)[t->index]);
491 typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
492 if (m == v->MemberEnd()) {
493 v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
495 v = &(--m)->value; // Assumes AddMember() appends at the end
505 *alreadyExist = exist;
510 //! Creates a value in a document.
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.
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);
526 //! Query a value in a subtree.
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.
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.
538 Use unresolvedTokenIndex to retrieve the token index.
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()) {
547 typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
548 if (m == v->MemberEnd())
554 if (t->index == kPointerInvalidIndex || t->index >= v->Size())
556 v = &((*v)[t->index]);
562 // Error: unresolved token
563 if (unresolvedTokenIndex)
564 *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
570 //! Query a const value in a const subtree.
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.
575 const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {
576 return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
581 //!@name Query a value with default
584 //! Query a value in a subtree with default value.
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.
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.
594 ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
596 ValueType& v = Create(root, allocator, &alreadyExist);
597 return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
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 {
603 ValueType& v = Create(root, allocator, &alreadyExist);
604 return alreadyExist ? v : v.SetString(defaultValue, allocator);
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 {
611 ValueType& v = Create(root, allocator, &alreadyExist);
612 return alreadyExist ? v : v.SetString(defaultValue, allocator);
616 //! Query a value in a subtree with default primitive value.
618 \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
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);
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());
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());
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());
646 //! Query a value in a document with default primitive value.
648 \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
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());
661 //! Set a value in a subtree, with move semantics.
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.
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.
671 ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
672 return Create(root, allocator) = value;
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);
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();
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();
692 //! Set a primitive value in a subtree.
694 \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
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();
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;
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());
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();
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();
728 //! Set a primitive value in a document.
730 \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
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;
740 //!@name Swap a value
743 //! Swap a value with a value in a subtree.
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.
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.
753 ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
754 return Create(root, allocator).Swap(value);
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);
765 //! Erase a value in a subtree.
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.
770 \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false.
772 bool Erase(ValueType& root) const {
773 RAPIDJSON_ASSERT(IsValid());
774 if (tokenCount_ == 0) // Cannot erase the root
777 ValueType* v = &root;
778 const Token* last = tokens_ + (tokenCount_ - 1);
779 for (const Token *t = tokens_; t != last; ++t) {
780 switch (v->GetType()) {
783 typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
784 if (m == v->MemberEnd())
790 if (t->index == kPointerInvalidIndex || t->index >= v->Size())
792 v = &((*v)[t->index]);
799 switch (v->GetType()) {
801 return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));
803 if (last->index == kPointerInvalidIndex || last->index >= v->Size())
805 v->Erase(v->Begin() + last->index);
813 //! Clone the content from rhs to this.
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.
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)();
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;
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));
834 if (nameBufferSize > 0) {
835 std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
838 // Adjust pointers to name buffer
839 std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
840 for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
843 return nameBuffer_ + nameBufferSize;
846 //! Check whether a character should be percent-encoded.
848 According to RFC 3986 2.3 Unreserved Characters.
849 \param c The character (code unit) to be tested.
851 bool NeedPercentEncode(Ch c) const {
852 return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~');
855 //! Parse a JSON String or its URI fragment representation into tokens.
856 #ifndef __clang__ // -Wdocumentation
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.
863 void Parse(const Ch* source, size_t length) {
864 RAPIDJSON_ASSERT(source != NULL);
865 RAPIDJSON_ASSERT(nameBuffer_ == 0);
866 RAPIDJSON_ASSERT(tokens_ == 0);
868 // Create own allocator if user did not supply.
870 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
872 // Count number of '/' as tokenCount
874 for (const Ch* s = source; s != source + length; s++)
878 Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));
879 Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
882 // Detect if it is a URI fragment
883 bool uriFragment = false;
884 if (source[i] == '#') {
889 if (i != length && source[i] != '/') {
890 parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;
895 RAPIDJSON_ASSERT(source[i] == '/');
899 bool isNumber = true;
901 while (i < length && source[i] != '/') {
904 // Decoding percent-encoding for URI fragment
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;
913 size_t len = os.PutEnd(begin);
924 else if (NeedPercentEncode(c)) {
925 parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode;
932 // Escaping "~0" -> '~', "~1" -> '/'
936 if (c == '0') c = '~';
937 else if (c == '1') c = '/';
939 parseErrorCode_ = kPointerParseErrorInvalidEscape;
945 parseErrorCode_ = kPointerParseErrorInvalidEscape;
950 // First check for index: all of characters are digit
951 if (c < '0' || c > '9')
956 token->length = static_cast<SizeType>(name - token->name);
957 if (token->length == 0)
959 *name++ = '\0'; // Null terminator
961 // Second check for index: more than one digit cannot have leading zero
962 if (isNumber && token->length > 1 && token->name[0] == '0')
965 // String to SizeType conversion
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
978 token->index = isNumber ? n : kPointerInvalidIndex;
982 RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer
983 parseErrorCode_ = kPointerParseErrorNone;
987 Allocator::Free(tokens_);
991 parseErrorOffset_ = i;
995 //! Stringify to string or URI fragment representation.
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.
1001 template<bool uriFragment, typename OutputStream>
1002 bool Stringify(OutputStream& os) const {
1003 RAPIDJSON_ASSERT(IsValid());
1008 for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
1010 for (size_t j = 0; j < t->length; j++) {
1016 else if (c == '/') {
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))
1026 j += source.Tell() - 1;
1035 //! A helper stream for decoding a percent-encoded sequence into code unit.
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().
1041 class PercentDecodeStream {
1043 typedef typename ValueType::Ch Ch;
1047 \param source Start of the stream
1048 \param end Past-the-end of the stream.
1050 PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}
1053 if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet
1059 for (int j = 0; j < 2; j++) {
1060 c = static_cast<Ch>(c << 4);
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);
1074 size_t Tell() const { return static_cast<size_t>(src_ - head_); }
1075 bool IsValid() const { return valid_; }
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.
1084 //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.
1085 template <typename OutputStream>
1086 class PercentEncodeStream {
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' };
1093 os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u >> 4]));
1094 os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u & 15]));
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.
1109 //! GenericPointer for Value (UTF-8, default allocator).
1110 typedef GenericPointer<Value> Pointer;
1112 //!@name Helper functions for GenericPointer
1115 //////////////////////////////////////////////////////////////////////////////
1117 template <typename T>
1118 typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) {
1119 return pointer.Create(root, a);
1122 template <typename T, typename CharType, size_t N>
1123 typename 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);
1127 // No allocator parameter
1129 template <typename DocumentType>
1130 typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) {
1131 return pointer.Create(document);
1134 template <typename DocumentType, typename CharType, size_t N>
1135 typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) {
1136 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);
1139 //////////////////////////////////////////////////////////////////////////////
1141 template <typename T>
1142 typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
1143 return pointer.Get(root, unresolvedTokenIndex);
1146 template <typename T>
1147 const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
1148 return pointer.Get(root, unresolvedTokenIndex);
1151 template <typename T, typename CharType, size_t N>
1152 typename 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);
1156 template <typename T, typename CharType, size_t N>
1157 const 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);
1161 //////////////////////////////////////////////////////////////////////////////
1163 template <typename T>
1164 typename 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);
1168 template <typename T>
1169 typename 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);
1173 #if RAPIDJSON_HAS_STDSTRING
1174 template <typename T>
1175 typename 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);
1180 template <typename T, typename T2>
1181 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
1182 GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {
1183 return pointer.GetWithDefault(root, defaultValue, a);
1186 template <typename T, typename CharType, size_t N>
1187 typename 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);
1191 template <typename T, typename CharType, size_t N>
1192 typename 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);
1196 #if RAPIDJSON_HAS_STDSTRING
1197 template <typename T, typename CharType, size_t N>
1198 typename 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);
1203 template <typename T, typename CharType, size_t N, typename T2>
1204 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
1205 GetValueByPointerWithDefault(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);
1209 // No allocator parameter
1211 template <typename DocumentType>
1212 typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) {
1213 return pointer.GetWithDefault(document, defaultValue);
1216 template <typename DocumentType>
1217 typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) {
1218 return pointer.GetWithDefault(document, defaultValue);
1221 #if RAPIDJSON_HAS_STDSTRING
1222 template <typename DocumentType>
1223 typename 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);
1228 template <typename DocumentType, typename T2>
1229 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
1230 GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {
1231 return pointer.GetWithDefault(document, defaultValue);
1234 template <typename DocumentType, typename CharType, size_t N>
1235 typename 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);
1239 template <typename DocumentType, typename CharType, size_t N>
1240 typename 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);
1244 #if RAPIDJSON_HAS_STDSTRING
1245 template <typename DocumentType, typename CharType, size_t N>
1246 typename 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);
1251 template <typename DocumentType, typename CharType, size_t N, typename T2>
1252 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
1253 GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {
1254 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1257 //////////////////////////////////////////////////////////////////////////////
1259 template <typename T>
1260 typename 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);
1264 template <typename T>
1265 typename 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);
1269 template <typename T>
1270 typename 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);
1274 #if RAPIDJSON_HAS_STDSTRING
1275 template <typename T>
1276 typename 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);
1281 template <typename T, typename T2>
1282 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
1283 SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {
1284 return pointer.Set(root, value, a);
1287 template <typename T, typename CharType, size_t N>
1288 typename 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);
1292 template <typename T, typename CharType, size_t N>
1293 typename 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);
1297 template <typename T, typename CharType, size_t N>
1298 typename 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);
1302 #if RAPIDJSON_HAS_STDSTRING
1303 template <typename T, typename CharType, size_t N>
1304 typename 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);
1309 template <typename T, typename CharType, size_t N, typename T2>
1310 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
1311 SetValueByPointer(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);
1315 // No allocator parameter
1317 template <typename DocumentType>
1318 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
1319 return pointer.Set(document, value);
1322 template <typename DocumentType>
1323 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) {
1324 return pointer.Set(document, value);
1327 template <typename DocumentType>
1328 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) {
1329 return pointer.Set(document, value);
1332 #if RAPIDJSON_HAS_STDSTRING
1333 template <typename DocumentType>
1334 typename 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);
1339 template <typename DocumentType, typename T2>
1340 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
1341 SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {
1342 return pointer.Set(document, value);
1345 template <typename DocumentType, typename CharType, size_t N>
1346 typename 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);
1350 template <typename DocumentType, typename CharType, size_t N>
1351 typename 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);
1355 template <typename DocumentType, typename CharType, size_t N>
1356 typename 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);
1360 #if RAPIDJSON_HAS_STDSTRING
1361 template <typename DocumentType, typename CharType, size_t N>
1362 typename 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);
1367 template <typename DocumentType, typename CharType, size_t N, typename T2>
1368 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
1369 SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {
1370 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1373 //////////////////////////////////////////////////////////////////////////////
1375 template <typename T>
1376 typename 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);
1380 template <typename T, typename CharType, size_t N>
1381 typename 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);
1385 template <typename DocumentType>
1386 typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
1387 return pointer.Swap(document, value);
1390 template <typename DocumentType, typename CharType, size_t N>
1391 typename 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);
1395 //////////////////////////////////////////////////////////////////////////////
1397 template <typename T>
1398 bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {
1399 return pointer.Erase(root);
1402 template <typename T, typename CharType, size_t N>
1403 bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
1404 return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);
1409 RAPIDJSON_NAMESPACE_END
1411 #if defined(__clang__) || defined(_MSC_VER)
1415 #endif // RAPIDJSON_POINTER_H_