载入中...
搜索中...
未找到
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
22#ifdef __clang__
23RAPIDJSON_DIAG_PUSH
24RAPIDJSON_DIAG_OFF(switch-enum)
25#elif defined(_MSC_VER)
26RAPIDJSON_DIAG_PUSH
27RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
28#endif
29
30RAPIDJSON_NAMESPACE_BEGIN
31
32static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
33
34//! Error code of parsing.
35/*! \ingroup RAPIDJSON_ERRORS
36 \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
37*/
39 kPointerParseErrorNone = 0, //!< The parse is successful
40
41 kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
43 kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
44 kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
45};
46
47///////////////////////////////////////////////////////////////////////////////
48// GenericPointer
49
50//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
51/*!
52 This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer"
53 (https://tools.ietf.org/html/rfc6901).
54
55 A JSON pointer is for identifying a specific value in a JSON document
56 (GenericDocument). It can simplify coding of DOM tree manipulation, because it
57 can access multiple-level depth of DOM tree with single API call.
58
59 After it parses a string representation (e.g. "/foo/0" or URI fragment
60 representation (e.g. "#/foo/0") into its internal representation (tokens),
61 it can be used to resolve a specific value in multiple documents, or sub-tree
62 of documents.
63
64 Contrary to GenericValue, Pointer can be copy constructed and copy assigned.
65 Apart from assignment, a Pointer cannot be modified after construction.
66
67 Although Pointer is very convenient, please aware that constructing Pointer
68 involves parsing and dynamic memory allocation. A special constructor with user-
69 supplied tokens eliminates these.
70
71 GenericPointer depends on GenericDocument and GenericValue.
72
73 \tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >
74 \tparam Allocator The allocator type for allocating memory for internal representation.
75
76 \note GenericPointer uses same encoding of ValueType.
77 However, Allocator of GenericPointer is independent of Allocator of Value.
78*/
79template <typename ValueType, typename Allocator = CrtAllocator>
81public:
82 typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
83 typedef typename ValueType::Ch Ch; //!< Character type from Value
85
86
87 //! A token is the basic units of internal representation.
88 /*!
89 A JSON pointer string representation "/foo/123" is parsed to two tokens:
90 "foo" and 123. 123 will be represented in both numeric form and string form.
91 They are resolved according to the actual value type (object or array).
92
93 For token that are not numbers, or the numeric value is out of bound
94 (greater than limits of SizeType), they are only treated as string form
95 (i.e. the token's index will be equal to kPointerInvalidIndex).
96
97 This struct is public so that user can create a Pointer without parsing and
98 allocation, using a special constructor.
99 */
100 struct Token {
101 const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character.
102 SizeType length; //!< Length of the name.
103 SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex.
104 };
105
106 //!@name Constructors and destructor.
107 //@{
108
109 //! Default constructor.
110 GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
111
112 //! Constructor that parses a string or URI fragment representation.
113 /*!
114 \param source A null-terminated, string or URI fragment representation of JSON pointer.
115 \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
116 */
117 explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
118 Parse(source, internal::StrLen(source));
119 }
120
121#if RAPIDJSON_HAS_STDSTRING
122 //! Constructor that parses a string or URI fragment representation.
123 /*!
124 \param source A string or URI fragment representation of JSON pointer.
125 \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
126 \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
127 */
128 explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
129 Parse(source.c_str(), source.size());
130 }
131#endif
132
133 //! Constructor that parses a string or URI fragment representation, with length of the source string.
134 /*!
135 \param source A string or URI fragment representation of JSON pointer.
136 \param length Length of source.
137 \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
138 \note Slightly faster than the overload without length.
139 */
140 GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
141 Parse(source, length);
142 }
143
144 //! Constructor with user-supplied tokens.
145 /*!
146 This constructor let user supplies const array of tokens.
147 This prevents the parsing process and eliminates allocation.
148 This is preferred for memory constrained environments.
149
150 \param tokens An constant array of tokens representing the JSON pointer.
151 \param tokenCount Number of tokens.
152
153 \b Example
154 \code
155 #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
156 #define INDEX(i) { #i, sizeof(#i) - 1, i }
157
158 static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
159 static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
160 // Equivalent to static const Pointer p("/foo/123");
161
162 #undef NAME
163 #undef INDEX
164 \endcode
165 */
166 GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
167
168 //! Copy constructor.
169 GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
170 *this = rhs;
171 }
172
173 //! Copy constructor.
174 GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
175 *this = rhs;
176 }
177
178 //! Destructor.
180 if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
181 Allocator::Free(tokens_);
182 RAPIDJSON_DELETE(ownAllocator_);
183 }
184
185 //! Assignment operator.
187 if (this != &rhs) {
188 // Do not delete ownAllcator
189 if (nameBuffer_)
190 Allocator::Free(tokens_);
191
192 tokenCount_ = rhs.tokenCount_;
193 parseErrorOffset_ = rhs.parseErrorOffset_;
194 parseErrorCode_ = rhs.parseErrorCode_;
195
196 if (rhs.nameBuffer_)
197 CopyFromRaw(rhs); // Normally parsed tokens.
198 else {
199 tokens_ = rhs.tokens_; // User supplied const tokens.
200 nameBuffer_ = 0;
201 }
202 }
203 return *this;
204 }
205
206 //! Swap the content of this pointer with an other.
207 /*!
208 \param other The pointer to swap with.
209 \note Constant complexity.
210 */
211 GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT {
212 internal::Swap(allocator_, other.allocator_);
213 internal::Swap(ownAllocator_, other.ownAllocator_);
214 internal::Swap(nameBuffer_, other.nameBuffer_);
215 internal::Swap(tokens_, other.tokens_);
216 internal::Swap(tokenCount_, other.tokenCount_);
217 internal::Swap(parseErrorOffset_, other.parseErrorOffset_);
218 internal::Swap(parseErrorCode_, other.parseErrorCode_);
219 return *this;
220 }
221
222 //! free-standing swap function helper
223 /*!
224 Helper function to enable support for common swap implementation pattern based on \c std::swap:
225 \code
226 void swap(MyClass& a, MyClass& b) {
227 using std::swap;
228 swap(a.pointer, b.pointer);
229 // ...
230 }
231 \endcode
232 \see Swap()
233 */
234 friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
235
236 //@}
237
238 //!@name Append token
239 //@{
240
241 //! Append a token and return a new Pointer
242 /*!
243 \param token Token to be appended.
244 \param allocator Allocator for the newly return Pointer.
245 \return A new Pointer with appended token.
246 */
247 GenericPointer Append(const Token& token, Allocator* allocator = 0) const {
249 r.allocator_ = allocator;
250 Ch *p = r.CopyFromRaw(*this, 1, token.length + 1);
251 std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));
252 r.tokens_[tokenCount_].name = p;
253 r.tokens_[tokenCount_].length = token.length;
254 r.tokens_[tokenCount_].index = token.index;
255 return r;
256 }
257
258 //! Append a name token with length, and return a new Pointer
259 /*!
260 \param name Name to be appended.
261 \param length Length of name.
262 \param allocator Allocator for the newly return Pointer.
263 \return A new Pointer with appended token.
264 */
265 GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {
266 Token token = { name, length, kPointerInvalidIndex };
267 return Append(token, allocator);
268 }
269
270 //! Append a name token without length, and return a new Pointer
271 /*!
272 \param name Name (const Ch*) to be appended.
273 \param allocator Allocator for the newly return Pointer.
274 \return A new Pointer with appended token.
275 */
276 template <typename T>
277 RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
278 Append(T* name, Allocator* allocator = 0) const {
279 return Append(name, internal::StrLen(name), allocator);
280 }
281
282#if RAPIDJSON_HAS_STDSTRING
283 //! Append a name token, and return a new Pointer
284 /*!
285 \param name Name to be appended.
286 \param allocator Allocator for the newly return Pointer.
287 \return A new Pointer with appended token.
288 */
289 GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {
290 return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);
291 }
292#endif
293
294 //! Append a index token, and return a new Pointer
295 /*!
296 \param index Index to be appended.
297 \param allocator Allocator for the newly return Pointer.
298 \return A new Pointer with appended token.
299 */
300 GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
301 char buffer[21];
302 char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);
303 SizeType length = static_cast<SizeType>(end - buffer);
304 buffer[length] = '\0';
305
306 if (sizeof(Ch) == 1) {
307 Token token = { reinterpret_cast<Ch*>(buffer), length, index };
308 return Append(token, allocator);
309 }
310 else {
311 Ch name[21];
312 for (size_t i = 0; i <= length; i++)
313 name[i] = static_cast<Ch>(buffer[i]);
314 Token token = { name, length, index };
315 return Append(token, allocator);
316 }
317 }
318
319 //! Append a token by value, and return a new Pointer
320 /*!
321 \param token token to be appended.
322 \param allocator Allocator for the newly return Pointer.
323 \return A new Pointer with appended token.
324 */
325 GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const {
326 if (token.IsString())
327 return Append(token.GetString(), token.GetStringLength(), allocator);
328 else {
329 RAPIDJSON_ASSERT(token.IsUint64());
330 RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));
331 return Append(static_cast<SizeType>(token.GetUint64()), allocator);
332 }
333 }
334
335 //!@name Handling Parse Error
336 //@{
337
338 //! Check whether this is a valid pointer.
339 bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }
340
341 //! Get the parsing error offset in code unit.
342 size_t GetParseErrorOffset() const { return parseErrorOffset_; }
343
344 //! Get the parsing error code.
345 PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
346
347 //@}
348
349 //! Get the allocator of this pointer.
350 Allocator& GetAllocator() { return *allocator_; }
351
352 //!@name Tokens
353 //@{
354
355 //! Get the token array (const version only).
356 const Token* GetTokens() const { return tokens_; }
357
358 //! Get the number of tokens.
359 size_t GetTokenCount() const { return tokenCount_; }
360
361 //@}
362
363 //!@name Equality/inequality operators
364 //@{
365
366 //! Equality operator.
367 /*!
368 \note When any pointers are invalid, always returns false.
369 */
370 bool operator==(const GenericPointer& rhs) const {
371 if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)
372 return false;
373
374 for (size_t i = 0; i < tokenCount_; i++) {
375 if (tokens_[i].index != rhs.tokens_[i].index ||
376 tokens_[i].length != rhs.tokens_[i].length ||
377 (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))
378 {
379 return false;
380 }
381 }
382
383 return true;
384 }
385
386 //! Inequality operator.
387 /*!
388 \note When any pointers are invalid, always returns true.
389 */
390 bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
391
392 //! Less than operator.
393 /*!
394 \note Invalid pointers are always greater than valid ones.
395 */
396 bool operator<(const GenericPointer& rhs) const {
397 if (!IsValid())
398 return false;
399 if (!rhs.IsValid())
400 return true;
401
402 if (tokenCount_ != rhs.tokenCount_)
403 return tokenCount_ < rhs.tokenCount_;
404
405 for (size_t i = 0; i < tokenCount_; i++) {
406 if (tokens_[i].index != rhs.tokens_[i].index)
407 return tokens_[i].index < rhs.tokens_[i].index;
408
409 if (tokens_[i].length != rhs.tokens_[i].length)
410 return tokens_[i].length < rhs.tokens_[i].length;
411
412 if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length))
413 return cmp < 0;
414 }
415
416 return false;
417 }
418
419 //@}
420
421 //!@name Stringify
422 //@{
423
424 //! Stringify the pointer into string representation.
425 /*!
426 \tparam OutputStream Type of output stream.
427 \param os The output stream.
428 */
429 template<typename OutputStream>
430 bool Stringify(OutputStream& os) const {
431 return Stringify<false, OutputStream>(os);
432 }
433
434 //! Stringify the pointer into URI fragment representation.
435 /*!
436 \tparam OutputStream Type of output stream.
437 \param os The output stream.
438 */
439 template<typename OutputStream>
440 bool StringifyUriFragment(OutputStream& os) const {
441 return Stringify<true, OutputStream>(os);
442 }
443
444 //@}
445
446 //!@name Create value
447 //@{
448
449 //! Create a value in a subtree.
450 /*!
451 If the value is not exist, it creates all parent values and a JSON Null value.
452 So it always succeed and return the newly created or existing value.
453
454 Remind that it may change types of parents according to tokens, so it
455 potentially removes previously stored values. For example, if a document
456 was an array, and "/foo" is used to create a value, then the document
457 will be changed to an object, and all existing array elements are lost.
458
459 \param root Root value of a DOM subtree to be resolved. It can be any value other than document root.
460 \param allocator Allocator for creating the values if the specified value or its parents are not exist.
461 \param alreadyExist If non-null, it stores whether the resolved value is already exist.
462 \return The resolved newly created (a JSON Null value), or already exists value.
463 */
464 ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const {
465 RAPIDJSON_ASSERT(IsValid());
466 ValueType* v = &root;
467 bool exist = true;
468 for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
469 if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
470 v->PushBack(ValueType().Move(), allocator);
471 v = &((*v)[v->Size() - 1]);
472 exist = false;
473 }
474 else {
475 if (t->index == kPointerInvalidIndex) { // must be object name
476 if (!v->IsObject())
477 v->SetObject(); // Change to Object
478 }
479 else { // object name or array index
480 if (!v->IsArray() && !v->IsObject())
481 v->SetArray(); // Change to Array
482 }
483
484 if (v->IsArray()) {
485 if (t->index >= v->Size()) {
486 v->Reserve(t->index + 1, allocator);
487 while (t->index >= v->Size())
488 v->PushBack(ValueType().Move(), allocator);
489 exist = false;
490 }
491 v = &((*v)[t->index]);
492 }
493 else {
494 typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
495 if (m == v->MemberEnd()) {
496 v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
497 m = v->MemberEnd();
498 v = &(--m)->value; // Assumes AddMember() appends at the end
499 exist = false;
500 }
501 else
502 v = &m->value;
503 }
504 }
505 }
506
507 if (alreadyExist)
508 *alreadyExist = exist;
509
510 return *v;
511 }
512
513 //! Creates a value in a document.
514 /*!
515 \param document A document to be resolved.
516 \param alreadyExist If non-null, it stores whether the resolved value is already exist.
517 \return The resolved newly created, or already exists value.
518 */
519 template <typename stackAllocator>
521 return Create(document, document.GetAllocator(), alreadyExist);
522 }
523
524 //@}
525
526 //!@name Compute URI
527 //@{
528
529 //! Compute the in-scope URI for a subtree.
530 // For use with JSON pointers into JSON schema documents.
531 /*!
532 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
533 \param rootUri Root URI
534 \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
535 \param allocator Allocator for Uris
536 \return Uri if it can be resolved. Otherwise null.
537
538 \note
539 There are only 3 situations when a URI cannot be resolved:
540 1. A value in the path is not an array nor object.
541 2. An object value does not contain the token.
542 3. A token is out of range of an array value.
543
544 Use unresolvedTokenIndex to retrieve the token index.
545 */
546 UriType GetUri(ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const {
547 static const Ch kIdString[] = { 'i', 'd', '\0' };
548 static const ValueType kIdValue(kIdString, 2);
549 UriType base = UriType(rootUri, allocator);
550 RAPIDJSON_ASSERT(IsValid());
551 ValueType* v = &root;
552 for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
553 switch (v->GetType()) {
554 case kObjectType:
555 {
556 // See if we have an id, and if so resolve with the current base
557 typename ValueType::MemberIterator m = v->FindMember(kIdValue);
558 if (m != v->MemberEnd() && (m->value).IsString()) {
559 UriType here = UriType(m->value, allocator).Resolve(base, allocator);
560 base = here;
561 }
562 m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
563 if (m == v->MemberEnd())
564 break;
565 v = &m->value;
566 }
567 continue;
568 case kArrayType:
569 if (t->index == kPointerInvalidIndex || t->index >= v->Size())
570 break;
571 v = &((*v)[t->index]);
572 continue;
573 default:
574 break;
575 }
576
577 // Error: unresolved token
578 if (unresolvedTokenIndex)
579 *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
580 return UriType(allocator);
581 }
582 return base;
583 }
584
585 UriType GetUri(const ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const {
586 return GetUri(const_cast<ValueType&>(root), rootUri, unresolvedTokenIndex, allocator);
587 }
588
589
590 //!@name Query value
591 //@{
592
593 //! Query a value in a subtree.
594 /*!
595 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
596 \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
597 \return Pointer to the value if it can be resolved. Otherwise null.
598
599 \note
600 There are only 3 situations when a value cannot be resolved:
601 1. A value in the path is not an array nor object.
602 2. An object value does not contain the token.
603 3. A token is out of range of an array value.
604
605 Use unresolvedTokenIndex to retrieve the token index.
606 */
607 ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
608 RAPIDJSON_ASSERT(IsValid());
609 ValueType* v = &root;
610 for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
611 switch (v->GetType()) {
612 case kObjectType:
613 {
614 typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
615 if (m == v->MemberEnd())
616 break;
617 v = &m->value;
618 }
619 continue;
620 case kArrayType:
621 if (t->index == kPointerInvalidIndex || t->index >= v->Size())
622 break;
623 v = &((*v)[t->index]);
624 continue;
625 default:
626 break;
627 }
628
629 // Error: unresolved token
630 if (unresolvedTokenIndex)
631 *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
632 return 0;
633 }
634 return v;
635 }
636
637 //! Query a const value in a const subtree.
638 /*!
639 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
640 \return Pointer to the value if it can be resolved. Otherwise null.
641 */
642 const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {
643 return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
644 }
645
646 //@}
647
648 //!@name Query a value with default
649 //@{
650
651 //! Query a value in a subtree with default value.
652 /*!
653 Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value.
654 So that this function always succeed.
655
656 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
657 \param defaultValue Default value to be cloned if the value was not exists.
658 \param allocator Allocator for creating the values if the specified value or its parents are not exist.
659 \see Create()
660 */
661 ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
662 bool alreadyExist;
663 ValueType& v = Create(root, allocator, &alreadyExist);
664 return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
665 }
666
667 //! Query a value in a subtree with default null-terminated string.
668 ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
669 bool alreadyExist;
670 ValueType& v = Create(root, allocator, &alreadyExist);
671 return alreadyExist ? v : v.SetString(defaultValue, allocator);
672 }
673
674#if RAPIDJSON_HAS_STDSTRING
675 //! Query a value in a subtree with default std::basic_string.
676 ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {
677 bool alreadyExist;
678 ValueType& v = Create(root, allocator, &alreadyExist);
679 return alreadyExist ? v : v.SetString(defaultValue, allocator);
680 }
681#endif
682
683 //! Query a value in a subtree with default primitive value.
684 /*!
685 \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
686 */
687 template <typename T>
688 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
689 GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const {
690 return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);
691 }
692
693 //! Query a value in a document with default value.
694 template <typename stackAllocator>
696 return GetWithDefault(document, defaultValue, document.GetAllocator());
697 }
698
699 //! Query a value in a document with default null-terminated string.
700 template <typename stackAllocator>
702 return GetWithDefault(document, defaultValue, document.GetAllocator());
703 }
704
705#if RAPIDJSON_HAS_STDSTRING
706 //! Query a value in a document with default std::basic_string.
707 template <typename stackAllocator>
708 ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const {
709 return GetWithDefault(document, defaultValue, document.GetAllocator());
710 }
711#endif
712
713 //! Query a value in a document with default primitive value.
714 /*!
715 \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
716 */
717 template <typename T, typename stackAllocator>
718 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
719 GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const {
720 return GetWithDefault(document, defaultValue, document.GetAllocator());
721 }
722
723 //@}
724
725 //!@name Set a value
726 //@{
727
728 //! Set a value in a subtree, with move semantics.
729 /*!
730 It creates all parents if they are not exist or types are different to the tokens.
731 So this function always succeeds but potentially remove existing values.
732
733 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
734 \param value Value to be set.
735 \param allocator Allocator for creating the values if the specified value or its parents are not exist.
736 \see Create()
737 */
738 ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
739 return Create(root, allocator) = value;
740 }
741
742 //! Set a value in a subtree, with copy semantics.
743 ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const {
744 return Create(root, allocator).CopyFrom(value, allocator);
745 }
746
747 //! Set a null-terminated string in a subtree.
748 ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const {
749 return Create(root, allocator) = ValueType(value, allocator).Move();
750 }
751
752#if RAPIDJSON_HAS_STDSTRING
753 //! Set a std::basic_string in a subtree.
754 ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const {
755 return Create(root, allocator) = ValueType(value, allocator).Move();
756 }
757#endif
758
759 //! Set a primitive value in a subtree.
760 /*!
761 \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
762 */
763 template <typename T>
764 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
765 Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const {
766 return Create(root, allocator) = ValueType(value).Move();
767 }
768
769 //! Set a value in a document, with move semantics.
770 template <typename stackAllocator>
772 return Create(document) = value;
773 }
774
775 //! Set a value in a document, with copy semantics.
776 template <typename stackAllocator>
778 return Create(document).CopyFrom(value, document.GetAllocator());
779 }
780
781 //! Set a null-terminated string in a document.
782 template <typename stackAllocator>
784 return Create(document) = ValueType(value, document.GetAllocator()).Move();
785 }
786
787#if RAPIDJSON_HAS_STDSTRING
788 //! Sets a std::basic_string in a document.
789 template <typename stackAllocator>
790 ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const {
791 return Create(document) = ValueType(value, document.GetAllocator()).Move();
792 }
793#endif
794
795 //! Set a primitive value in a document.
796 /*!
797 \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
798 */
799 template <typename T, typename stackAllocator>
800 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
801 Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const {
802 return Create(document) = value;
803 }
804
805 //@}
806
807 //!@name Swap a value
808 //@{
809
810 //! Swap a value with a value in a subtree.
811 /*!
812 It creates all parents if they are not exist or types are different to the tokens.
813 So this function always succeeds but potentially remove existing values.
814
815 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
816 \param value Value to be swapped.
817 \param allocator Allocator for creating the values if the specified value or its parents are not exist.
818 \see Create()
819 */
820 ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
821 return Create(root, allocator).Swap(value);
822 }
823
824 //! Swap a value with a value in a document.
825 template <typename stackAllocator>
827 return Create(document).Swap(value);
828 }
829
830 //@}
831
832 //! Erase a value in a subtree.
833 /*!
834 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
835 \return Whether the resolved value is found and erased.
836
837 \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false.
838 */
839 bool Erase(ValueType& root) const {
840 RAPIDJSON_ASSERT(IsValid());
841 if (tokenCount_ == 0) // Cannot erase the root
842 return false;
843
844 ValueType* v = &root;
845 const Token* last = tokens_ + (tokenCount_ - 1);
846 for (const Token *t = tokens_; t != last; ++t) {
847 switch (v->GetType()) {
848 case kObjectType:
849 {
850 typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
851 if (m == v->MemberEnd())
852 return false;
853 v = &m->value;
854 }
855 break;
856 case kArrayType:
857 if (t->index == kPointerInvalidIndex || t->index >= v->Size())
858 return false;
859 v = &((*v)[t->index]);
860 break;
861 default:
862 return false;
863 }
864 }
865
866 switch (v->GetType()) {
867 case kObjectType:
868 return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));
869 case kArrayType:
870 if (last->index == kPointerInvalidIndex || last->index >= v->Size())
871 return false;
872 v->Erase(v->Begin() + last->index);
873 return true;
874 default:
875 return false;
876 }
877 }
878
879private:
880 //! Clone the content from rhs to this.
881 /*!
882 \param rhs Source pointer.
883 \param extraToken Extra tokens to be allocated.
884 \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated.
885 \return Start of non-occupied name buffer, for storing extra names.
886 */
887 Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {
888 if (!allocator_) // allocator is independently owned.
889 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
890
891 size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
892 for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
893 nameBufferSize += t->length;
894
895 tokenCount_ = rhs.tokenCount_ + extraToken;
896 tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
897 nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
898 if (rhs.tokenCount_ > 0) {
899 std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
900 }
901 if (nameBufferSize > 0) {
902 std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
903 }
904
905 // Adjust pointers to name buffer
906 std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
907 for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
908 t->name += diff;
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: document.h:2499
Allocator & GetAllocator()
Get the allocator of this document.
Definition: document.h:2795
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
Definition: pointer.h:80
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:140
GenericPointer & operator=(const GenericPointer &rhs)
Assignment operator.
Definition: pointer.h:186
~GenericPointer()
Destructor.
Definition: pointer.h:179
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:668
friend void swap(GenericPointer &a, GenericPointer &b) RAPIDJSON_NOEXCEPT
free-standing swap function helper
Definition: pointer.h:234
bool operator<(const GenericPointer &rhs) const
Less than operator.
Definition: pointer.h:396
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:265
ValueType & Create(ValueType &root, typename ValueType::AllocatorType &allocator, bool *alreadyExist=0) const
Create a value in a subtree.
Definition: pointer.h:464
ValueType::EncodingType EncodingType
Encoding type from Value
Definition: pointer.h:82
ValueType & Set(ValueType &root, const Ch *value, typename ValueType::AllocatorType &allocator) const
Set a null-terminated string in a subtree.
Definition: pointer.h:748
bool operator==(const GenericPointer &rhs) const
Equality operator.
Definition: pointer.h:370
ValueType & Set(GenericDocument< EncodingType, typename ValueType::AllocatorType, stackAllocator > &document, const Ch *value) const
Set a null-terminated string in a document.
Definition: pointer.h:783
GenericPointer Append(SizeType index, Allocator *allocator=0) const
Append a index token, and return a new Pointer
Definition: pointer.h:300
GenericPointer Append(const ValueType &token, Allocator *allocator=0) const
Append a token by value, and return a new Pointer
Definition: pointer.h:325
Allocator & GetAllocator()
Get the allocator of this pointer.
Definition: pointer.h:350
ValueType & Create(GenericDocument< EncodingType, typename ValueType::AllocatorType, stackAllocator > &document, bool *alreadyExist=0) const
Creates a value in a document.
Definition: pointer.h:520
GenericPointer(const Token *tokens, size_t tokenCount)
Constructor with user-supplied tokens.
Definition: pointer.h:166
bool Stringify(OutputStream &os) const
Stringify the pointer into string representation.
Definition: pointer.h:430
size_t GetParseErrorOffset() const
Get the parsing error offset in code unit.
Definition: pointer.h:342
size_t GetTokenCount() const
Get the number of tokens.
Definition: pointer.h:359
GenericPointer Append(const Token &token, Allocator *allocator=0) const
Append a token and return a new Pointer
Definition: pointer.h:247
ValueType & Set(ValueType &root, const ValueType &value, typename ValueType::AllocatorType &allocator) const
Set a value in a subtree, with copy semantics.
Definition: pointer.h:743
ValueType & GetWithDefault(ValueType &root, const ValueType &defaultValue, typename ValueType::AllocatorType &allocator) const
Query a value in a subtree with default value.
Definition: pointer.h:661
ValueType::Ch Ch
Character type from Value
Definition: pointer.h:83
ValueType * Get(ValueType &root, size_t *unresolvedTokenIndex=0) const
Query a value in a subtree.
Definition: pointer.h:607
bool operator!=(const GenericPointer &rhs) const
Inequality operator.
Definition: pointer.h:390
GenericPointer(const Ch *source, Allocator *allocator=0)
Constructor that parses a string or URI fragment representation.
Definition: pointer.h:117
ValueType & Set(GenericDocument< EncodingType, typename ValueType::AllocatorType, stackAllocator > &document, ValueType &value) const
Set a value in a document, with move semantics.
Definition: pointer.h:771
ValueType & Swap(ValueType &root, ValueType &value, typename ValueType::AllocatorType &allocator) const
Swap a value with a value in a subtree.
Definition: pointer.h:820
bool Erase(ValueType &root) const
Erase a value in a subtree.
Definition: pointer.h:839
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:777
bool IsValid() const
Check whether this is a valid pointer.
Definition: pointer.h:339
GenericPointer(Allocator *allocator=0)
Default constructor.
Definition: pointer.h:110
ValueType & Swap(GenericDocument< EncodingType, typename ValueType::AllocatorType, stackAllocator > &document, ValueType &value) const
Swap a value with a value in a document.
Definition: pointer.h:826
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:695
ValueType & Set(ValueType &root, ValueType &value, typename ValueType::AllocatorType &allocator) const
Set a value in a subtree, with move semantics.
Definition: pointer.h:738
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:701
const ValueType * Get(const ValueType &root, size_t *unresolvedTokenIndex=0) const
Query a const value in a const subtree.
Definition: pointer.h:642
GenericPointer & Swap(GenericPointer &other) RAPIDJSON_NOEXCEPT
Swap the content of this pointer with an other.
Definition: pointer.h:211
GenericPointer(const GenericPointer &rhs)
Copy constructor.
Definition: pointer.h:169
bool StringifyUriFragment(OutputStream &os) const
Stringify the pointer into URI fragment representation.
Definition: pointer.h:440
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:546
const Token * GetTokens() const
Get the token array (const version only).
Definition: pointer.h:356
PointerParseErrorCode GetParseErrorCode() const
Get the parsing error code.
Definition: pointer.h:345
GenericPointer(const GenericPointer &rhs, Allocator *allocator)
Copy constructor.
Definition: pointer.h:174
Definition: uri.h:33
GenericUri Resolve(const GenericUri &baseuri, Allocator *allocator=0)
Resolve this URI against another (base) URI in accordance with URI resolution rules.
Definition: uri.h:156
Represents a JSON value. Use Value for UTF8 encoding and default allocator.
Definition: document.h:668
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:437
PointerParseErrorCode
Error code of parsing.
Definition: pointer.h:38
@ kPointerParseErrorInvalidPercentEncoding
Invalid percent encoding in URI fragment
Definition: pointer.h:43
@ kPointerParseErrorTokenMustBeginWithSolidus
A token must begin with a '/'
Definition: pointer.h:41
@ kPointerParseErrorInvalidEscape
Invalid escape
Definition: pointer.h:42
@ kPointerParseErrorNone
The parse is successful
Definition: pointer.h:39
@ kPointerParseErrorCharacterMustPercentEncode
A character must percent encoded in URI fragment
Definition: pointer.h:44
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:100
SizeType index
A valid array index, if it is not equal to kPointerInvalidIndex.
Definition: pointer.h:103
const Ch * name
Name of the token. It has null character at the end but it can contain null character.
Definition: pointer.h:101
SizeType length
Length of the name.
Definition: pointer.h:102
Reference to a constant string (not taking a copy)
Definition: document.h:346