]>
Commit | Line | Data |
---|---|---|
31f18b77 FG |
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_ |