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