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