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