/src/valijson/include/valijson/adapters/rapidjson_adapter.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * @file |
3 | | * |
4 | | * @brief Adapter implementation for the RapidJson parser library. |
5 | | * |
6 | | * Include this file in your program to enable support for RapidJson. |
7 | | * |
8 | | * This file defines the following template classes (not in this order): |
9 | | * - GenericRapidJsonAdapter |
10 | | * - GenericRapidJsonArray |
11 | | * - GenericRapidJsonArrayValueIterator |
12 | | * - GenericRapidJsonFrozenValue |
13 | | * - GenericRapidJsonObject |
14 | | * - GenericRapidJsonObjectMember |
15 | | * - GenericRapidJsonObjectMemberIterator |
16 | | * - GenericRapidJsonValue |
17 | | * |
18 | | * All of these classes share a template argument called 'ValueType', which can |
19 | | * be used to choose the underlying the RapidJson value type that is used. This |
20 | | * allows different RapidJson encodings and allocators to be used. |
21 | | * |
22 | | * This file also defines the following typedefs, which use RapidJson's default |
23 | | * ValueType: |
24 | | * - RapidJsonAdapter |
25 | | * - RapidJsonArray |
26 | | * - RapidJsonArrayValueIterator |
27 | | * - RapidJsonFrozenValue |
28 | | * - RapidJsonObject |
29 | | * - RapidJsonObjectMember |
30 | | * - RapidJsonObjectMemberIterator |
31 | | * - RapidJsonValue |
32 | | * |
33 | | * Due to the dependencies that exist between these classes, the ordering of |
34 | | * class declarations and definitions may be a bit confusing. The best place to |
35 | | * start is RapidJsonAdapter. This class definition is actually very small, |
36 | | * since most of the functionality is inherited from the BasicAdapter class. |
37 | | * Most of the classes in this file are provided as template arguments to the |
38 | | * inherited BasicAdapter class. |
39 | | */ |
40 | | |
41 | | #pragma once |
42 | | |
43 | | #include <string> |
44 | | #include <iterator> |
45 | | |
46 | | #ifdef VALIJSON_USE_EXCEPTIONS |
47 | | #ifdef RAPIDJSON_ASSERT |
48 | | #warning "RAPIDJSON_ASSERT already defined." |
49 | | #warning "Please include valijson/adapters/rapidjson_adapter.hpp before any RapidJSON headers." |
50 | | #else |
51 | | template<typename T> |
52 | | T rapidjson_assert(T t, const std::string& file, const int line) { |
53 | | if (t) { |
54 | | return t; |
55 | | } |
56 | | |
57 | | throw std::runtime_error("assertion failed; file: " + file + "; line: " + std::to_string(line)); |
58 | | } |
59 | | |
60 | | #define RAPIDJSON_ASSERT(x) rapidjson_assert(x, __FILE__, __LINE__) |
61 | | #endif |
62 | | #endif |
63 | | |
64 | | #include <rapidjson/document.h> |
65 | | |
66 | | #include <valijson/internal/adapter.hpp> |
67 | | #include <valijson/internal/basic_adapter.hpp> |
68 | | #include <valijson/internal/frozen_value.hpp> |
69 | | #include <valijson/exceptions.hpp> |
70 | | |
71 | | namespace valijson { |
72 | | namespace adapters { |
73 | | |
74 | | template<class ValueType = rapidjson::Value> |
75 | | class GenericRapidJsonAdapter; |
76 | | |
77 | | template<class ValueType = rapidjson::Value> |
78 | | class GenericRapidJsonArrayValueIterator; |
79 | | |
80 | | template<class ValueType = rapidjson::Value> |
81 | | class GenericRapidJsonObjectMemberIterator; |
82 | | |
83 | | /// Container for a property name and an associated RapidJson value |
84 | | template<class ValueType = rapidjson::Value> |
85 | | class GenericRapidJsonObjectMember : |
86 | | public std::pair<std::string, GenericRapidJsonAdapter<ValueType>> |
87 | | { |
88 | | private: |
89 | | typedef std::pair<std::string, GenericRapidJsonAdapter<ValueType>> Super; |
90 | | |
91 | | public: |
92 | | GenericRapidJsonObjectMember( |
93 | | const std::string &name, |
94 | | const GenericRapidJsonAdapter<ValueType> &value) |
95 | 0 | : Super(name, value) { } |
96 | | }; |
97 | | |
98 | | /** |
99 | | * @brief Light weight wrapper for a RapidJson array value. |
100 | | * |
101 | | * This class is light weight wrapper for a RapidJson array. It provides a |
102 | | * minimum set of container functions and typedefs that allow it to be used as |
103 | | * an iterable container. |
104 | | * |
105 | | * An instance of this class contains a single reference to an underlying |
106 | | * RapidJson value, assumed to be an array, so there is very little overhead |
107 | | * associated with copy construction and passing by value. |
108 | | */ |
109 | | template<class ValueType = rapidjson::Value> |
110 | | class GenericRapidJsonArray |
111 | | { |
112 | | public: |
113 | | |
114 | | typedef GenericRapidJsonArrayValueIterator<ValueType> const_iterator; |
115 | | typedef GenericRapidJsonArrayValueIterator<ValueType> iterator; |
116 | | |
117 | | /// Construct a RapidJsonArray referencing an empty array singleton. |
118 | | GenericRapidJsonArray() |
119 | 0 | : m_value(emptyArray()) { } |
120 | | |
121 | | /** |
122 | | * @brief Construct a RapidJsonArray referencing a specific RapidJson |
123 | | * value. |
124 | | * |
125 | | * @param value reference to a RapidJson value |
126 | | * |
127 | | * Note that this constructor will throw an exception if the value is not |
128 | | * an array. |
129 | | */ |
130 | | GenericRapidJsonArray(const ValueType &value) |
131 | | : m_value(value) |
132 | 0 | { |
133 | 0 | if (!value.IsArray()) { |
134 | 0 | throwRuntimeError("Value is not an array."); |
135 | 0 | } |
136 | 0 | } |
137 | | |
138 | | /// Return an iterator for the first element in the array. |
139 | | iterator begin() const; |
140 | | |
141 | | /// Return an iterator for one-past the last element of the array. |
142 | | iterator end() const; |
143 | | |
144 | | /// Return the number of elements in the array |
145 | | size_t size() const |
146 | 0 | { |
147 | 0 | return m_value.Size(); |
148 | 0 | } |
149 | | |
150 | | private: |
151 | | |
152 | | /** |
153 | | * @brief Return a reference to a RapidJson value that is an empty array. |
154 | | * |
155 | | * Note that the value returned by this function is a singleton. |
156 | | */ |
157 | | static const ValueType & emptyArray() |
158 | 0 | { |
159 | 0 | static const ValueType array(rapidjson::kArrayType); |
160 | 0 | return array; |
161 | 0 | } |
162 | | |
163 | | /// Reference to the contained value |
164 | | const ValueType &m_value; |
165 | | }; |
166 | | |
167 | | /** |
168 | | * @brief Light weight wrapper for a RapidJson object. |
169 | | * |
170 | | * This class is light weight wrapper for a RapidJson object. It provides a |
171 | | * minimum set of container functions and typedefs that allow it to be used as |
172 | | * an iterable container. |
173 | | * |
174 | | * An instance of this class contains a single reference to the underlying |
175 | | * RapidJson value, assumed to be an object, so there is very little overhead |
176 | | * associated with copy construction and passing by value. |
177 | | */ |
178 | | template <class ValueType = rapidjson::Value> |
179 | | class GenericRapidJsonObject |
180 | | { |
181 | | public: |
182 | | |
183 | | typedef GenericRapidJsonObjectMemberIterator<ValueType> const_iterator; |
184 | | typedef GenericRapidJsonObjectMemberIterator<ValueType> iterator; |
185 | | |
186 | | /// Construct a GenericRapidJsonObject referencing an empty object singleton. |
187 | | GenericRapidJsonObject() |
188 | 0 | : m_value(emptyObject()) { } |
189 | | |
190 | | /** |
191 | | * @brief Construct a GenericRapidJsonObject referencing a specific |
192 | | * RapidJson value. |
193 | | * |
194 | | * @param value reference to a RapidJson value |
195 | | * |
196 | | * Note that this constructor will throw an exception if the value is not |
197 | | * an object. |
198 | | */ |
199 | | GenericRapidJsonObject(const ValueType &value) |
200 | | : m_value(value) |
201 | 0 | { |
202 | 0 | if (!value.IsObject()) { |
203 | 0 | throwRuntimeError("Value is not an object."); |
204 | 0 | } |
205 | 0 | } |
206 | | |
207 | | /** |
208 | | * @brief Return an iterator for this first object member |
209 | | * |
210 | | * The iterator return by this function is effectively a wrapper around |
211 | | * the pointer value returned by the underlying RapidJson implementation. |
212 | | */ |
213 | | iterator begin() const; |
214 | | |
215 | | /** |
216 | | * @brief Return an iterator for an invalid object member that indicates |
217 | | * the end of the collection. |
218 | | * |
219 | | * The iterator return by this function is effectively a wrapper around |
220 | | * the pointer value returned by the underlying RapidJson implementation. |
221 | | */ |
222 | | iterator end() const; |
223 | | |
224 | | /** |
225 | | * @brief Return an iterator for the object member with the specified |
226 | | * property name. |
227 | | * |
228 | | * If an object member with the specified name does not exist, the iterator |
229 | | * returned will be the same as the iterator returned by the end() function. |
230 | | * |
231 | | * @param property property name to search for |
232 | | */ |
233 | | iterator find(const std::string &property) const; |
234 | | |
235 | | /// Returns the number of members belonging to this object. |
236 | | size_t size() const |
237 | | { |
238 | | return m_value.MemberEnd() - m_value.MemberBegin(); |
239 | | } |
240 | | |
241 | | private: |
242 | | |
243 | | /** |
244 | | * @brief Return a reference to a RapidJson value that is empty object. |
245 | | * |
246 | | * Note that the value returned by this function is a singleton. |
247 | | */ |
248 | | static const ValueType & emptyObject() |
249 | 0 | { |
250 | 0 | static ValueType object(rapidjson::kObjectType); |
251 | 0 | return object; |
252 | 0 | } |
253 | | |
254 | | /// Reference to the contained object |
255 | | const ValueType &m_value; |
256 | | }; |
257 | | |
258 | | /** |
259 | | * @brief Stores an independent copy of a RapidJson value. |
260 | | * |
261 | | * This class allows a RapidJson value to be stored independent of its original |
262 | | * document. RapidJson makes this a bit harder than usual, because RapidJson |
263 | | * values are associated with a custom memory allocator. As such, RapidJson |
264 | | * values have to be copied recursively, referencing a custom allocator held |
265 | | * by this class. |
266 | | * |
267 | | * @see FrozenValue |
268 | | */ |
269 | | template<class ValueType = rapidjson::Value> |
270 | | class GenericRapidJsonFrozenValue: public FrozenValue |
271 | | { |
272 | | public: |
273 | | |
274 | | explicit GenericRapidJsonFrozenValue(const char *str) |
275 | | { |
276 | | m_value.SetString(str, m_allocator); |
277 | | } |
278 | | |
279 | | explicit GenericRapidJsonFrozenValue(const std::string &str) |
280 | | { |
281 | | m_value.SetString(str.c_str(), (unsigned int)str.length(), m_allocator); |
282 | | } |
283 | | |
284 | | /** |
285 | | * @brief Make a copy of a RapidJson value |
286 | | * |
287 | | * @param source the RapidJson value to be copied |
288 | | */ |
289 | | explicit GenericRapidJsonFrozenValue(const ValueType &source) |
290 | 0 | { |
291 | 0 | if (!copy(source, m_value, m_allocator)) { |
292 | 0 | throwRuntimeError("Failed to copy ValueType"); |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | | FrozenValue * clone() const override |
297 | 0 | { |
298 | 0 | return new GenericRapidJsonFrozenValue(m_value); |
299 | 0 | } |
300 | | |
301 | | bool equalTo(const Adapter &other, bool strict) const override; |
302 | | |
303 | | private: |
304 | | |
305 | | /** |
306 | | * @brief Recursively copy a RapidJson value using a separate allocator |
307 | | * |
308 | | * @param source value to copy from |
309 | | * @param dest value to copy into |
310 | | * @param allocator reference to an allocator held by this class |
311 | | * |
312 | | * @tparam Allocator type of RapidJson Allocator to be used |
313 | | * |
314 | | * @returns true if copied successfully, false otherwise. |
315 | | */ |
316 | | template<typename Allocator> |
317 | | static bool copy(const ValueType &source, |
318 | | ValueType &dest, |
319 | | Allocator &allocator) |
320 | 0 | { |
321 | 0 | switch (source.GetType()) { |
322 | 0 | case rapidjson::kNullType: |
323 | 0 | dest.SetNull(); |
324 | 0 | return true; |
325 | 0 | case rapidjson::kFalseType: |
326 | 0 | dest.SetBool(false); |
327 | 0 | return true; |
328 | 0 | case rapidjson::kTrueType: |
329 | 0 | dest.SetBool(true); |
330 | 0 | return true; |
331 | 0 | case rapidjson::kObjectType: |
332 | 0 | dest.SetObject(); |
333 | 0 | for (typename ValueType::ConstMemberIterator itr = source.MemberBegin(); itr != source.MemberEnd(); ++itr) { |
334 | 0 | ValueType name(itr->name.GetString(), itr->name.GetStringLength(), allocator); |
335 | 0 | ValueType value; |
336 | 0 | copy(itr->value, value, allocator); |
337 | 0 | dest.AddMember(name, value, allocator); |
338 | 0 | } |
339 | 0 | return true; |
340 | 0 | case rapidjson::kArrayType: |
341 | 0 | dest.SetArray(); |
342 | 0 | for (typename ValueType::ConstValueIterator itr = source.Begin(); itr != source.End(); ++itr) { |
343 | 0 | ValueType value; |
344 | 0 | copy(*itr, value, allocator); |
345 | 0 | dest.PushBack(value, allocator); |
346 | 0 | } |
347 | 0 | return true; |
348 | 0 | case rapidjson::kStringType: |
349 | 0 | dest.SetString(source.GetString(), source.GetStringLength(), allocator); |
350 | 0 | return true; |
351 | 0 | case rapidjson::kNumberType: |
352 | 0 | if (source.IsInt()) { |
353 | 0 | dest.SetInt(source.GetInt()); |
354 | 0 | } else if (source.IsUint()) { |
355 | 0 | dest.SetUint(source.GetUint()); |
356 | 0 | } else if (source.IsInt64()) { |
357 | 0 | dest.SetInt64(source.GetInt64()); |
358 | 0 | } else if (source.IsUint64()) { |
359 | 0 | dest.SetUint64(source.GetUint64()); |
360 | 0 | } else { |
361 | 0 | dest.SetDouble(source.GetDouble()); |
362 | 0 | } |
363 | 0 | return true; |
364 | 0 | default: |
365 | 0 | break; |
366 | 0 | } |
367 | | |
368 | 0 | return false; |
369 | 0 | } |
370 | | |
371 | | /// Local memory allocator for RapidJson value |
372 | | typename ValueType::AllocatorType m_allocator; |
373 | | |
374 | | /// Local RapidJson value |
375 | | ValueType m_value; |
376 | | }; |
377 | | |
378 | | /** |
379 | | * @brief Light weight wrapper for a RapidJson value. |
380 | | * |
381 | | * This class is passed as an argument to the BasicAdapter template class, |
382 | | * and is used to provide access to a RapidJson value. This class is responsible |
383 | | * for the mechanics of actually reading a RapidJson value, whereas the |
384 | | * BasicAdapter class is responsible for the semantics of type comparisons |
385 | | * and conversions. |
386 | | * |
387 | | * The functions that need to be provided by this class are defined implicitly |
388 | | * by the implementation of the BasicAdapter template class. |
389 | | * |
390 | | * @see BasicAdapter |
391 | | */ |
392 | | template<class ValueType = rapidjson::Value> |
393 | | class GenericRapidJsonValue |
394 | | { |
395 | | public: |
396 | | /// Construct a wrapper for the empty object singleton |
397 | | GenericRapidJsonValue() |
398 | | : m_value(emptyObject()) { } |
399 | | |
400 | | /// Construct a wrapper for a specific RapidJson value |
401 | | GenericRapidJsonValue(const ValueType &value) |
402 | 103 | : m_value(value) { } |
403 | | |
404 | | /** |
405 | | * @brief Create a new GenericRapidJsonFrozenValue instance that contains |
406 | | * the value referenced by this GenericRapidJsonValue instance. |
407 | | * |
408 | | * @returns pointer to a new GenericRapidJsonFrozenValue instance, belonging |
409 | | * to the caller. |
410 | | */ |
411 | | FrozenValue * freeze() const |
412 | 0 | { |
413 | 0 | return new GenericRapidJsonFrozenValue<ValueType>(m_value); |
414 | 0 | } |
415 | | |
416 | | /** |
417 | | * @brief Optionally return a GenericRapidJsonArray instance. |
418 | | * |
419 | | * If the referenced RapidJson value is an array, this function will return |
420 | | * a std::optional containing a GenericRapidJsonArray instance referencing |
421 | | * the array. |
422 | | * |
423 | | * Otherwise it will return an empty optional. |
424 | | */ |
425 | | opt::optional<GenericRapidJsonArray<ValueType>> getArrayOptional() const |
426 | 0 | { |
427 | 0 | if (m_value.IsArray()) { |
428 | 0 | return opt::make_optional(GenericRapidJsonArray<ValueType>(m_value)); |
429 | 0 | } |
430 | | |
431 | 0 | return {}; |
432 | 0 | } |
433 | | |
434 | | /** |
435 | | * @brief Retrieve the number of elements in the array |
436 | | * |
437 | | * If the referenced RapidJson value is an array, this function will |
438 | | * retrieve the number of elements in the array and store it in the output |
439 | | * variable provided. |
440 | | * |
441 | | * @param result reference to size_t to set with result |
442 | | * |
443 | | * @returns true if the number of elements was retrieved, false otherwise. |
444 | | */ |
445 | | bool getArraySize(size_t &result) const |
446 | 0 | { |
447 | 0 | if (m_value.IsArray()) { |
448 | 0 | result = m_value.Size(); |
449 | 0 | return true; |
450 | 0 | } |
451 | | |
452 | 0 | return false; |
453 | 0 | } |
454 | | |
455 | | bool getBool(bool &result) const |
456 | 0 | { |
457 | 0 | if (m_value.IsBool()) { |
458 | 0 | result = m_value.GetBool(); |
459 | 0 | return true; |
460 | 0 | } |
461 | | |
462 | 0 | return false; |
463 | 0 | } |
464 | | |
465 | | bool getDouble(double &result) const |
466 | 0 | { |
467 | 0 | if (m_value.IsDouble()) { |
468 | 0 | result = m_value.GetDouble(); |
469 | 0 | return true; |
470 | 0 | } |
471 | | |
472 | 0 | return false; |
473 | 0 | } |
474 | | |
475 | | bool getInteger(int64_t &result) const |
476 | 0 | { |
477 | 0 | if (m_value.IsInt()) { |
478 | 0 | result = m_value.GetInt(); |
479 | 0 | return true; |
480 | 0 | } else if (m_value.IsInt64()) { |
481 | 0 | result = m_value.GetInt64(); |
482 | 0 | return true; |
483 | 0 | } else if (m_value.IsUint()) { |
484 | 0 | result = static_cast<int64_t>(m_value.GetUint()); |
485 | 0 | return true; |
486 | 0 | } else if (m_value.IsUint64()) { |
487 | 0 | result = static_cast<int64_t>(m_value.GetUint64()); |
488 | 0 | return true; |
489 | 0 | } |
490 | | |
491 | 0 | return false; |
492 | 0 | } |
493 | | |
494 | | /** |
495 | | * @brief Optionally return a GenericRapidJsonObject instance. |
496 | | * |
497 | | * If the referenced RapidJson value is an object, this function will return |
498 | | * a std::optional containing a GenericRapidJsonObject instance |
499 | | * referencing the object. |
500 | | * |
501 | | * Otherwise it will return an empty optional. |
502 | | */ |
503 | | opt::optional<GenericRapidJsonObject<ValueType>> getObjectOptional() const |
504 | 0 | { |
505 | 0 | if (m_value.IsObject()) { |
506 | 0 | return opt::make_optional(GenericRapidJsonObject<ValueType>(m_value)); |
507 | 0 | } |
508 | | |
509 | 0 | return {}; |
510 | 0 | } |
511 | | |
512 | | /** |
513 | | * @brief Retrieve the number of members in the object |
514 | | * |
515 | | * If the referenced RapidJson value is an object, this function will |
516 | | * retrieve the number of members in the object and store it in the output |
517 | | * variable provided. |
518 | | * |
519 | | * @param result reference to size_t to set with result |
520 | | * |
521 | | * @returns true if the number of members was retrieved, false otherwise. |
522 | | */ |
523 | | bool getObjectSize(size_t &result) const |
524 | 0 | { |
525 | 0 | if (m_value.IsObject()) { |
526 | 0 | result = m_value.MemberEnd() - m_value.MemberBegin(); |
527 | 0 | return true; |
528 | 0 | } |
529 | | |
530 | 0 | return false; |
531 | 0 | } |
532 | | |
533 | | bool getString(std::string &result) const |
534 | 0 | { |
535 | 0 | if (m_value.IsString()) { |
536 | 0 | result.assign(m_value.GetString(), m_value.GetStringLength()); |
537 | 0 | return true; |
538 | 0 | } |
539 | | |
540 | 0 | return false; |
541 | 0 | } |
542 | | |
543 | | static bool hasStrictTypes() |
544 | 0 | { |
545 | 0 | return true; |
546 | 0 | } |
547 | | |
548 | | bool isArray() const |
549 | 206 | { |
550 | 206 | return m_value.IsArray(); |
551 | 206 | } |
552 | | |
553 | | bool isBool() const |
554 | 206 | { |
555 | 206 | return m_value.IsBool(); |
556 | 206 | } |
557 | | |
558 | | bool isDouble() const |
559 | 103 | { |
560 | 103 | return m_value.IsDouble(); |
561 | 103 | } |
562 | | |
563 | | bool isInteger() const |
564 | 103 | { |
565 | 103 | return m_value.IsInt() || m_value.IsInt64() || m_value.IsUint() || m_value.IsUint64(); |
566 | 103 | } |
567 | | |
568 | | bool isNull() const |
569 | 103 | { |
570 | 103 | return m_value.IsNull(); |
571 | 103 | } |
572 | | |
573 | | bool isNumber() const |
574 | 0 | { |
575 | 0 | return m_value.IsNumber(); |
576 | 0 | } |
577 | | |
578 | | bool isObject() const |
579 | 412 | { |
580 | 412 | return m_value.IsObject(); |
581 | 412 | } |
582 | | |
583 | | bool isString() const |
584 | 206 | { |
585 | 206 | return m_value.IsString(); |
586 | 206 | } |
587 | | |
588 | | private: |
589 | | |
590 | | /// Return a reference to an empty object singleton |
591 | | static const ValueType & emptyObject() |
592 | | { |
593 | | static const ValueType object(rapidjson::kObjectType); |
594 | | return object; |
595 | | } |
596 | | |
597 | | /// Reference to the contained RapidJson value. |
598 | | const ValueType &m_value; |
599 | | }; |
600 | | |
601 | | /** |
602 | | * @brief An implementation of the Adapter interface supporting RapidJson. |
603 | | * |
604 | | * This class is defined in terms of the BasicAdapter template class, which |
605 | | * helps to ensure that all of the Adapter implementations behave consistently. |
606 | | * |
607 | | * @see Adapter |
608 | | * @see BasicAdapter |
609 | | */ |
610 | | template<class ValueType> |
611 | | class GenericRapidJsonAdapter: |
612 | | public BasicAdapter<GenericRapidJsonAdapter<ValueType>, |
613 | | GenericRapidJsonArray<ValueType>, |
614 | | GenericRapidJsonObjectMember<ValueType>, |
615 | | GenericRapidJsonObject<ValueType>, |
616 | | GenericRapidJsonValue<ValueType>> |
617 | | { |
618 | | public: |
619 | | |
620 | | /// Construct a RapidJsonAdapter that contains an empty object |
621 | | GenericRapidJsonAdapter() |
622 | | : BasicAdapter<GenericRapidJsonAdapter<ValueType>, |
623 | | GenericRapidJsonArray<ValueType>, |
624 | | GenericRapidJsonObjectMember<ValueType>, |
625 | | GenericRapidJsonObject<ValueType>, |
626 | | GenericRapidJsonValue<ValueType>>() { } |
627 | | |
628 | | /// Construct a RapidJsonAdapter containing a specific RapidJson value |
629 | | GenericRapidJsonAdapter(const ValueType &value) |
630 | | : BasicAdapter<GenericRapidJsonAdapter<ValueType>, |
631 | | GenericRapidJsonArray<ValueType>, |
632 | | GenericRapidJsonObjectMember<ValueType>, |
633 | | GenericRapidJsonObject<ValueType>, |
634 | 103 | GenericRapidJsonValue<ValueType>>(value) { } |
635 | | }; |
636 | | |
637 | | /** |
638 | | * @brief Class for iterating over values held in a JSON array. |
639 | | * |
640 | | * This class provides a JSON array iterator that dereferences as an instance of |
641 | | * RapidJsonAdapter representing a value stored in the array. |
642 | | * |
643 | | * @see RapidJsonArray |
644 | | */ |
645 | | template<class ValueType> |
646 | | class GenericRapidJsonArrayValueIterator |
647 | | { |
648 | | public: |
649 | | using iterator_category = std::bidirectional_iterator_tag; |
650 | | using value_type = GenericRapidJsonAdapter<ValueType>; |
651 | | using difference_type = GenericRapidJsonAdapter<ValueType>; |
652 | | using pointer = GenericRapidJsonAdapter<ValueType>*; |
653 | | using reference = GenericRapidJsonAdapter<ValueType>&; |
654 | | |
655 | | /** |
656 | | * @brief Construct a new GenericRapidJsonArrayValueIterator using an |
657 | | * existing RapidJson iterator. |
658 | | * |
659 | | * @param itr RapidJson iterator to store |
660 | | */ |
661 | | GenericRapidJsonArrayValueIterator( |
662 | | const typename ValueType::ConstValueIterator &itr) |
663 | 0 | : m_itr(itr) { } |
664 | | |
665 | | /// Returns a GenericRapidJsonAdapter that contains the value of the current |
666 | | /// element. |
667 | | GenericRapidJsonAdapter<ValueType> operator*() const |
668 | 0 | { |
669 | 0 | return GenericRapidJsonAdapter<ValueType>(*m_itr); |
670 | 0 | } |
671 | | |
672 | | /// Returns a proxy for the value of the current element |
673 | | DerefProxy<GenericRapidJsonAdapter<ValueType>> operator->() const |
674 | | { |
675 | | return DerefProxy<GenericRapidJsonAdapter<ValueType>>(**this); |
676 | | } |
677 | | |
678 | | /** |
679 | | * @brief Compare this iterator against another iterator. |
680 | | * |
681 | | * Note that this directly compares the iterators, not the underlying |
682 | | * values, and assumes that two identical iterators will point to the same |
683 | | * underlying object. |
684 | | * |
685 | | * @param other iterator to compare against |
686 | | * |
687 | | * @returns true if the iterators are equal, false otherwise. |
688 | | */ |
689 | | bool operator==(const GenericRapidJsonArrayValueIterator<ValueType> &other) const |
690 | 0 | { |
691 | 0 | return m_itr == other.m_itr; |
692 | 0 | } |
693 | | |
694 | | bool operator!=(const GenericRapidJsonArrayValueIterator<ValueType>& other) const |
695 | 0 | { |
696 | 0 | return m_itr != other.m_itr; |
697 | 0 | } |
698 | | |
699 | | GenericRapidJsonArrayValueIterator<ValueType>& operator++() |
700 | 0 | { |
701 | 0 | m_itr++; |
702 | |
|
703 | 0 | return *this; |
704 | 0 | } |
705 | | |
706 | 0 | GenericRapidJsonArrayValueIterator<ValueType> operator++(int) { |
707 | 0 | GenericRapidJsonArrayValueIterator<ValueType> iterator_pre(m_itr); |
708 | 0 | ++(*this); |
709 | 0 | return iterator_pre; |
710 | 0 | } |
711 | | |
712 | | GenericRapidJsonArrayValueIterator<ValueType>& operator--() |
713 | | { |
714 | | m_itr--; |
715 | | |
716 | | return *this; |
717 | | } |
718 | | |
719 | | void advance(std::ptrdiff_t n) |
720 | 0 | { |
721 | 0 | m_itr += n; |
722 | 0 | } |
723 | | |
724 | | std::ptrdiff_t difference(const GenericRapidJsonArrayValueIterator<ValueType> &other) |
725 | | { |
726 | | return std::distance(m_itr, other.itr); |
727 | | } |
728 | | |
729 | | private: |
730 | | |
731 | | typename ValueType::ConstValueIterator m_itr; |
732 | | }; |
733 | | |
734 | | /** |
735 | | * @brief Class for iterating over the members belonging to a JSON object. |
736 | | * |
737 | | * This class provides a JSON object iterator that dereferences as an instance |
738 | | * of GenericRapidJsonObjectMember representing one of the members of the |
739 | | * object. |
740 | | * |
741 | | * @see GenericRapidJsonObject |
742 | | * @see GenericRapidJsonObjectMember |
743 | | */ |
744 | | template<class ValueType> |
745 | | class GenericRapidJsonObjectMemberIterator |
746 | | { |
747 | | public: |
748 | | using iterator_category = std::bidirectional_iterator_tag; |
749 | | using value_type = GenericRapidJsonObjectMember<ValueType>; |
750 | | using difference_type = GenericRapidJsonObjectMember<ValueType>; |
751 | | using pointer = GenericRapidJsonObjectMember<ValueType>*; |
752 | | using reference = GenericRapidJsonObjectMember<ValueType>&; |
753 | | |
754 | | /** |
755 | | * @brief Construct an iterator from a RapidJson iterator. |
756 | | * |
757 | | * @param itr RapidJson iterator to store |
758 | | */ |
759 | | GenericRapidJsonObjectMemberIterator( |
760 | | const typename ValueType::ConstMemberIterator &itr) |
761 | 0 | : m_itr(itr) { } |
762 | | |
763 | | |
764 | | /** |
765 | | * @brief Returns a GenericRapidJsonObjectMember that contains the key and |
766 | | * value belonging to the object member identified by the iterator. |
767 | | */ |
768 | | GenericRapidJsonObjectMember<ValueType> operator*() const |
769 | 0 | { |
770 | 0 | return GenericRapidJsonObjectMember<ValueType>( |
771 | 0 | std::string(m_itr->name.GetString(), m_itr->name.GetStringLength()), |
772 | 0 | m_itr->value); |
773 | 0 | } |
774 | | |
775 | | /// Returns a proxy for the value of the current element |
776 | | DerefProxy<GenericRapidJsonObjectMember<ValueType>> operator->() const |
777 | 0 | { |
778 | 0 | return DerefProxy<GenericRapidJsonObjectMember<ValueType>>(**this); |
779 | 0 | } |
780 | | |
781 | | /** |
782 | | * @brief Compare this iterator with another iterator. |
783 | | * |
784 | | * Note that this directly compares the iterators, not the underlying |
785 | | * values, and assumes that two identical iterators will point to the same |
786 | | * underlying object. |
787 | | * |
788 | | * @param other Iterator to compare with |
789 | | * |
790 | | * @returns true if the underlying iterators are equal, false otherwise |
791 | | */ |
792 | | bool operator==(const GenericRapidJsonObjectMemberIterator<ValueType> &other) const |
793 | 0 | { |
794 | 0 | return m_itr == other.m_itr; |
795 | 0 | } |
796 | | |
797 | | bool operator!=(const GenericRapidJsonObjectMemberIterator<ValueType> &other) const |
798 | 0 | { |
799 | 0 | return m_itr != other.m_itr; |
800 | 0 | } |
801 | | |
802 | | GenericRapidJsonObjectMemberIterator<ValueType>& operator++() |
803 | 0 | { |
804 | 0 | m_itr++; |
805 | 0 | return *this; |
806 | 0 | } |
807 | | |
808 | | GenericRapidJsonObjectMemberIterator<ValueType> operator++(int) |
809 | | { |
810 | | GenericRapidJsonObjectMemberIterator<ValueType> iterator_pre(m_itr); |
811 | | ++(*this); |
812 | | return iterator_pre; |
813 | | } |
814 | | |
815 | | GenericRapidJsonObjectMemberIterator<ValueType>& operator--() |
816 | | { |
817 | | m_itr--; |
818 | | return *this; |
819 | | } |
820 | | |
821 | | std::ptrdiff_t difference(const GenericRapidJsonObjectMemberIterator &other) |
822 | | { |
823 | | return std::distance(m_itr, other.itr); |
824 | | } |
825 | | |
826 | | private: |
827 | | |
828 | | /// Iternal copy of the original RapidJson iterator |
829 | | typename ValueType::ConstMemberIterator m_itr; |
830 | | }; |
831 | | |
832 | | template<class ValueType> |
833 | | inline bool GenericRapidJsonFrozenValue<ValueType>::equalTo(const Adapter &other, bool strict) const |
834 | 0 | { |
835 | 0 | return GenericRapidJsonAdapter<ValueType>(m_value).equalTo(other, strict); |
836 | 0 | } |
837 | | |
838 | | template<class ValueType> |
839 | | inline typename GenericRapidJsonArray<ValueType>::iterator GenericRapidJsonArray<ValueType>::begin() const |
840 | 0 | { |
841 | 0 | return m_value.Begin(); |
842 | 0 | } |
843 | | |
844 | | template<class ValueType> |
845 | | inline typename GenericRapidJsonArray<ValueType>::iterator GenericRapidJsonArray<ValueType>::end() const |
846 | 0 | { |
847 | 0 | return m_value.End(); |
848 | 0 | } |
849 | | |
850 | | template<class ValueType> |
851 | | inline typename GenericRapidJsonObject<ValueType>::iterator GenericRapidJsonObject<ValueType>::begin() const |
852 | 0 | { |
853 | 0 | return m_value.MemberBegin(); |
854 | 0 | } |
855 | | |
856 | | template<class ValueType> |
857 | | inline typename GenericRapidJsonObject<ValueType>::iterator GenericRapidJsonObject<ValueType>::end() const |
858 | 0 | { |
859 | 0 | return m_value.MemberEnd(); |
860 | 0 | } |
861 | | |
862 | | template<class ValueType> |
863 | | inline typename GenericRapidJsonObject<ValueType>::iterator |
864 | | GenericRapidJsonObject<ValueType>::find(const std::string &propertyName) const |
865 | 0 | { |
866 | | // Hack to support older versions of rapidjson where pointers are used as |
867 | | // the built in iterator type. In those versions, the FindMember function |
868 | | // would return a null pointer when the requested member could not be |
869 | | // found. After calling FindMember on an empty object, we compare the |
870 | | // result against what we would expect if a non-null-pointer iterator was |
871 | | // returned. |
872 | 0 | const ValueType empty(rapidjson::kObjectType); |
873 | 0 | const typename ValueType::ConstMemberIterator maybeEnd = empty.FindMember(""); |
874 | 0 | if (maybeEnd != empty.MemberBegin() + 1) { |
875 | | // In addition to the pointer-based iterator issue, RapidJson's internal |
876 | | // string comparison code seemed to rely on the query string being |
877 | | // initialised to a length greater than or equal to that of the |
878 | | // properties being compared. We get around this by implementing our |
879 | | // own linear scan. |
880 | 0 | const size_t propertyNameLength = propertyName.length(); |
881 | 0 | for (typename ValueType::ConstMemberIterator itr = m_value.MemberBegin(); itr != m_value.MemberEnd(); ++itr) { |
882 | 0 | const size_t memberNameLength = itr->name.GetStringLength(); |
883 | 0 | if (memberNameLength == propertyNameLength && |
884 | 0 | strncmp(itr->name.GetString(), propertyName.c_str(), itr->name.GetStringLength()) == 0) { |
885 | 0 | return itr; |
886 | 0 | } |
887 | 0 | } |
888 | | |
889 | 0 | return m_value.MemberEnd(); |
890 | 0 | } |
891 | | |
892 | 0 | return m_value.FindMember(propertyName.c_str()); // Times are good. |
893 | 0 | } |
894 | | |
895 | | typedef GenericRapidJsonAdapter<> RapidJsonAdapter; |
896 | | typedef GenericRapidJsonArray<> RapidJsonArray; |
897 | | typedef GenericRapidJsonArrayValueIterator<> RapidJsonArrayValue; |
898 | | typedef GenericRapidJsonFrozenValue<> RapidJsonFrozenValue; |
899 | | typedef GenericRapidJsonObject<> RapidJsonObject; |
900 | | typedef GenericRapidJsonObjectMember<> RapidJsonObjectMember; |
901 | | typedef GenericRapidJsonObjectMemberIterator<> RapidJsonObjectMemberIterator; |
902 | | typedef GenericRapidJsonValue<> RapidJsonValue; |
903 | | |
904 | | /** |
905 | | * @brief Specialisation of the AdapterTraits template struct for a |
906 | | * RapidJsonAdapter that uses a pool allocator |
907 | | */ |
908 | | template<> |
909 | | struct AdapterTraits<valijson::adapters::RapidJsonAdapter> |
910 | | { |
911 | | typedef rapidjson::Document DocumentType; |
912 | | |
913 | | static std::string adapterName() |
914 | 0 | { |
915 | 0 | return "RapidJsonAdapter"; |
916 | 0 | } |
917 | | }; |
918 | | |
919 | | typedef rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator> RapidJsonCrt; |
920 | | |
921 | | /** |
922 | | * @brief Specialisation of the AdapterTraits template struct for a |
923 | | * RapidJsonAdapter that uses the default CRT allocator |
924 | | */ |
925 | | template<> |
926 | | struct AdapterTraits<valijson::adapters::GenericRapidJsonAdapter<RapidJsonCrt>> |
927 | | { |
928 | | typedef rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> DocumentType; |
929 | | |
930 | | static std::string adapterName() |
931 | 0 | { |
932 | 0 | return "GenericRapidJsonAdapter (using CrtAllocator)"; |
933 | 0 | } |
934 | | }; |
935 | | |
936 | | } // namespace adapters |
937 | | } // namespace valijson |