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