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