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 
21 RAPIDJSON_NAMESPACE_BEGIN
22 
23 static 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 */
29 enum 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 */
70 template <typename ValueType, typename Allocator = CrtAllocator>
71 class GenericPointer {
72 public:
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.
GenericPointer()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     */
allocator_(allocator)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     */
allocator_(allocator)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     */
allocator_(allocator)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     */
GenericPointer(const Token * tokens,size_t tokenCount)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.
GenericPointer(const GenericPointer & rhs)158     GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
159         *this = rhs;
160     }
161 
162     //! Destructor.
~GenericPointer()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.
IsValid()292     bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }
293 
294     //! Get the parsing error offset in code unit.
GetParseErrorOffset()295     size_t GetParseErrorOffset() const { return parseErrorOffset_; }
296 
297     //! Get the parsing error code.
GetParseErrorCode()298     PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
299 
300     //@}
301 
302     //!@name Tokens
303     //@{
304 
305     //! Get the token array (const version only).
GetTokens()306     const Token* GetTokens() const { return tokens_; }
307 
308     //! Get the number of tokens.
GetTokenCount()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>
Stringify(OutputStream & os)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>
StringifyUriFragment(OutputStream & os)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     */
Get(ValueType & root)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     */
Get(const ValueType & root)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     */
GetWithDefault(ValueType & root,const ValueType & defaultValue,typename ValueType::AllocatorType & allocator)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.
GetWithDefault(ValueType & root,const Ch * defaultValue,typename ValueType::AllocatorType & allocator)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.
GetWithDefault(ValueType & root,const std::basic_string<Ch> & defaultValue,typename ValueType::AllocatorType & allocator)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&))
GetWithDefault(ValueType & root,T defaultValue,typename ValueType::AllocatorType & allocator)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>
GetWithDefault(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,const ValueType & defaultValue)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>
GetWithDefault(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,const Ch * defaultValue)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>
GetWithDefault(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,const std::basic_string<Ch> & defaultValue)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&))
GetWithDefault(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,T defaultValue)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     */
Set(ValueType & root,ValueType & value,typename ValueType::AllocatorType & allocator)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.
Set(ValueType & root,const ValueType & value,typename ValueType::AllocatorType & allocator)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.
Set(ValueType & root,const Ch * value,typename ValueType::AllocatorType & allocator)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.
Set(ValueType & root,const std::basic_string<Ch> & value,typename ValueType::AllocatorType & allocator)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&))
Set(ValueType & root,T value,typename ValueType::AllocatorType & allocator)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>
Set(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,ValueType & value)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>
Set(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,const ValueType & value)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>
Set(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,const Ch * value)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>
Set(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,const std::basic_string<Ch> & value)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&))
Set(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,T value)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     */
Swap(ValueType & root,ValueType & value,typename ValueType::AllocatorType & allocator)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>
Swap(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,ValueType & value)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     */
Erase(ValueType & root)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 
722 private:
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     */
NeedPercentEncode(Ch c)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     */
Parse(const Ch * source,size_t length)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>
Stringify(OutputStream & os)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         */
PercentDecodeStream(const Ch * source,const Ch * end)952         PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}
953 
Take()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 
Tell()976         size_t Tell() const { return src_ - head_; }
IsValid()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:
PercentEncodeStream(OutputStream & os)990         PercentEncodeStream(OutputStream& os) : os_(os) {}
Put(char c)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).
1012 typedef GenericPointer<Value> Pointer;
1013 
1014 //!@name Helper functions for GenericPointer
1015 //@{
1016 
1017 //////////////////////////////////////////////////////////////////////////////
1018 
1019 template <typename T>
CreateValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,typename T::AllocatorType & a)1020 typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) {
1021     return pointer.Create(root, a);
1022 }
1023 
1024 template <typename T, typename CharType, size_t N>
CreateValueByPointer(T & root,const CharType (& source)[N],typename T::AllocatorType & a)1025 typename 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 
1031 template <typename DocumentType>
CreateValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer)1032 typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) {
1033     return pointer.Create(document);
1034 }
1035 
1036 template <typename DocumentType, typename CharType, size_t N>
CreateValueByPointer(DocumentType & document,const CharType (& source)[N])1037 typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) {
1038     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);
1039 }
1040 
1041 //////////////////////////////////////////////////////////////////////////////
1042 
1043 template <typename T>
GetValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer)1044 typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {
1045     return pointer.Get(root);
1046 }
1047 
1048 template <typename T>
GetValueByPointer(const T & root,const GenericPointer<typename T::ValueType> & pointer)1049 const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer) {
1050     return pointer.Get(root);
1051 }
1052 
1053 template <typename T, typename CharType, size_t N>
GetValueByPointer(T & root,const CharType (& source)[N])1054 typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N]) {
1055     return GenericPointer<typename T::ValueType>(source, N - 1).Get(root);
1056 }
1057 
1058 template <typename T, typename CharType, size_t N>
GetValueByPointer(const T & root,const CharType (& source)[N])1059 const 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 
1065 template <typename T>
GetValueByPointerWithDefault(T & root,const GenericPointer<typename T::ValueType> & pointer,const typename T::ValueType & defaultValue,typename T::AllocatorType & a)1066 typename 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 
1070 template <typename T>
GetValueByPointerWithDefault(T & root,const GenericPointer<typename T::ValueType> & pointer,const typename T::Ch * defaultValue,typename T::AllocatorType & a)1071 typename 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
1076 template <typename T>
GetValueByPointerWithDefault(T & root,const GenericPointer<typename T::ValueType> & pointer,const std::basic_string<typename T::Ch> & defaultValue,typename T::AllocatorType & a)1077 typename 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 
1082 template <typename T, typename T2>
1083 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
GetValueByPointerWithDefault(T & root,const GenericPointer<typename T::ValueType> & pointer,T2 defaultValue,typename T::AllocatorType & a)1084 GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {
1085     return pointer.GetWithDefault(root, defaultValue, a);
1086 }
1087 
1088 template <typename T, typename CharType, size_t N>
GetValueByPointerWithDefault(T & root,const CharType (& source)[N],const typename T::ValueType & defaultValue,typename T::AllocatorType & a)1089 typename 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 
1093 template <typename T, typename CharType, size_t N>
GetValueByPointerWithDefault(T & root,const CharType (& source)[N],const typename T::Ch * defaultValue,typename T::AllocatorType & a)1094 typename 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
1099 template <typename T, typename CharType, size_t N>
GetValueByPointerWithDefault(T & root,const CharType (& source)[N],const std::basic_string<typename T::Ch> & defaultValue,typename T::AllocatorType & a)1100 typename 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 
1105 template <typename T, typename CharType, size_t N, typename T2>
1106 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
GetValueByPointerWithDefault(T & root,const CharType (& source)[N],T2 defaultValue,typename T::AllocatorType & a)1107 GetValueByPointerWithDefault(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 
1113 template <typename DocumentType>
GetValueByPointerWithDefault(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,const typename DocumentType::ValueType & defaultValue)1114 typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) {
1115     return pointer.GetWithDefault(document, defaultValue);
1116 }
1117 
1118 template <typename DocumentType>
GetValueByPointerWithDefault(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,const typename DocumentType::Ch * defaultValue)1119 typename 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
1124 template <typename DocumentType>
GetValueByPointerWithDefault(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,const std::basic_string<typename DocumentType::Ch> & defaultValue)1125 typename 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 
1130 template <typename DocumentType, typename T2>
1131 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
GetValueByPointerWithDefault(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,T2 defaultValue)1132 GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {
1133     return pointer.GetWithDefault(document, defaultValue);
1134 }
1135 
1136 template <typename DocumentType, typename CharType, size_t N>
GetValueByPointerWithDefault(DocumentType & document,const CharType (& source)[N],const typename DocumentType::ValueType & defaultValue)1137 typename 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 
1141 template <typename DocumentType, typename CharType, size_t N>
GetValueByPointerWithDefault(DocumentType & document,const CharType (& source)[N],const typename DocumentType::Ch * defaultValue)1142 typename 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
1147 template <typename DocumentType, typename CharType, size_t N>
GetValueByPointerWithDefault(DocumentType & document,const CharType (& source)[N],const std::basic_string<typename DocumentType::Ch> & defaultValue)1148 typename 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 
1153 template <typename DocumentType, typename CharType, size_t N, typename T2>
1154 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
GetValueByPointerWithDefault(DocumentType & document,const CharType (& source)[N],T2 defaultValue)1155 GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {
1156     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1157 }
1158 
1159 //////////////////////////////////////////////////////////////////////////////
1160 
1161 template <typename T>
SetValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,typename T::ValueType & value,typename T::AllocatorType & a)1162 typename 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 
1166 template <typename T>
SetValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,const typename T::ValueType & value,typename T::AllocatorType & a)1167 typename 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 
1171 template <typename T>
SetValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,const typename T::Ch * value,typename T::AllocatorType & a)1172 typename 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
1177 template <typename T>
SetValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,const std::basic_string<typename T::Ch> & value,typename T::AllocatorType & a)1178 typename 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 
1183 template <typename T, typename T2>
1184 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
SetValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,T2 value,typename T::AllocatorType & a)1185 SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {
1186     return pointer.Set(root, value, a);
1187 }
1188 
1189 template <typename T, typename CharType, size_t N>
SetValueByPointer(T & root,const CharType (& source)[N],typename T::ValueType & value,typename T::AllocatorType & a)1190 typename 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 
1194 template <typename T, typename CharType, size_t N>
SetValueByPointer(T & root,const CharType (& source)[N],const typename T::ValueType & value,typename T::AllocatorType & a)1195 typename 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 
1199 template <typename T, typename CharType, size_t N>
SetValueByPointer(T & root,const CharType (& source)[N],const typename T::Ch * value,typename T::AllocatorType & a)1200 typename 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
1205 template <typename T, typename CharType, size_t N>
SetValueByPointer(T & root,const CharType (& source)[N],const std::basic_string<typename T::Ch> & value,typename T::AllocatorType & a)1206 typename 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 
1211 template <typename T, typename CharType, size_t N, typename T2>
1212 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
SetValueByPointer(T & root,const CharType (& source)[N],T2 value,typename T::AllocatorType & a)1213 SetValueByPointer(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 
1219 template <typename DocumentType>
SetValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,typename DocumentType::ValueType & value)1220 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
1221     return pointer.Set(document, value);
1222 }
1223 
1224 template <typename DocumentType>
SetValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,const typename DocumentType::ValueType & value)1225 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) {
1226     return pointer.Set(document, value);
1227 }
1228 
1229 template <typename DocumentType>
SetValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,const typename DocumentType::Ch * value)1230 typename 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
1235 template <typename DocumentType>
SetValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,const std::basic_string<typename DocumentType::Ch> & value)1236 typename 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 
1241 template <typename DocumentType, typename T2>
1242 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
SetValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,T2 value)1243 SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {
1244     return pointer.Set(document, value);
1245 }
1246 
1247 template <typename DocumentType, typename CharType, size_t N>
SetValueByPointer(DocumentType & document,const CharType (& source)[N],typename DocumentType::ValueType & value)1248 typename 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 
1252 template <typename DocumentType, typename CharType, size_t N>
SetValueByPointer(DocumentType & document,const CharType (& source)[N],const typename DocumentType::ValueType & value)1253 typename 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 
1257 template <typename DocumentType, typename CharType, size_t N>
SetValueByPointer(DocumentType & document,const CharType (& source)[N],const typename DocumentType::Ch * value)1258 typename 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
1263 template <typename DocumentType, typename CharType, size_t N>
SetValueByPointer(DocumentType & document,const CharType (& source)[N],const std::basic_string<typename DocumentType::Ch> & value)1264 typename 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 
1269 template <typename DocumentType, typename CharType, size_t N, typename T2>
1270 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
SetValueByPointer(DocumentType & document,const CharType (& source)[N],T2 value)1271 SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {
1272     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1273 }
1274 
1275 //////////////////////////////////////////////////////////////////////////////
1276 
1277 template <typename T>
SwapValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,typename T::ValueType & value,typename T::AllocatorType & a)1278 typename 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 
1282 template <typename T, typename CharType, size_t N>
SwapValueByPointer(T & root,const CharType (& source)[N],typename T::ValueType & value,typename T::AllocatorType & a)1283 typename 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 
1287 template <typename DocumentType>
SwapValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,typename DocumentType::ValueType & value)1288 typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
1289     return pointer.Swap(document, value);
1290 }
1291 
1292 template <typename DocumentType, typename CharType, size_t N>
SwapValueByPointer(DocumentType & document,const CharType (& source)[N],typename DocumentType::ValueType & value)1293 typename 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 
1299 template <typename T>
EraseValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer)1300 bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {
1301     return pointer.Erase(root);
1302 }
1303 
1304 template <typename T, typename CharType, size_t N>
EraseValueByPointer(T & root,const CharType (& source)[N])1305 bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
1306     return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);
1307 }
1308 
1309 //@}
1310 
1311 RAPIDJSON_NAMESPACE_END
1312 
1313 #endif // RAPIDJSON_POINTER_H_
1314