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