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