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