Coverage Report

Created: 2023-06-07 06:59

/src/valijson/include/valijson/internal/basic_adapter.hpp
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <cstdint>
4
#include <sstream>
5
6
#include <valijson/internal/adapter.hpp>
7
#include <valijson/internal/optional.hpp>
8
#include <valijson/exceptions.hpp>
9
10
namespace valijson {
11
namespace adapters {
12
13
/**
14
 * @brief  A helper for the array and object member iterators.
15
 *
16
 * See http://www.stlsoft.org/doc-1.9/group__group____pattern____dereference__proxy.html
17
 * for motivation
18
 *
19
 * @tparam Value  Name of the value type
20
 */
21
template<class Value>
22
struct DerefProxy
23
{
24
    explicit DerefProxy(const Value& x)
25
0
      : m_ref(x) { }
26
27
    Value* operator->()
28
0
    {
29
0
        return std::addressof(m_ref);
30
0
    }
31
32
    explicit operator Value*()
33
    {
34
        return std::addressof(m_ref);
35
    }
36
37
private:
38
    Value m_ref;
39
};
40
41
/**
42
 * @brief  Template class that implements the expected semantics of an Adapter.
43
 *
44
 * Implementing all of the type-casting functionality for each Adapter is error
45
 * prone and tedious, so this template class aims to minimise the duplication
46
 * of code between various Adapter implementations. This template doesn't quite
47
 * succeed in removing all duplication, but it has greatly simplified the
48
 * implementation of a new Adapter by encapsulating the type-casting semantics
49
 * and a lot of the trivial functionality associated with the Adapter interface.
50
 *
51
 * By inheriting from this template class, Adapter implementations will inherit
52
 * the exception throwing behaviour that is expected by other parts of the
53
 * Valijson library.
54
 *
55
 * @tparam  AdapterType       Self-referential name of the Adapter being
56
 *                            specialised.
57
 * @tparam  ArrayType         Name of the type that will be returned by the
58
 *                            getArray() function. Instances of this type should
59
 *                            provide begin(), end() and size() functions so
60
 *                            that it is possible to iterate over the values in
61
 *                            the array.
62
 * @tparam  ObjectMemberType  Name of the type exposed when iterating over the
63
 *                            contents of an object returned by getObject().
64
 * @tparam  ObjectType        Name of the type that will be returned by the
65
 *                            getObject() function. Instances of this type
66
 *                            should provide begin(), end(), find() and size()
67
 *                            functions so that it is possible to iterate over
68
 *                            the members of the object.
69
 * @tparam  ValueType         Name of the type that provides a consistent
70
 *                            interface to a JSON value for a parser. For
71
 *                            example, this type should provide the getDouble()
72
 *                            and isDouble() functions. But it does not need to
73
 *                            know how to cast values from one type to another -
74
 *                            that functionality is provided by this template
75
 *                            class.
76
 */
77
template<
78
    typename AdapterType,
79
    typename ArrayType,
80
    typename ObjectMemberType,
81
    typename ObjectType,
82
    typename ValueType>
83
class BasicAdapter: public Adapter
84
{
85
protected:
86
87
    /**
88
     * @brief   Functor for comparing two arrays.
89
     *
90
     * This functor is used to compare the elements in an array of the type
91
     * ArrayType with individual values provided as generic Adapter objects.
92
     * Comparison is performed by the () operator.
93
     *
94
     * The functor works by maintaining an iterator for the current position
95
     * in an array. Each time the () operator is called, the value at this
96
     * position is compared with the value passed as an argument to ().
97
     * Immediately after the comparison, the iterator will be incremented.
98
     *
99
     * This functor is designed to be passed to the applyToArray() function
100
     * of an Adapter object.
101
     */
102
    class ArrayComparisonFunctor
103
    {
104
    public:
105
106
        /**
107
         * @brief   Construct an ArrayComparisonFunctor for an array.
108
         *
109
         * @param   array   Array to compare values against
110
         * @param   strict  Flag to use strict type comparison
111
         */
112
        ArrayComparisonFunctor(const ArrayType &array, bool strict)
113
          : m_itr(array.begin()),
114
            m_end(array.end()),
115
0
            m_strict(strict) { }
116
117
        /**
118
         * @brief   Compare a value against the current element in the array.
119
         *
120
         * @param   adapter  Value to be compared with current element
121
         *
122
         * @returns true if values are equal, false otherwise.
123
         */
124
        bool operator()(const Adapter &adapter)
125
0
        {
126
0
            if (m_itr == m_end) {
127
0
                return false;
128
0
            }
129
130
0
            return AdapterType(*m_itr++).equalTo(adapter, m_strict);
131
0
        }
132
133
    private:
134
135
        /// Iterator for current element in the array
136
        typename ArrayType::const_iterator m_itr;
137
138
        /// Iterator for one-past the last element of the array
139
        typename ArrayType::const_iterator m_end;
140
141
        /// Flag to use strict type comparison
142
        const bool m_strict;
143
    };
144
145
    /**
146
     * @brief   Functor for comparing two objects
147
     *
148
     * This functor is used to compare the members of an object of the type
149
     * ObjectType with key-value pairs belonging to another object.
150
     *
151
     * The functor works by maintaining a reference to an object provided via
152
     * the constructor. When time the () operator is called with a key-value
153
     * pair as arguments, the function will attempt to find the key in the
154
     * base object. If found, the associated value will be compared with the
155
     * value provided to the () operator.
156
     *
157
     * This functor is designed to be passed to the applyToObject() function
158
     * of an Adapter object.
159
     */
160
    class ObjectComparisonFunctor
161
    {
162
    public:
163
164
        /**
165
         * @brief   Construct a new ObjectComparisonFunctor for an object.
166
         *
167
         * @param   object  object to use as comparison baseline
168
         * @param   strict  flag to use strict type-checking
169
         */
170
        ObjectComparisonFunctor(const ObjectType &object, bool strict)
171
          : m_object(object),
172
0
            m_strict(strict) { }
173
174
        /**
175
         * @brief   Find a key in the object and compare its value.
176
         *
177
         * @param   key    Key to find
178
         * @param   value  Value to be compared against
179
         *
180
         * @returns true if key is found and values are equal, false otherwise.
181
         */
182
        bool operator()(const std::string &key, const Adapter &value)
183
0
        {
184
0
            const typename ObjectType::const_iterator itr = m_object.find(key);
185
0
            if (itr == m_object.end()) {
186
0
                return false;
187
0
            }
188
189
0
            return (*itr).second.equalTo(value, m_strict);
190
0
        }
191
192
    private:
193
194
        /// Object to be used as a comparison baseline
195
        const ObjectType &m_object;
196
197
        /// Flag to use strict type-checking
198
        bool m_strict;
199
    };
200
201
202
public:
203
204
    /// Alias for ArrayType template parameter
205
    typedef ArrayType Array;
206
207
    /// Alias for ObjectMemberType template parameter
208
    typedef ObjectMemberType ObjectMember;
209
210
    /// Alias for ObjectType template parameter
211
    typedef ObjectType Object;
212
213
    /**
214
     * @brief   Construct an Adapter using the default value.
215
     *
216
     * This constructor relies on the default constructor of the ValueType
217
     * class provided as a template argument.
218
     */
219
    BasicAdapter() = default;
220
221
    /**
222
     * @brief   Construct an Adapter using a specified ValueType object.
223
     *
224
     * This constructor relies on the copy constructor of the ValueType
225
     * class provided as template argument.
226
     */
227
    explicit BasicAdapter(const ValueType &value)
228
103
      : m_value(value) { }
229
230
    bool applyToArray(ArrayValueCallback fn) const override
231
0
    {
232
0
        if (!maybeArray()) {
233
0
            return false;
234
0
        }
235
236
        // Due to the fact that the only way a value can be 'maybe an array' is
237
        // if it is an empty string or empty object, we only need to go to
238
        // effort of constructing an ArrayType instance if the value is
239
        // definitely an array.
240
0
        if (m_value.isArray()) {
241
0
            const opt::optional<Array> array = m_value.getArrayOptional();
242
0
            for (const AdapterType element : *array) {
243
0
                if (!fn(element)) {
244
0
                    return false;
245
0
                }
246
0
            }
247
0
        }
248
249
0
        return true;
250
0
    }
251
252
    bool applyToObject(ObjectMemberCallback fn) const override
253
0
    {
254
0
        if (!maybeObject()) {
255
0
            return false;
256
0
        }
257
258
0
        if (m_value.isObject()) {
259
0
            const opt::optional<Object> object = m_value.getObjectOptional();
260
0
            for (const ObjectMemberType member : *object) {
261
0
                if (!fn(member.first, AdapterType(member.second))) {
262
0
                    return false;
263
0
                }
264
0
            }
265
0
        }
266
267
0
        return true;
268
0
    }
269
270
    /**
271
     * @brief   Return an ArrayType instance containing an array representation
272
     *          of the value held by this Adapter.
273
     *
274
     * This is a convenience function that is not actually declared in the
275
     * Adapter interface, but allows for useful techniques such as procedural
276
     * iteration over the elements in an array. The ArrayType instance that is
277
     * returned by this function is compatible with the BOOST_FOREACH macro.
278
     *
279
     * If the contained value is either an empty object, or an empty string,
280
     * then this function will cast the value to an empty array.
281
     *
282
     * @returns ArrayType instance containing an array representation of the
283
     *          value held by this Adapter.
284
     */
285
    ArrayType asArray() const
286
0
    {
287
0
        if (m_value.isArray()) {
288
0
            return *m_value.getArrayOptional();
289
0
        } else if (m_value.isObject()) {
290
0
            size_t objectSize;
291
0
            if (m_value.getObjectSize(objectSize) && objectSize == 0) {
292
0
                return ArrayType();
293
0
            }
294
0
        } else if (m_value.isString()) {
295
0
            std::string stringValue;
296
0
            if (m_value.getString(stringValue) && stringValue.empty()) {
297
0
                return ArrayType();
298
0
            }
299
0
        }
300
301
0
        throwRuntimeError("JSON value cannot be cast to an array.");
302
0
    }
303
304
    bool asBool() const override
305
0
    {
306
0
        bool result;
307
0
        if (asBool(result)) {
308
0
            return result;
309
0
        }
310
311
0
        throwRuntimeError("JSON value cannot be cast to a boolean.");
312
0
    }
313
314
    bool asBool(bool &result) const override
315
0
    {
316
0
        if (m_value.isBool()) {
317
0
            return m_value.getBool(result);
318
0
        } else if (m_value.isString()) {
319
0
            std::string s;
320
0
            if (m_value.getString(s)) {
321
0
                if (s == "true") {
322
0
                    result = true;
323
0
                    return true;
324
0
                } else if (s == "false") {
325
0
                    result = false;
326
0
                    return true;
327
0
                }
328
0
            }
329
0
        }
330
331
0
        return false;
332
0
    }
333
334
    double asDouble() const override
335
0
    {
336
0
        double result;
337
0
        if (asDouble(result)) {
338
0
            return result;
339
0
        }
340
341
0
        throwRuntimeError("JSON value cannot be cast to a double.");
342
0
    }
343
344
    bool asDouble(double &result) const override
345
0
    {
346
0
        if (m_value.isDouble()) {
347
0
            return m_value.getDouble(result);
348
0
        } else if (m_value.isInteger()) {
349
0
            int64_t i;
350
0
            if (m_value.getInteger(i)) {
351
0
                result = double(i);
352
0
                return true;
353
0
            }
354
0
        } else if (m_value.isString()) {
355
0
            std::string s;
356
0
            if (m_value.getString(s)) {
357
0
                const char *b = s.c_str();
358
0
                char *e = nullptr;
359
0
                double x = strtod(b, &e);
360
0
                if (e == b || e != b + s.length()) {
361
0
                    return false;
362
0
                }
363
0
                result = x;
364
0
                return true;
365
0
            }
366
0
        }
367
368
0
        return false;
369
0
    }
370
371
    int64_t asInteger() const override
372
0
    {
373
0
        int64_t result;
374
0
        if (asInteger(result)) {
375
0
            return result;
376
0
        }
377
378
0
        throwRuntimeError("JSON value cannot be cast as an integer.");
379
0
    }
380
381
    bool asInteger(int64_t &result) const override
382
0
    {
383
0
        if (m_value.isInteger()) {
384
0
            return m_value.getInteger(result);
385
0
        } else if (m_value.isString()) {
386
0
            std::string s;
387
0
            if (m_value.getString(s)) {
388
0
                std::istringstream i(s);
389
0
                int64_t x;
390
0
                char c;
391
0
                if (!(!(i >> x) || i.get(c))) {
392
0
                    result = x;
393
0
                    return true;
394
0
                }
395
0
            }
396
0
        }
397
398
0
        return false;
399
0
    }
400
401
    /**
402
     * @brief   Return an ObjectType instance containing an array representation
403
     *          of the value held by this Adapter.
404
     *
405
     * This is a convenience function that is not actually declared in the
406
     * Adapter interface, but allows for useful techniques such as procedural
407
     * iteration over the members of the object. The ObjectType instance that is
408
     * returned by this function is compatible with the BOOST_FOREACH macro.
409
     *
410
     * @returns ObjectType instance containing an object representation of the
411
     *          value held by this Adapter.
412
     */
413
    ObjectType asObject() const
414
0
    {
415
0
        if (m_value.isObject()) {
416
0
            return *m_value.getObjectOptional();
417
0
        } else if (m_value.isArray()) {
418
0
            size_t arraySize;
419
0
            if (m_value.getArraySize(arraySize) && arraySize == 0) {
420
0
                return ObjectType();
421
0
            }
422
0
        } else if (m_value.isString()) {
423
0
            std::string stringValue;
424
0
            if (m_value.getString(stringValue) && stringValue.empty()) {
425
0
                return ObjectType();
426
0
            }
427
0
        }
428
429
0
        throwRuntimeError("JSON value cannot be cast to an object.");
430
0
    }
431
432
    std::string asString() const override
433
0
    {
434
0
        std::string result;
435
0
        if (asString(result)) {
436
0
            return result;
437
0
        }
438
439
0
        throwRuntimeError("JSON value cannot be cast to a string.");
440
0
    }
441
442
    bool asString(std::string &result) const override
443
0
    {
444
0
        if (m_value.isString()) {
445
0
            return m_value.getString(result);
446
0
        } else if (m_value.isNull()) {
447
0
            result.clear();
448
0
            return true;
449
0
        } else if (m_value.isArray()) {
450
0
            size_t arraySize;
451
0
            if (m_value.getArraySize(arraySize) && arraySize == 0) {
452
0
                result.clear();
453
0
                return true;
454
0
            }
455
0
        } else if (m_value.isObject()) {
456
0
            size_t objectSize;
457
0
            if (m_value.getObjectSize(objectSize) && objectSize == 0) {
458
0
                result.clear();
459
0
                return true;
460
0
            }
461
0
        } else if (m_value.isBool()) {
462
0
            bool boolValue;
463
0
            if (m_value.getBool(boolValue)) {
464
0
                result = boolValue ? "true" : "false";
465
0
                return true;
466
0
            }
467
0
        } else if (m_value.isInteger()) {
468
0
            int64_t integerValue;
469
0
            if (m_value.getInteger(integerValue)) {
470
0
                result = std::to_string(integerValue);
471
0
                return true;
472
0
            }
473
0
        } else if (m_value.isDouble()) {
474
0
            double doubleValue;
475
0
            if (m_value.getDouble(doubleValue)) {
476
0
                result = std::to_string(doubleValue);
477
0
                return true;
478
0
            }
479
0
        }
480
481
0
        return false;
482
0
    }
483
484
    bool equalTo(const Adapter &other, bool strict) const override
485
0
    {
486
0
        if (isNull() || (!strict && maybeNull())) {
487
0
            return other.isNull() || (!strict && other.maybeNull());
488
0
        } else if (isBool() || (!strict && maybeBool())) {
489
0
            return (other.isBool() || (!strict && other.maybeBool())) && other.asBool() == asBool();
490
0
        } else if (isNumber() && strict) {
491
0
            return other.isNumber() && other.getNumber() == getNumber();
492
0
        } else if (!strict && maybeDouble()) {
493
0
            return (other.maybeDouble() && other.asDouble() == asDouble());
494
0
        } else if (!strict && maybeInteger()) {
495
0
            return (other.maybeInteger() && other.asInteger() == asInteger());
496
0
        } else if (isString() || (!strict && maybeString())) {
497
0
            return (other.isString() || (!strict && other.maybeString())) &&
498
0
                other.asString() == asString();
499
0
        } else if (isArray()) {
500
0
            if (other.isArray() && getArraySize() == other.getArraySize()) {
501
0
                const opt::optional<ArrayType> array = m_value.getArrayOptional();
502
0
                if (array) {
503
0
                    ArrayComparisonFunctor fn(*array, strict);
504
0
                    return other.applyToArray(fn);
505
0
                }
506
0
            } else if (!strict && other.maybeArray() && getArraySize() == 0) {
507
0
                return true;
508
0
            }
509
0
        } else if (isObject()) {
510
0
            if (other.isObject() && other.getObjectSize() == getObjectSize()) {
511
0
                const opt::optional<ObjectType> object = m_value.getObjectOptional();
512
0
                if (object) {
513
0
                    ObjectComparisonFunctor fn(*object, strict);
514
0
                    return other.applyToObject(fn);
515
0
                }
516
0
            } else if (!strict && other.maybeObject() && getObjectSize() == 0) {
517
0
                return true;
518
0
            }
519
0
        }
520
521
0
        return false;
522
0
    }
523
524
    /**
525
     * @brief   Return an ArrayType instance representing the array contained
526
     *          by this Adapter instance.
527
     *
528
     * This is a convenience function that is not actually declared in the
529
     * Adapter interface, but allows for useful techniques such as procedural
530
     * iteration over the elements in an array. The ArrayType instance that is
531
     * returned by this function is compatible with the BOOST_FOREACH macro.
532
     *
533
     * If the contained is not an array, this function will throw an exception.
534
     *
535
     * @returns ArrayType instance containing an array representation of the
536
     *          value held by this Adapter.
537
     */
538
    ArrayType getArray() const
539
0
    {
540
0
        opt::optional<ArrayType> arrayValue = m_value.getArrayOptional();
541
0
        if (arrayValue) {
542
0
            return *arrayValue;
543
0
        }
544
545
0
        throwRuntimeError("JSON value is not an array.");
546
0
    }
547
548
    size_t getArraySize() const override
549
0
    {
550
0
        size_t result;
551
0
        if (m_value.getArraySize(result)) {
552
0
            return result;
553
0
        }
554
555
0
        throwRuntimeError("JSON value is not an array.");
556
0
    }
557
558
    bool getArraySize(size_t &result) const override
559
0
    {
560
0
        return m_value.getArraySize(result);
561
0
    }
562
563
    bool getBool() const override
564
0
    {
565
0
        bool result;
566
0
        if (getBool(result)) {
567
0
            return result;
568
0
        }
569
570
0
        throwRuntimeError("JSON value is not a boolean.");
571
0
    }
572
573
    bool getBool(bool &result) const override
574
0
    {
575
0
        return m_value.getBool(result);
576
0
    }
577
578
    double getDouble() const override
579
0
    {
580
0
        double result;
581
0
        if (getDouble(result)) {
582
0
            return result;
583
0
        }
584
585
0
        throwRuntimeError("JSON value is not a double.");
586
0
    }
587
588
    bool getDouble(double &result) const override
589
0
    {
590
0
        return m_value.getDouble(result);
591
0
    }
592
593
    int64_t getInteger() const override
594
0
    {
595
0
        int64_t result;
596
0
        if (getInteger(result)) {
597
0
            return result;
598
0
        }
599
600
0
        throwRuntimeError("JSON value is not an integer.");
601
0
    }
602
603
    bool getInteger(int64_t &result) const override
604
0
    {
605
0
        return m_value.getInteger(result);
606
0
    }
607
608
    double getNumber() const override
609
0
    {
610
0
        double result;
611
0
        if (getNumber(result)) {
612
0
            return result;
613
0
        }
614
615
0
        throwRuntimeError("JSON value is not a number.");
616
0
    }
617
618
    bool getNumber(double &result) const override
619
0
    {
620
0
        if (isDouble()) {
621
0
            return getDouble(result);
622
0
        } else if (isInteger()) {
623
0
            int64_t integerResult;
624
0
            if (getInteger(integerResult)) {
625
0
                result = static_cast<double>(integerResult);
626
0
                return true;
627
0
            }
628
0
        }
629
630
0
        return false;
631
0
    }
632
633
    /**
634
     * @brief   Return an ObjectType instance representing the object contained
635
     *          by this Adapter instance.
636
     *
637
     * This is a convenience function that is not actually declared in the
638
     * Adapter interface, but allows for useful techniques such as procedural
639
     * iteration over the members of an object. The ObjectType instance that is
640
     * returned by this function is compatible with the BOOST_FOREACH macro.
641
     *
642
     * If the contained is not an object, this function will throw an exception.
643
     *
644
     * @returns ObjectType instance containing an array representation of the
645
     *          value held by this Adapter.
646
     */
647
    ObjectType getObject() const
648
0
    {
649
0
        opt::optional<ObjectType> objectValue = m_value.getObjectOptional();
650
0
        if (objectValue) {
651
0
            return *objectValue;
652
0
        }
653
654
0
        throwRuntimeError("JSON value is not an object.");
655
0
    }
656
657
    size_t getObjectSize() const override
658
0
    {
659
0
        size_t result;
660
0
        if (getObjectSize(result)) {
661
0
            return result;
662
0
        }
663
664
0
        throwRuntimeError("JSON value is not an object.");
665
0
    }
666
667
    bool getObjectSize(size_t &result) const override
668
0
    {
669
0
        return m_value.getObjectSize(result);
670
0
    }
671
672
    std::string getString() const override
673
0
    {
674
0
        std::string result;
675
0
        if (getString(result)) {
676
0
            return result;
677
0
        }
678
679
0
        throwRuntimeError("JSON value is not a string.");
680
0
    }
681
682
    bool getString(std::string &result) const override
683
0
    {
684
0
        return m_value.getString(result);
685
0
    }
686
687
    FrozenValue * freeze() const override
688
0
    {
689
0
        return m_value.freeze();
690
0
    }
691
692
    bool hasStrictTypes() const override
693
0
    {
694
0
        return ValueType::hasStrictTypes();
695
0
    }
696
697
    bool isArray() const override
698
103
    {
699
103
        return m_value.isArray();
700
103
    }
701
702
    bool isBool() const override
703
0
    {
704
0
        return m_value.isBool();
705
0
    }
706
707
    bool isDouble() const override
708
0
    {
709
0
        return m_value.isDouble();
710
0
    }
711
712
    bool isInteger() const override
713
0
    {
714
0
        return m_value.isInteger();
715
0
    }
716
717
    bool isNull() const override
718
103
    {
719
103
        return m_value.isNull();
720
103
    }
721
722
    bool isNumber() const override
723
0
    {
724
0
        return m_value.isInteger() || m_value.isDouble();
725
0
    }
726
727
    bool isObject() const override
728
309
    {
729
309
        return m_value.isObject();
730
309
    }
731
732
    bool isString() const override
733
103
    {
734
103
        return m_value.isString();
735
103
    }
736
737
    bool maybeArray() const override
738
0
    {
739
0
        if (m_value.isArray()) {
740
0
            return true;
741
0
        } else if (m_value.isObject()) {
742
0
            size_t objectSize;
743
0
            if (m_value.getObjectSize(objectSize) && objectSize == 0) {
744
0
                return true;
745
0
            }
746
0
        }
747
748
0
        return false;
749
0
    }
750
751
    bool maybeBool() const override
752
103
    {
753
103
        if (m_value.isBool()) {
754
0
            return true;
755
103
        } else if (maybeString()) {
756
0
            std::string stringValue;
757
0
            if (m_value.getString(stringValue)) {
758
0
                if (stringValue == "true" || stringValue == "false") {
759
0
                    return true;
760
0
                }
761
0
            }
762
0
        }
763
764
103
        return false;
765
103
    }
766
767
    bool maybeDouble() const override
768
0
    {
769
0
        if (m_value.isNumber()) {
770
0
            return true;
771
0
        } else if (maybeString()) {
772
0
            std::string s;
773
0
            if (m_value.getString(s)) {
774
0
                const char *b = s.c_str();
775
0
                char *e = nullptr;
776
0
                strtod(b, &e);
777
0
                return e != b && e == b + s.length();
778
0
            }
779
0
        }
780
781
0
        return false;
782
0
    }
783
784
    bool maybeInteger() const override
785
0
    {
786
0
        if (m_value.isInteger()) {
787
0
            return true;
788
0
        } else if (maybeString()) {
789
0
            std::string s;
790
0
            if (m_value.getString(s)) {
791
0
                std::istringstream i(s);
792
0
                int64_t x;
793
0
                char c;
794
0
                if (!(i >> x) || i.get(c)) {
795
0
                    return false;
796
0
                }
797
0
                return true;
798
0
            }
799
0
        }
800
801
0
        return false;
802
0
    }
803
804
    bool maybeNull() const override
805
0
    {
806
0
        if (m_value.isNull()) {
807
0
            return true;
808
0
        } else if (maybeString()) {
809
0
            std::string stringValue;
810
0
            if (m_value.getString(stringValue)) {
811
0
                if (stringValue.empty()) {
812
0
                    return true;
813
0
                }
814
0
            }
815
0
        }
816
817
0
        return false;
818
0
    }
819
820
    bool maybeObject() const override
821
0
    {
822
0
        if (m_value.isObject()) {
823
0
            return true;
824
0
        } else if (maybeArray()) {
825
0
            size_t arraySize;
826
0
            if (m_value.getArraySize(arraySize) && arraySize == 0) {
827
0
                return true;
828
0
            }
829
0
        }
830
831
0
        return false;
832
0
    }
833
834
    bool maybeString() const override
835
103
    {
836
103
        if (m_value.isString() || m_value.isBool() || m_value.isInteger() || m_value.isDouble()) {
837
0
            return true;
838
103
        } else if (m_value.isObject()) {
839
0
            size_t objectSize;
840
0
            if (m_value.getObjectSize(objectSize) && objectSize == 0) {
841
0
                return true;
842
0
            }
843
103
        } else if (m_value.isArray()) {
844
0
            size_t arraySize;
845
0
            if (m_value.getArraySize(arraySize) && arraySize == 0) {
846
0
                return true;
847
0
            }
848
0
        }
849
850
103
        return false;
851
103
    }
852
853
private:
854
855
    const ValueType m_value;
856
};
857
858
}  // namespace adapters
859
}  // namespace valijson