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