Coverage Report

Created: 2025-08-25 06:27

/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
7.67M
      : m_ref(x) { }
valijson::adapters::DerefProxy<valijson::adapters::GenericRapidJsonObjectMember<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > > >::DerefProxy(valijson::adapters::GenericRapidJsonObjectMember<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > > const&)
Line
Count
Source
25
1.02M
      : m_ref(x) { }
valijson::adapters::DerefProxy<valijson::adapters::GenericRapidJsonAdapter<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > > >::DerefProxy(valijson::adapters::GenericRapidJsonAdapter<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > > const&)
Line
Count
Source
25
6.64M
      : m_ref(x) { }
26
27
    Value* operator->()
28
7.67M
    {
29
7.67M
        return std::addressof(m_ref);
30
7.67M
    }
valijson::adapters::DerefProxy<valijson::adapters::GenericRapidJsonObjectMember<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > > >::operator->()
Line
Count
Source
28
1.02M
    {
29
1.02M
        return std::addressof(m_ref);
30
1.02M
    }
Unexecuted instantiation: valijson::adapters::DerefProxy<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, valijson::adapters::StdStringAdapter> >::operator->()
Unexecuted instantiation: valijson::adapters::DerefProxy<valijson::adapters::StdStringAdapter>::operator->()
valijson::adapters::DerefProxy<valijson::adapters::GenericRapidJsonAdapter<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > > >::operator->()
Line
Count
Source
28
6.64M
    {
29
6.64M
        return std::addressof(m_ref);
30
6.64M
    }
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
16.9k
          : m_itr(array.begin()),
114
16.9k
            m_end(array.end()),
115
16.9k
            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
3.05k
        {
126
3.05k
            if (m_itr == m_end) {
127
0
                return false;
128
0
            }
129
130
3.05k
            return AdapterType(*m_itr++).equalTo(adapter, m_strict);
131
3.05k
        }
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
249k
          : m_object(object),
172
249k
            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
146k
        {
184
146k
            const typename ObjectType::const_iterator itr = m_object.find(key);
185
146k
            if (itr == m_object.end()) {
186
133k
                return false;
187
133k
            }
188
189
13.9k
            return (*itr).second.equalTo(value, m_strict);
190
146k
        }
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
17.4M
      : m_value(value) { }
229
230
    bool applyToArray(ArrayValueCallback fn) const override
231
16.9k
    {
232
16.9k
        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
16.9k
        if (m_value.isArray()) {
241
16.9k
            const opt::optional<Array> array = m_value.getArrayOptional();
242
16.9k
            for (const AdapterType element : *array) {
243
3.05k
                if (!fn(element)) {
244
1.36k
                    return false;
245
1.36k
                }
246
3.05k
            }
247
16.9k
        }
248
249
15.5k
        return true;
250
16.9k
    }
251
252
    bool applyToObject(ObjectMemberCallback fn) const override
253
249k
    {
254
249k
        if (!maybeObject()) {
255
0
            return false;
256
0
        }
257
258
249k
        if (m_value.isObject()) {
259
249k
            const opt::optional<Object> object = m_value.getObjectOptional();
260
249k
            for (const ObjectMemberType member : *object) {
261
146k
                if (!fn(member.first, AdapterType(member.second))) {
262
133k
                    return false;
263
133k
                }
264
146k
            }
265
249k
        }
266
267
116k
        return true;
268
249k
    }
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
165k
    {
287
165k
        if (m_value.isArray()) {
288
123k
            return *m_value.getArrayOptional();
289
123k
        } else if (m_value.isObject()) {
290
42.3k
            size_t objectSize;
291
42.3k
            if (m_value.getObjectSize(objectSize) && objectSize == 0) {
292
42.3k
                return ArrayType();
293
42.3k
            }
294
42.3k
        } 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
17.4k
    {
306
17.4k
        bool result;
307
17.4k
        if (asBool(result)) {
308
17.4k
            return result;
309
17.4k
        }
310
311
0
        throwRuntimeError("JSON value cannot be cast to a boolean.");
312
0
    }
313
314
    bool asBool(bool &result) const override
315
17.4k
    {
316
17.4k
        if (m_value.isBool()) {
317
17.3k
            return m_value.getBool(result);
318
17.3k
        } else if (m_value.isString()) {
319
108
            std::string s;
320
108
            if (m_value.getString(s)) {
321
108
                if (s == "true") {
322
48
                    result = true;
323
48
                    return true;
324
60
                } else if (s == "false") {
325
60
                    result = false;
326
60
                    return true;
327
60
                }
328
108
            }
329
108
        }
330
331
0
        return false;
332
17.4k
    }
333
334
    double asDouble() const override
335
19.2k
    {
336
19.2k
        double result;
337
19.2k
        if (asDouble(result)) {
338
19.2k
            return result;
339
19.2k
        }
340
341
0
        throwRuntimeError("JSON value cannot be cast to a double.");
342
0
    }
343
344
    bool asDouble(double &result) const override
345
21.5k
    {
346
21.5k
        if (m_value.isDouble()) {
347
3.13k
            return m_value.getDouble(result);
348
18.4k
        } else if (m_value.isInteger()) {
349
13.9k
            int64_t i;
350
13.9k
            if (m_value.getInteger(i)) {
351
13.9k
                result = double(i);
352
13.9k
                return true;
353
13.9k
            }
354
13.9k
        } else if (m_value.isString()) {
355
4.44k
            std::string s;
356
4.44k
            if (m_value.getString(s)) {
357
4.44k
                const char *b = s.c_str();
358
4.44k
                char *e = nullptr;
359
4.44k
                double x = strtod(b, &e);
360
4.44k
                if (e == b || e != b + s.length()) {
361
0
                    return false;
362
0
                }
363
4.44k
                result = x;
364
4.44k
                return true;
365
4.44k
            }
366
4.44k
        }
367
368
0
        return false;
369
21.5k
    }
370
371
    int64_t asInteger() const override
372
32.5k
    {
373
32.5k
        int64_t result;
374
32.5k
        if (asInteger(result)) {
375
32.5k
            return result;
376
32.5k
        }
377
378
0
        throwRuntimeError("JSON value cannot be cast as an integer.");
379
0
    }
380
381
    bool asInteger(int64_t &result) const override
382
34.5k
    {
383
34.5k
        if (m_value.isInteger()) {
384
19.2k
            return m_value.getInteger(result);
385
19.2k
        } else if (m_value.isString()) {
386
15.2k
            std::string s;
387
15.2k
            if (m_value.getString(s)) {
388
15.2k
                std::istringstream i(s);
389
15.2k
                int64_t x;
390
15.2k
                char c;
391
15.2k
                if (!(!(i >> x) || i.get(c))) {
392
15.2k
                    result = x;
393
15.2k
                    return true;
394
15.2k
                }
395
15.2k
            }
396
15.2k
        }
397
398
0
        return false;
399
34.5k
    }
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
941k
    {
415
941k
        if (m_value.isObject()) {
416
940k
            return *m_value.getObjectOptional();
417
940k
        } else if (m_value.isArray()) {
418
1.21k
            size_t arraySize;
419
1.21k
            if (m_value.getArraySize(arraySize) && arraySize == 0) {
420
1.21k
                return ObjectType();
421
1.21k
            }
422
1.21k
        } 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
211k
    {
434
211k
        std::string result;
435
211k
        if (asString(result)) {
436
211k
            return result;
437
211k
        }
438
439
0
        throwRuntimeError("JSON value cannot be cast to a string.");
440
0
    }
441
442
    bool asString(std::string &result) const override
443
211k
    {
444
211k
        if (m_value.isString()) {
445
168k
            return m_value.getString(result);
446
168k
        } else if (m_value.isNull()) {
447
0
            result.clear();
448
0
            return true;
449
43.6k
        } else if (m_value.isArray()) {
450
5.40k
            size_t arraySize;
451
5.40k
            if (m_value.getArraySize(arraySize) && arraySize == 0) {
452
5.40k
                result.clear();
453
5.40k
                return true;
454
5.40k
            }
455
38.2k
        } else if (m_value.isObject()) {
456
18.6k
            size_t objectSize;
457
18.6k
            if (m_value.getObjectSize(objectSize) && objectSize == 0) {
458
18.6k
                result.clear();
459
18.6k
                return true;
460
18.6k
            }
461
19.5k
        } else if (m_value.isBool()) {
462
1.06k
            bool boolValue;
463
1.06k
            if (m_value.getBool(boolValue)) {
464
1.06k
                result = boolValue ? "true" : "false";
465
1.06k
                return true;
466
1.06k
            }
467
18.4k
        } else if (m_value.isInteger()) {
468
13.9k
            int64_t integerValue;
469
13.9k
            if (m_value.getInteger(integerValue)) {
470
13.9k
                result = std::to_string(integerValue);
471
13.9k
                return true;
472
13.9k
            }
473
13.9k
        } else if (m_value.isDouble()) {
474
4.53k
            double doubleValue;
475
4.53k
            if (m_value.getDouble(doubleValue)) {
476
4.53k
                result = std::to_string(doubleValue);
477
4.53k
                return true;
478
4.53k
            }
479
4.53k
        }
480
481
0
        return false;
482
211k
    }
483
484
    bool equalTo(const Adapter &other, bool strict) const override
485
6.70M
    {
486
6.70M
        if (isNull() || (!strict && maybeNull())) {
487
1.10k
            return other.isNull() || (!strict && other.maybeNull());
488
6.70M
        } else if (isBool() || (!strict && maybeBool())) {
489
1.56k
            return (other.isBool() || (!strict && other.maybeBool())) && other.asBool() == asBool();
490
6.70M
        } else if (isNumber() && strict) {
491
6.06M
            return other.isNumber() && other.getNumber() == getNumber();
492
6.06M
        } else if (!strict && maybeDouble()) {
493
0
            return (other.maybeDouble() && other.asDouble() == asDouble());
494
644k
        } else if (!strict && maybeInteger()) {
495
0
            return (other.maybeInteger() && other.asInteger() == asInteger());
496
644k
        } else if (isString() || (!strict && maybeString())) {
497
57.9k
            return (other.isString() || (!strict && other.maybeString())) &&
498
57.9k
                other.asString() == asString();
499
586k
        } else if (isArray()) {
500
24.3k
            if (other.isArray() && getArraySize() == other.getArraySize()) {
501
16.9k
                const opt::optional<ArrayType> array = m_value.getArrayOptional();
502
16.9k
                if (array) {
503
16.9k
                    ArrayComparisonFunctor fn(*array, strict);
504
16.9k
                    return other.applyToArray(fn);
505
16.9k
                }
506
16.9k
            } else if (!strict && other.maybeArray() && getArraySize() == 0) {
507
0
                return true;
508
0
            }
509
562k
        } else if (isObject()) {
510
562k
            if (other.isObject() && other.getObjectSize() == getObjectSize()) {
511
249k
                const opt::optional<ObjectType> object = m_value.getObjectOptional();
512
249k
                if (object) {
513
249k
                    ObjectComparisonFunctor fn(*object, strict);
514
249k
                    return other.applyToObject(fn);
515
249k
                }
516
312k
            } else if (!strict && other.maybeObject() && getObjectSize() == 0) {
517
0
                return true;
518
0
            }
519
562k
        }
520
521
319k
        return false;
522
6.70M
    }
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
135k
    {
540
135k
        opt::optional<ArrayType> arrayValue = m_value.getArrayOptional();
541
135k
        if (arrayValue) {
542
135k
            return *arrayValue;
543
135k
        }
544
545
387
        throwRuntimeError("JSON value is not an array.");
546
387
    }
547
548
    size_t getArraySize() const override
549
48.2k
    {
550
48.2k
        size_t result;
551
48.2k
        if (m_value.getArraySize(result)) {
552
48.2k
            return result;
553
48.2k
        }
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
17.5k
    {
590
17.5k
        return m_value.getDouble(result);
591
17.5k
    }
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
11.5M
    {
605
11.5M
        return m_value.getInteger(result);
606
11.5M
    }
607
608
    double getNumber() const override
609
11.5M
    {
610
11.5M
        double result;
611
11.5M
        if (getNumber(result)) {
612
11.5M
            return result;
613
11.5M
        }
614
615
0
        throwRuntimeError("JSON value is not a number.");
616
0
    }
617
618
    bool getNumber(double &result) const override
619
11.5M
    {
620
11.5M
        if (isDouble()) {
621
17.5k
            return getDouble(result);
622
11.5M
        } else if (isInteger()) {
623
11.5M
            int64_t integerResult;
624
11.5M
            if (getInteger(integerResult)) {
625
11.5M
                result = static_cast<double>(integerResult);
626
11.5M
                return true;
627
11.5M
            }
628
11.5M
        }
629
630
0
        return false;
631
11.5M
    }
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
1.06M
    {
649
1.06M
        opt::optional<ObjectType> objectValue = m_value.getObjectOptional();
650
1.06M
        if (objectValue) {
651
1.06M
            return *objectValue;
652
1.06M
        }
653
654
99
        throwRuntimeError("JSON value is not an object.");
655
99
    }
656
657
    size_t getObjectSize() const override
658
514k
    {
659
514k
        size_t result;
660
514k
        if (getObjectSize(result)) {
661
514k
            return result;
662
514k
        }
663
664
0
        throwRuntimeError("JSON value is not an object.");
665
0
    }
666
667
    bool getObjectSize(size_t &result) const override
668
514k
    {
669
514k
        return m_value.getObjectSize(result);
670
514k
    }
671
672
    std::string getString() const override
673
221k
    {
674
221k
        std::string result;
675
221k
        if (getString(result)) {
676
220k
            return result;
677
220k
        }
678
679
468
        throwRuntimeError("JSON value is not a string.");
680
468
    }
681
682
    bool getString(std::string &result) const override
683
403k
    {
684
403k
        return m_value.getString(result);
685
403k
    }
686
687
    FrozenValue * freeze() const override
688
77.5k
    {
689
77.5k
        return m_value.freeze();
690
77.5k
    }
691
692
    bool hasStrictTypes() const override
693
21.7k
    {
694
21.7k
        return ValueType::hasStrictTypes();
695
21.7k
    }
696
697
    bool isArray() const override
698
892k
    {
699
892k
        return m_value.isArray();
700
892k
    }
701
702
    bool isBool() const override
703
7.14M
    {
704
7.14M
        return m_value.isBool();
705
7.14M
    }
706
707
    bool isDouble() const override
708
11.5M
    {
709
11.5M
        return m_value.isDouble();
710
11.5M
    }
711
712
    bool isInteger() const override
713
11.5M
    {
714
11.5M
        return m_value.isInteger();
715
11.5M
    }
716
717
    bool isNull() const override
718
6.71M
    {
719
6.71M
        return m_value.isNull();
720
6.71M
    }
721
722
    bool isNumber() const override
723
12.7M
    {
724
12.7M
        return m_value.isInteger() || m_value.isDouble();
725
12.7M
    }
726
727
    bool isObject() const override
728
3.49M
    {
729
3.49M
        return m_value.isObject();
730
3.49M
    }
731
732
    bool isString() const override
733
755k
    {
734
755k
        return m_value.isString();
735
755k
    }
736
737
    bool maybeArray() const override
738
235k
    {
739
235k
        if (m_value.isArray()) {
740
143k
            return true;
741
143k
        } else if (m_value.isObject()) {
742
84.2k
            size_t objectSize;
743
84.2k
            if (m_value.getObjectSize(objectSize) && objectSize == 0) {
744
42.3k
                return true;
745
42.3k
            }
746
84.2k
        }
747
748
49.3k
        return false;
749
235k
    }
750
751
    bool maybeBool() const override
752
33.0k
    {
753
33.0k
        if (m_value.isBool()) {
754
19.4k
            return true;
755
19.4k
        } else if (maybeString()) {
756
8.19k
            std::string stringValue;
757
8.19k
            if (m_value.getString(stringValue)) {
758
1.30k
                if (stringValue == "true" || stringValue == "false") {
759
142
                    return true;
760
142
                }
761
1.30k
            }
762
8.19k
        }
763
764
13.5k
        return false;
765
33.0k
    }
766
767
    bool maybeDouble() const override
768
88.9k
    {
769
88.9k
        if (m_value.isNumber()) {
770
17.1k
            return true;
771
71.8k
        } else if (maybeString()) {
772
14.8k
            std::string s;
773
14.8k
            if (m_value.getString(s)) {
774
12.6k
                const char *b = s.c_str();
775
12.6k
                char *e = nullptr;
776
12.6k
                strtod(b, &e);
777
12.6k
                return e != b && e == b + s.length();
778
12.6k
            }
779
14.8k
        }
780
781
59.2k
        return false;
782
88.9k
    }
783
784
    bool maybeInteger() const override
785
102k
    {
786
102k
        if (m_value.isInteger()) {
787
19.2k
            return true;
788
83.4k
        } else if (maybeString()) {
789
26.4k
            std::string s;
790
26.4k
            if (m_value.getString(s)) {
791
23.5k
                std::istringstream i(s);
792
23.5k
                int64_t x;
793
23.5k
                char c;
794
23.5k
                if (!(i >> x) || i.get(c)) {
795
8.33k
                    return false;
796
8.33k
                }
797
15.2k
                return true;
798
23.5k
            }
799
26.4k
        }
800
801
59.8k
        return false;
802
102k
    }
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
615k
    {
822
615k
        if (m_value.isObject()) {
823
598k
            return true;
824
598k
        } else if (maybeArray()) {
825
9.45k
            size_t arraySize;
826
9.45k
            if (m_value.getArraySize(arraySize) && arraySize == 0) {
827
9.41k
                return true;
828
9.41k
            }
829
9.45k
        }
830
831
7.05k
        return false;
832
615k
    }
833
834
    bool maybeString() const override
835
455k
    {
836
455k
        if (m_value.isString() || m_value.isBool() || m_value.isInteger() || m_value.isDouble()) {
837
302k
            return true;
838
302k
        } else if (m_value.isObject()) {
839
39.6k
            size_t objectSize;
840
39.6k
            if (m_value.getObjectSize(objectSize) && objectSize == 0) {
841
13.2k
                return true;
842
13.2k
            }
843
112k
        } else if (m_value.isArray()) {
844
112k
            size_t arraySize;
845
112k
            if (m_value.getArraySize(arraySize) && arraySize == 0) {
846
12.4k
                return true;
847
12.4k
            }
848
112k
        }
849
850
126k
        return false;
851
455k
    }
852
853
private:
854
855
    const ValueType m_value;
856
};
857
858
}  // namespace adapters
859
}  // namespace valijson