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