Coverage Report

Created: 2023-03-26 06:57

/src/boost/boost/json/impl/value.ipp
Line
Count
Source (jump to first uncovered line)
1
//
2
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3
//
4
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
//
7
// Official repository: https://github.com/boostorg/json
8
//
9
10
#ifndef BOOST_JSON_IMPL_VALUE_IPP
11
#define BOOST_JSON_IMPL_VALUE_IPP
12
13
#include <boost/container_hash/hash.hpp>
14
#include <boost/json/value.hpp>
15
#include <boost/json/parser.hpp>
16
#include <cstring>
17
#include <istream>
18
#include <limits>
19
#include <new>
20
#include <utility>
21
22
namespace boost {
23
namespace json {
24
25
namespace
26
{
27
28
struct value_hasher
29
{
30
    std::size_t& seed;
31
32
    template< class T >
33
    void operator()( T&& t ) const noexcept
34
0
    {
35
0
        boost::hash_combine( seed, t );
36
0
    }
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<decltype(nullptr)>(decltype(nullptr)&&) const
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<bool>(bool&&) const
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<long>(long&&) const
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<unsigned long>(unsigned long&&) const
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<double>(double&&) const
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<boost::json::string const&>(boost::json::string const&) const
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<boost::json::array const&>(boost::json::array const&) const
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<boost::json::object const&>(boost::json::object const&) const
37
};
38
39
} // namespace
40
41
value::
42
~value() noexcept
43
10.0M
{
44
10.0M
    switch(kind())
45
10.0M
    {
46
18.6k
    case json::kind::null:
47
44.3k
    case json::kind::bool_:
48
4.88M
    case json::kind::int64:
49
4.90M
    case json::kind::uint64:
50
9.86M
    case json::kind::double_:
51
9.86M
        sca_.~scalar();
52
9.86M
        break;
53
54
156k
    case json::kind::string:
55
156k
        str_.~string();
56
156k
        break;
57
58
14.6k
    case json::kind::array:
59
14.6k
        arr_.~array();
60
14.6k
        break;
61
62
22.2k
    case json::kind::object:
63
22.2k
        obj_.~object();
64
22.2k
        break;
65
10.0M
    }
66
10.0M
}
67
68
value::
69
value(
70
    value const& other,
71
    storage_ptr sp)
72
0
{
73
0
    switch(other.kind())
74
0
    {
75
0
    case json::kind::null:
76
0
        ::new(&sca_) scalar(
77
0
            std::move(sp));
78
0
        break;
79
80
0
    case json::kind::bool_:
81
0
        ::new(&sca_) scalar(
82
0
            other.sca_.b,
83
0
            std::move(sp));
84
0
        break;
85
86
0
    case json::kind::int64:
87
0
        ::new(&sca_) scalar(
88
0
            other.sca_.i,
89
0
            std::move(sp));
90
0
        break;
91
92
0
    case json::kind::uint64:
93
0
        ::new(&sca_) scalar(
94
0
            other.sca_.u,
95
0
            std::move(sp));
96
0
        break;
97
98
0
    case json::kind::double_:
99
0
        ::new(&sca_) scalar(
100
0
            other.sca_.d,
101
0
            std::move(sp));
102
0
        break;
103
104
0
    case json::kind::string:
105
0
        ::new(&str_) string(
106
0
            other.str_,
107
0
            std::move(sp));
108
0
        break;
109
110
0
    case json::kind::array:
111
0
        ::new(&arr_) array(
112
0
            other.arr_,
113
0
            std::move(sp));
114
0
        break;
115
116
0
    case json::kind::object:
117
0
        ::new(&obj_) object(
118
0
            other.obj_,
119
0
            std::move(sp));
120
0
        break;
121
0
    }
122
0
}
123
124
value::
125
value(value&& other) noexcept
126
0
{
127
0
    relocate(this, other);
128
0
    ::new(&other.sca_) scalar(sp_);
129
0
}
130
131
value::
132
value(
133
    value&& other,
134
    storage_ptr sp)
135
0
{
136
0
    switch(other.kind())
137
0
    {
138
0
    case json::kind::null:
139
0
        ::new(&sca_) scalar(
140
0
            std::move(sp));
141
0
        break;
142
143
0
    case json::kind::bool_:
144
0
        ::new(&sca_) scalar(
145
0
            other.sca_.b, std::move(sp));
146
0
        break;
147
148
0
    case json::kind::int64:
149
0
        ::new(&sca_) scalar(
150
0
            other.sca_.i, std::move(sp));
151
0
        break;
152
153
0
    case json::kind::uint64:
154
0
        ::new(&sca_) scalar(
155
0
            other.sca_.u, std::move(sp));
156
0
        break;
157
158
0
    case json::kind::double_:
159
0
        ::new(&sca_) scalar(
160
0
            other.sca_.d, std::move(sp));
161
0
        break;
162
163
0
    case json::kind::string:
164
0
        ::new(&str_) string(
165
0
            std::move(other.str_),
166
0
            std::move(sp));
167
0
        break;
168
169
0
    case json::kind::array:
170
0
        ::new(&arr_) array(
171
0
            std::move(other.arr_),
172
0
            std::move(sp));
173
0
        break;
174
175
0
    case json::kind::object:
176
0
        ::new(&obj_) object(
177
0
            std::move(other.obj_),
178
0
            std::move(sp));
179
0
        break;
180
0
    }
181
0
}
182
183
//----------------------------------------------------------
184
//
185
// Conversion
186
//
187
//----------------------------------------------------------
188
189
value::
190
value(
191
    std::initializer_list<value_ref> init,
192
    storage_ptr sp)
193
0
{
194
0
    if(value_ref::maybe_object(init))
195
0
        ::new(&obj_) object(
196
0
            value_ref::make_object(
197
0
                init, std::move(sp)));
198
0
    else
199
0
        ::new(&arr_) array(
200
0
            value_ref::make_array(
201
0
                init, std::move(sp)));
202
0
}
203
204
//----------------------------------------------------------
205
//
206
// Assignment
207
//
208
//----------------------------------------------------------
209
210
value&
211
value::
212
operator=(value const& other)
213
0
{
214
0
    value(other,
215
0
        storage()).swap(*this);
216
0
    return *this;
217
0
}
218
219
value&
220
value::
221
operator=(value&& other)
222
0
{
223
0
    value(std::move(other),
224
0
        storage()).swap(*this);
225
0
    return *this;
226
0
}
227
228
value&
229
value::
230
operator=(
231
    std::initializer_list<value_ref> init)
232
0
{
233
0
    value(init,
234
0
        storage()).swap(*this);
235
0
    return *this;
236
0
}
237
238
value&
239
value::
240
operator=(string_view s)
241
0
{
242
0
    value(s, storage()).swap(*this);
243
0
    return *this;
244
0
}
245
246
value&
247
value::
248
operator=(char const* s)
249
0
{
250
0
    value(s, storage()).swap(*this);
251
0
    return *this;
252
0
}
253
254
value&
255
value::
256
operator=(string const& str)
257
0
{
258
0
    value(str, storage()).swap(*this);
259
0
    return *this;
260
0
}
261
262
value&
263
value::
264
operator=(string&& str)
265
0
{
266
0
    value(std::move(str),
267
0
        storage()).swap(*this);
268
0
    return *this;
269
0
}
270
271
value&
272
value::
273
operator=(array const& arr)
274
0
{
275
0
    value(arr, storage()).swap(*this);
276
0
    return *this;
277
0
}
278
279
value&
280
value::
281
operator=(array&& arr)
282
0
{
283
0
    value(std::move(arr),
284
0
        storage()).swap(*this);
285
0
    return *this;
286
0
}
287
288
value&
289
value::
290
operator=(object const& obj)
291
0
{
292
0
    value(obj, storage()).swap(*this);
293
0
    return *this;
294
0
}
295
296
value&
297
value::
298
operator=(object&& obj)
299
0
{
300
0
    value(std::move(obj),
301
0
        storage()).swap(*this);
302
0
    return *this;
303
0
}
304
305
//----------------------------------------------------------
306
//
307
// Modifiers
308
//
309
//----------------------------------------------------------
310
311
string&
312
value::
313
emplace_string() noexcept
314
0
{
315
0
    return *::new(&str_) string(destroy());
316
0
}
317
318
array&
319
value::
320
emplace_array() noexcept
321
0
{
322
0
    return *::new(&arr_) array(destroy());
323
0
}
324
325
object&
326
value::
327
emplace_object() noexcept
328
0
{
329
0
    return *::new(&obj_) object(destroy());
330
0
}
331
332
void
333
value::
334
swap(value& other)
335
0
{
336
0
    if(*storage() == *other.storage())
337
0
    {
338
        // fast path
339
0
        union U
340
0
        {
341
0
            value tmp;
342
0
            U(){}
343
0
            ~U(){}
344
0
        };
345
0
        U u;
346
0
        relocate(&u.tmp, *this);
347
0
        relocate(this, other);
348
0
        relocate(&other, u.tmp);
349
0
        return;
350
0
    }
351
352
    // copy
353
0
    value temp1(
354
0
        std::move(*this),
355
0
        other.storage());
356
0
    value temp2(
357
0
        std::move(other),
358
0
        this->storage());
359
0
    other.~value();
360
0
    ::new(&other) value(pilfer(temp1));
361
0
    this->~value();
362
0
    ::new(this) value(pilfer(temp2));
363
0
}
364
365
std::istream&
366
operator>>(
367
    std::istream& is,
368
    value& jv)
369
0
{
370
0
    using Traits = std::istream::traits_type;
371
372
    // sentry prepares the stream for reading and finalizes it in destructor
373
0
    std::istream::sentry sentry(is);
374
0
    if( !sentry )
375
0
        return is;
376
377
0
    unsigned char parser_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
378
0
    stream_parser p({}, {}, parser_buf);
379
0
    p.reset( jv.storage() );
380
381
0
    char read_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
382
0
    std::streambuf& buf = *is.rdbuf();
383
0
    std::ios::iostate err = std::ios::goodbit;
384
0
    try
385
0
    {
386
0
        while( true )
387
0
        {
388
0
            error_code ec;
389
390
            // we peek the buffer; this either makes sure that there's no
391
            // more input, or makes sure there's something in the internal
392
            // buffer (so in_avail will return a positive number)
393
0
            std::istream::int_type c = is.rdbuf()->sgetc();
394
            // if we indeed reached EOF, we check if we parsed a full JSON
395
            // document; if not, we error out
396
0
            if( Traits::eq_int_type(c, Traits::eof()) )
397
0
            {
398
0
                err |= std::ios::eofbit;
399
0
                p.finish(ec);
400
0
                if( ec.failed() )
401
0
                    break;
402
0
            }
403
404
            // regardless of reaching EOF, we might have parsed a full JSON
405
            // document; if so, we successfully finish
406
0
            if( p.done() )
407
0
            {
408
0
                jv = p.release();
409
0
                return is;
410
0
            }
411
412
            // at this point we definitely have more input, specifically in
413
            // buf's internal buffer; we also definitely haven't parsed a whole
414
            // document
415
0
            std::streamsize available = buf.in_avail();
416
            // if this assert fails, the streambuf is buggy
417
0
            BOOST_ASSERT( available > 0 );
418
419
0
            available = ( std::min )(
420
0
                static_cast<std::size_t>(available), sizeof(read_buf) );
421
            // we read from the internal buffer of buf into our buffer
422
0
            available = buf.sgetn( read_buf, available );
423
424
0
            std::size_t consumed = p.write_some(
425
0
                read_buf, static_cast<std::size_t>(available), ec );
426
            // if the parser hasn't consumed the entire input we've took from
427
            // buf, we put the remaining data back; this should succeed,
428
            // because we only read data from buf's internal buffer
429
0
            while( consumed++ < static_cast<std::size_t>(available) )
430
0
            {
431
0
                std::istream::int_type const status = buf.sungetc();
432
0
                BOOST_ASSERT( status != Traits::eof() );
433
0
                (void)status;
434
0
            }
435
436
0
            if( ec.failed() )
437
0
                break;
438
0
        }
439
0
    }
440
0
    catch(...)
441
0
    {
442
0
        try
443
0
        {
444
0
            is.setstate(std::ios::badbit);
445
0
        }
446
        // we ignore the exception, because we need to throw the original
447
        // exception instead
448
0
        catch( std::ios::failure const& ) { }
449
450
0
        if( is.exceptions() & std::ios::badbit )
451
0
            throw;
452
0
    }
453
454
0
    is.setstate(err | std::ios::failbit);
455
0
    return is;
456
0
}
457
458
//----------------------------------------------------------
459
//
460
// private
461
//
462
//----------------------------------------------------------
463
464
storage_ptr
465
value::
466
destroy() noexcept
467
0
{
468
0
    switch(kind())
469
0
    {
470
0
    case json::kind::null:
471
0
    case json::kind::bool_:
472
0
    case json::kind::int64:
473
0
    case json::kind::uint64:
474
0
    case json::kind::double_:
475
0
        break;
476
477
0
    case json::kind::string:
478
0
    {
479
0
        auto sp = str_.storage();
480
0
        str_.~string();
481
0
        return sp;
482
0
    }
483
484
0
    case json::kind::array:
485
0
    {
486
0
        auto sp = arr_.storage();
487
0
        arr_.~array();
488
0
        return sp;
489
0
    }
490
491
0
    case json::kind::object:
492
0
    {
493
0
        auto sp = obj_.storage();
494
0
        obj_.~object();
495
0
        return sp;
496
0
    }
497
498
0
    }
499
0
    return std::move(sp_);
500
0
}
501
502
bool
503
value::
504
equal(value const& other) const noexcept
505
0
{
506
0
    switch(kind())
507
0
    {
508
0
    default: // unreachable()?
509
0
    case json::kind::null:
510
0
        return other.kind() == json::kind::null;
511
512
0
    case json::kind::bool_:
513
0
        return
514
0
            other.kind() == json::kind::bool_ &&
515
0
            get_bool() == other.get_bool();
516
517
0
    case json::kind::int64:
518
0
        switch(other.kind())
519
0
        {
520
0
        case json::kind::int64:
521
0
            return get_int64() == other.get_int64();
522
0
        case json::kind::uint64:
523
0
            if(get_int64() < 0)
524
0
                return false;
525
0
            return static_cast<std::uint64_t>(
526
0
                get_int64()) == other.get_uint64();
527
0
        default:
528
0
            return false;
529
0
        }
530
531
0
    case json::kind::uint64:
532
0
        switch(other.kind())
533
0
        {
534
0
        case json::kind::uint64:
535
0
            return get_uint64() == other.get_uint64();
536
0
        case json::kind::int64:
537
0
            if(other.get_int64() < 0)
538
0
                return false;
539
0
            return static_cast<std::uint64_t>(
540
0
                other.get_int64()) == get_uint64();
541
0
        default:
542
0
            return false;
543
0
        }
544
545
0
    case json::kind::double_:
546
0
        return
547
0
            other.kind() == json::kind::double_ &&
548
0
            get_double() == other.get_double();
549
550
0
    case json::kind::string:
551
0
        return
552
0
            other.kind() == json::kind::string &&
553
0
            get_string() == other.get_string();
554
555
0
    case json::kind::array:
556
0
        return
557
0
            other.kind() == json::kind::array &&
558
0
            get_array() == other.get_array();
559
560
0
    case json::kind::object:
561
0
        return
562
0
            other.kind() == json::kind::object &&
563
0
            get_object() == other.get_object();
564
0
    }
565
0
}
566
567
//----------------------------------------------------------
568
//
569
// key_value_pair
570
//
571
//----------------------------------------------------------
572
573
// empty keys point here
574
BOOST_JSON_REQUIRE_CONST_INIT
575
char const
576
key_value_pair::empty_[1] = { 0 };
577
578
key_value_pair::
579
key_value_pair(
580
    pilfered<json::value> key,
581
    pilfered<json::value> value) noexcept
582
    : value_(value)
583
999k
{
584
999k
    std::size_t len;
585
999k
    key_ = access::release_key(key.get(), len);
586
999k
    len_ = static_cast<std::uint32_t>(len);
587
999k
}
588
589
key_value_pair::
590
key_value_pair(
591
    key_value_pair const& other,
592
    storage_ptr sp)
593
    : value_(other.value_, std::move(sp))
594
0
{
595
0
    auto p = reinterpret_cast<
596
0
        char*>(value_.storage()->
597
0
            allocate(other.len_ + 1,
598
0
                alignof(char)));
599
0
    std::memcpy(
600
0
        p, other.key_, other.len_);
601
0
    len_ = other.len_;
602
0
    p[len_] = 0;
603
0
    key_ = p;
604
0
}
605
606
//----------------------------------------------------------
607
608
namespace detail
609
{
610
611
std::size_t
612
hash_value_impl( value const& jv ) noexcept
613
0
{
614
0
    std::size_t seed = 0;
615
616
0
    kind const k = jv.kind();
617
0
    boost::hash_combine( seed, k != kind::int64 ? k : kind::uint64 );
618
619
0
    visit( value_hasher{seed}, jv );
620
0
    return seed;
621
0
}
622
623
} // namespace detail
624
} // namespace json
625
} // namespace boost
626
627
//----------------------------------------------------------
628
//
629
// std::hash specialization
630
//
631
//----------------------------------------------------------
632
633
std::size_t
634
std::hash<::boost::json::value>::operator()(
635
    ::boost::json::value const& jv) const noexcept
636
0
{
637
0
    return ::boost::hash< ::boost::json::value >()( jv );
638
0
}
639
640
//----------------------------------------------------------
641
642
#endif