Coverage Report

Created: 2023-06-07 06:59

/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