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