Coverage Report

Created: 2026-08-13 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boost/boost/json/impl/value.ipp
Line
Count
Source
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
int parse_depth_xalloc = std::ios::xalloc();
29
int parse_flags_xalloc = std::ios::xalloc();
30
31
struct value_hasher
32
{
33
    std::size_t& seed;
34
35
    template< class T >
36
    void operator()( T&& t ) const noexcept
37
0
    {
38
0
        boost::hash_combine( seed, t );
39
0
    }
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
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<bool const&>(bool const&) const
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<long const&>(long const&) const
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<unsigned long const&>(unsigned long const&) const
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<double const&>(double const&) const
Unexecuted instantiation: src.cpp:void boost::json::(anonymous namespace)::value_hasher::operator()<decltype(nullptr) const&>(decltype(nullptr) const&) const
40
};
41
42
enum class stream_parse_flags
43
{
44
    allow_comments = 1 << 0,
45
    allow_trailing_commas = 1 << 1,
46
    allow_invalid_utf8 = 1 << 2,
47
};
48
49
long
50
to_bitmask( parse_options const& opts )
51
0
{
52
0
    using E = stream_parse_flags;
53
0
    return
54
0
        (opts.allow_comments ?
55
0
            static_cast<long>(E::allow_comments) : 0) |
56
0
        (opts.allow_trailing_commas ?
57
0
            static_cast<long>(E::allow_trailing_commas) : 0) |
58
0
        (opts.allow_invalid_utf8 ?
59
0
            static_cast<long>(E::allow_invalid_utf8) : 0);
60
0
}
61
62
parse_options
63
get_parse_options( std::istream& is )
64
0
{
65
0
    long const flags = is.iword(parse_flags_xalloc);
66
67
0
    using E = stream_parse_flags;
68
0
    parse_options opts;
69
0
    opts.allow_comments =
70
0
        flags & static_cast<long>(E::allow_comments) ? true : false;
71
0
    opts.allow_trailing_commas =
72
0
        flags & static_cast<long>(E::allow_trailing_commas) ? true : false;
73
0
    opts.allow_invalid_utf8 =
74
0
        flags & static_cast<long>(E::allow_invalid_utf8) ? true : false;
75
0
    return opts;
76
0
}
77
78
} // namespace
79
80
value::
81
~value() noexcept
82
7.14M
{
83
7.14M
    switch(kind())
84
7.14M
    {
85
36.5k
    case json::kind::null:
86
72.4k
    case json::kind::bool_:
87
3.44M
    case json::kind::int64:
88
3.49M
    case json::kind::uint64:
89
6.69M
    case json::kind::double_:
90
6.69M
        sca_.~scalar();
91
6.69M
        break;
92
93
406k
    case json::kind::string:
94
406k
        str_.~string();
95
406k
        break;
96
97
16.8k
    case json::kind::array:
98
16.8k
        arr_.~array();
99
16.8k
        break;
100
101
26.6k
    case json::kind::object:
102
26.6k
        obj_.~object();
103
26.6k
        break;
104
7.14M
    }
105
7.14M
}
106
107
value::
108
value(
109
    value const& other,
110
    storage_ptr sp)
111
0
{
112
0
    switch(other.kind())
113
0
    {
114
0
    case json::kind::null:
115
0
        ::new(&sca_) scalar(
116
0
            std::move(sp));
117
0
        break;
118
119
0
    case json::kind::bool_:
120
0
        ::new(&sca_) scalar(
121
0
            other.sca_.b,
122
0
            std::move(sp));
123
0
        break;
124
125
0
    case json::kind::int64:
126
0
        ::new(&sca_) scalar(
127
0
            other.sca_.i,
128
0
            std::move(sp));
129
0
        break;
130
131
0
    case json::kind::uint64:
132
0
        ::new(&sca_) scalar(
133
0
            other.sca_.u,
134
0
            std::move(sp));
135
0
        break;
136
137
0
    case json::kind::double_:
138
0
        ::new(&sca_) scalar(
139
0
            other.sca_.d,
140
0
            std::move(sp));
141
0
        break;
142
143
0
    case json::kind::string:
144
0
        ::new(&str_) string(
145
0
            other.str_,
146
0
            std::move(sp));
147
0
        break;
148
149
0
    case json::kind::array:
150
0
        ::new(&arr_) array(
151
0
            other.arr_,
152
0
            std::move(sp));
153
0
        break;
154
155
0
    case json::kind::object:
156
0
        ::new(&obj_) object(
157
0
            other.obj_,
158
0
            std::move(sp));
159
0
        break;
160
0
    }
161
0
}
162
163
value::
164
value(value&& other) noexcept
165
0
{
166
0
    relocate(this, other);
167
0
    ::new(&other.sca_) scalar(sp_);
168
0
}
169
170
value::
171
value(
172
    value&& other,
173
    storage_ptr sp)
174
0
{
175
0
    switch(other.kind())
176
0
    {
177
0
    case json::kind::null:
178
0
        ::new(&sca_) scalar(
179
0
            std::move(sp));
180
0
        break;
181
182
0
    case json::kind::bool_:
183
0
        ::new(&sca_) scalar(
184
0
            other.sca_.b, std::move(sp));
185
0
        break;
186
187
0
    case json::kind::int64:
188
0
        ::new(&sca_) scalar(
189
0
            other.sca_.i, std::move(sp));
190
0
        break;
191
192
0
    case json::kind::uint64:
193
0
        ::new(&sca_) scalar(
194
0
            other.sca_.u, std::move(sp));
195
0
        break;
196
197
0
    case json::kind::double_:
198
0
        ::new(&sca_) scalar(
199
0
            other.sca_.d, std::move(sp));
200
0
        break;
201
202
0
    case json::kind::string:
203
0
        ::new(&str_) string(
204
0
            std::move(other.str_),
205
0
            std::move(sp));
206
0
        break;
207
208
0
    case json::kind::array:
209
0
        ::new(&arr_) array(
210
0
            std::move(other.arr_),
211
0
            std::move(sp));
212
0
        break;
213
214
0
    case json::kind::object:
215
0
        ::new(&obj_) object(
216
0
            std::move(other.obj_),
217
0
            std::move(sp));
218
0
        break;
219
0
    }
220
0
}
221
222
//----------------------------------------------------------
223
//
224
// Conversion
225
//
226
//----------------------------------------------------------
227
228
value::
229
value(
230
    std::initializer_list<value_ref> init,
231
    storage_ptr sp)
232
0
{
233
0
    if(value_ref::maybe_object(init))
234
0
    {
235
0
        ::new(&obj_) object(
236
0
            value_ref::make_object(
237
0
                init, std::move(sp)));
238
0
    }
239
0
    else
240
0
    {
241
0
        if( init.size() == 1 )
242
0
        {
243
0
            ::new(this) value(
244
0
                init.begin()->make_value( std::move(sp) ));
245
0
        }
246
0
        else
247
0
        {
248
0
            ::new(&arr_) array(
249
0
                value_ref::make_array(
250
0
                    init, std::move(sp)));
251
0
        }
252
0
    }
253
0
}
254
255
//----------------------------------------------------------
256
//
257
// Assignment
258
//
259
//----------------------------------------------------------
260
261
value&
262
value::
263
operator=(value const& other)
264
0
{
265
0
    value(other,
266
0
        storage()).swap(*this);
267
0
    return *this;
268
0
}
269
270
value&
271
value::
272
operator=(value&& other)
273
0
{
274
0
    value(std::move(other),
275
0
        storage()).swap(*this);
276
0
    return *this;
277
0
}
278
279
value&
280
value::
281
operator=(
282
    std::initializer_list<value_ref> init)
283
0
{
284
0
    value(init,
285
0
        storage()).swap(*this);
286
0
    return *this;
287
0
}
288
289
value&
290
value::
291
operator=(string_view s)
292
0
{
293
0
    value(s, storage()).swap(*this);
294
0
    return *this;
295
0
}
296
297
value&
298
value::
299
operator=(char const* s)
300
0
{
301
0
    value(s, storage()).swap(*this);
302
0
    return *this;
303
0
}
304
305
value&
306
value::
307
operator=(string const& str)
308
0
{
309
0
    value(str, storage()).swap(*this);
310
0
    return *this;
311
0
}
312
313
value&
314
value::
315
operator=(string&& str)
316
0
{
317
0
    value(std::move(str),
318
0
        storage()).swap(*this);
319
0
    return *this;
320
0
}
321
322
value&
323
value::
324
operator=(array const& arr)
325
0
{
326
0
    value(arr, storage()).swap(*this);
327
0
    return *this;
328
0
}
329
330
value&
331
value::
332
operator=(array&& arr)
333
0
{
334
0
    value(std::move(arr),
335
0
        storage()).swap(*this);
336
0
    return *this;
337
0
}
338
339
value&
340
value::
341
operator=(object const& obj)
342
0
{
343
0
    value(obj, storage()).swap(*this);
344
0
    return *this;
345
0
}
346
347
value&
348
value::
349
operator=(object&& obj)
350
0
{
351
0
    value(std::move(obj),
352
0
        storage()).swap(*this);
353
0
    return *this;
354
0
}
355
356
//----------------------------------------------------------
357
//
358
// Accessors
359
//
360
//----------------------------------------------------------
361
362
system::result<array&>
363
value::try_as_array() noexcept
364
0
{
365
0
    if( is_array() )
366
0
        return arr_;
367
368
0
    system::error_code ec;
369
0
    BOOST_JSON_FAIL(ec, error::not_array);
370
0
    return ec;
371
0
}
372
373
system::result<array const&>
374
value::try_as_array() const noexcept
375
0
{
376
0
    if( is_array() )
377
0
        return arr_;
378
379
0
    system::error_code ec;
380
0
    BOOST_JSON_FAIL(ec, error::not_array);
381
0
    return ec;
382
0
}
383
384
system::result<object&>
385
value::try_as_object() noexcept
386
0
{
387
0
    if( is_object() )
388
0
        return obj_;
389
390
0
    system::error_code ec;
391
0
    BOOST_JSON_FAIL(ec, error::not_object);
392
0
    return ec;
393
0
}
394
395
system::result<object const&>
396
value::try_as_object() const noexcept
397
0
{
398
0
    if( is_object() )
399
0
        return obj_;
400
401
0
    system::error_code ec;
402
0
    BOOST_JSON_FAIL(ec, error::not_object);
403
0
    return ec;
404
0
}
405
406
system::result<string&>
407
value::try_as_string() noexcept
408
0
{
409
0
    if( is_string() )
410
0
        return str_;
411
412
0
    system::error_code ec;
413
0
    BOOST_JSON_FAIL(ec, error::not_string);
414
0
    return ec;
415
0
}
416
417
system::result<string const&>
418
value::try_as_string() const noexcept
419
0
{
420
0
    if( is_string() )
421
0
        return str_;
422
423
0
    system::error_code ec;
424
0
    BOOST_JSON_FAIL(ec, error::not_string);
425
0
    return ec;
426
0
}
427
428
system::result<std::int64_t&>
429
value::try_as_int64() noexcept
430
0
{
431
0
    if( is_int64() )
432
0
        return sca_.i;
433
434
0
    system::error_code ec;
435
0
    BOOST_JSON_FAIL(ec, error::not_int64);
436
0
    return ec;
437
0
}
438
439
system::result<std::int64_t>
440
value::try_as_int64() const noexcept
441
0
{
442
0
    if( is_int64() )
443
0
        return sca_.i;
444
445
0
    system::error_code ec;
446
0
    BOOST_JSON_FAIL(ec, error::not_int64);
447
0
    return ec;
448
0
}
449
450
system::result<std::uint64_t&>
451
value::try_as_uint64() noexcept
452
0
{
453
0
    if( is_uint64() )
454
0
        return sca_.u;
455
456
0
    system::error_code ec;
457
0
    BOOST_JSON_FAIL(ec, error::not_uint64);
458
0
    return ec;
459
0
}
460
461
system::result<std::uint64_t>
462
value::try_as_uint64() const noexcept
463
0
{
464
0
    if( is_uint64() )
465
0
        return sca_.u;
466
467
0
    system::error_code ec;
468
0
    BOOST_JSON_FAIL(ec, error::not_uint64);
469
0
    return ec;
470
0
}
471
472
system::result<double&>
473
value::try_as_double() noexcept
474
0
{
475
0
    if( is_double() )
476
0
        return sca_.d;
477
478
0
    system::error_code ec;
479
0
    BOOST_JSON_FAIL(ec, error::not_double);
480
0
    return ec;
481
0
}
482
483
system::result<double>
484
value::try_as_double() const noexcept
485
0
{
486
0
    if( is_double() )
487
0
        return sca_.d;
488
489
0
    system::error_code ec;
490
0
    BOOST_JSON_FAIL(ec, error::not_double);
491
0
    return ec;
492
0
}
493
494
system::result<bool&>
495
value::try_as_bool() noexcept
496
0
{
497
0
    if( is_bool() )
498
0
        return sca_.b;
499
500
0
    system::error_code ec;
501
0
    BOOST_JSON_FAIL(ec, error::not_bool);
502
0
    return ec;
503
0
}
504
505
system::result<bool>
506
value::try_as_bool() const noexcept
507
0
{
508
0
    if( is_bool() )
509
0
        return sca_.b;
510
511
0
    system::error_code ec;
512
0
    BOOST_JSON_FAIL(ec, error::not_bool);
513
0
    return ec;
514
0
}
515
516
system::result<std::nullptr_t>
517
value::try_as_null() const noexcept
518
0
{
519
0
    if( is_null() )
520
0
        return nullptr;
521
522
0
    system::error_code ec;
523
0
    BOOST_JSON_FAIL(ec, error::not_null);
524
0
    return ec;
525
0
}
526
527
boost::system::result<value&>
528
value::try_at(string_view key) noexcept
529
0
{
530
0
    auto r = try_as_object();
531
0
    if( !r )
532
0
        return r.error();
533
0
    return r.unsafe_value().try_at(key);
534
0
}
535
536
boost::system::result<value const&>
537
value::try_at(string_view key) const noexcept
538
0
{
539
0
    auto r = try_as_object();
540
0
    if( !r )
541
0
        return r.error();
542
0
    return r.unsafe_value().try_at(key);
543
0
}
544
545
boost::system::result<value&>
546
value::try_at(std::size_t pos) noexcept
547
0
{
548
0
    auto r = try_as_array();
549
0
    if( !r )
550
0
        return r.error();
551
0
    return r.unsafe_value().try_at(pos);
552
0
}
553
554
boost::system::result<value const&>
555
value::try_at(std::size_t pos) const noexcept
556
0
{
557
0
    auto r = try_as_array();
558
0
    if( !r )
559
0
        return r.error();
560
0
    return r.unsafe_value().try_at(pos);
561
0
}
562
563
object const&
564
value::as_object(source_location const& loc) const&
565
0
{
566
0
    return try_as_object().value(loc);
567
0
}
568
569
array const&
570
value::as_array(source_location const& loc) const&
571
0
{
572
0
    return try_as_array().value(loc);
573
0
}
574
575
string const&
576
value::as_string(source_location const& loc) const&
577
0
{
578
0
    return try_as_string().value(loc);
579
0
}
580
581
std::int64_t&
582
value::as_int64(source_location const& loc)
583
0
{
584
0
    return try_as_int64().value(loc);
585
0
}
586
587
std::int64_t
588
value::as_int64(source_location const& loc) const
589
0
{
590
0
    return try_as_int64().value(loc);
591
0
}
592
593
std::uint64_t&
594
value::as_uint64(source_location const& loc)
595
0
{
596
0
    return try_as_uint64().value(loc);
597
0
}
598
599
std::uint64_t
600
value::as_uint64(source_location const& loc) const
601
0
{
602
0
    return try_as_uint64().value(loc);
603
0
}
604
605
double&
606
value::as_double(source_location const& loc)
607
0
{
608
0
    return try_as_double().value(loc);
609
0
}
610
611
double
612
value::as_double(source_location const& loc) const
613
0
{
614
0
    return try_as_double().value(loc);
615
0
}
616
617
bool&
618
value::as_bool(source_location const& loc)
619
0
{
620
0
    return try_as_bool().value(loc);
621
0
}
622
623
bool
624
value::as_bool(source_location const& loc) const
625
0
{
626
0
    return try_as_bool().value(loc);
627
0
}
628
629
//----------------------------------------------------------
630
//
631
// Modifiers
632
//
633
//----------------------------------------------------------
634
635
string&
636
value::
637
emplace_string() noexcept
638
0
{
639
0
    storage_ptr sp = destroy();
640
0
    return *::new(&str_) string(sp);
641
0
}
642
643
array&
644
value::
645
emplace_array() noexcept
646
0
{
647
0
    storage_ptr sp = destroy();
648
0
    return *::new(&arr_) array(sp);
649
0
}
650
651
object&
652
value::
653
emplace_object() noexcept
654
0
{
655
0
    storage_ptr sp = destroy();
656
0
    return *::new(&obj_) object(sp);
657
0
}
658
659
void
660
value::
661
swap(value& other)
662
0
{
663
0
    if(*storage() == *other.storage())
664
0
    {
665
        // fast path
666
0
        union U
667
0
        {
668
0
            value tmp;
669
0
            U(){}
670
0
            ~U(){}
671
0
        };
672
0
        U u;
673
0
        relocate(&u.tmp, *this);
674
0
        relocate(this, other);
675
0
        relocate(&other, u.tmp);
676
0
        return;
677
0
    }
678
679
    // copy
680
0
    value temp1(
681
0
        std::move(*this),
682
0
        other.storage());
683
0
    value temp2(
684
0
        std::move(other),
685
0
        this->storage());
686
0
    other.~value();
687
0
    ::new(&other) value(pilfer(temp1));
688
0
    this->~value();
689
0
    ::new(this) value(pilfer(temp2));
690
0
}
691
692
std::istream&
693
operator>>(
694
    std::istream& is,
695
    value& jv)
696
0
{
697
0
    using Traits = std::istream::traits_type;
698
699
    // sentry prepares the stream for reading and finalizes it in destructor
700
0
    std::istream::sentry sentry(is);
701
0
    if( !sentry )
702
0
        return is;
703
704
0
    parse_options opts = get_parse_options( is );
705
0
    if( auto depth = static_cast<std::size_t>( is.iword(parse_depth_xalloc) ) )
706
0
        opts.max_depth = depth;
707
708
0
    unsigned char parser_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
709
0
    stream_parser p( {}, opts, parser_buf );
710
0
    p.reset( jv.storage() );
711
712
0
    char read_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
713
0
    std::streambuf& buf = *is.rdbuf();
714
0
    std::ios::iostate err = std::ios::goodbit;
715
0
#ifndef BOOST_NO_EXCEPTIONS
716
0
    try
717
0
#endif
718
0
    {
719
0
        while( true )
720
0
        {
721
0
            system::error_code ec;
722
723
            // we peek the buffer; this either makes sure that there's no
724
            // more input, or makes sure there's something in the internal
725
            // buffer (so in_avail will return a positive number)
726
0
            std::istream::int_type c = is.rdbuf()->sgetc();
727
            // if we indeed reached EOF, we check if we parsed a full JSON
728
            // document; if not, we error out
729
0
            if( Traits::eq_int_type(c, Traits::eof()) )
730
0
            {
731
0
                err |= std::ios::eofbit;
732
0
                p.finish(ec);
733
0
                if( ec.failed() )
734
0
                    break;
735
0
            }
736
737
            // regardless of reaching EOF, we might have parsed a full JSON
738
            // document; if so, we successfully finish
739
0
            if( p.done() )
740
0
            {
741
0
                jv = p.release();
742
0
                return is;
743
0
            }
744
745
            // at this point we definitely have more input, specifically in
746
            // buf's internal buffer; we also definitely haven't parsed a whole
747
            // document
748
0
            std::streamsize available = buf.in_avail();
749
            // if this assert fails, the streambuf is buggy
750
0
            BOOST_ASSERT( available > 0 );
751
752
0
            available = ( std::min )(
753
0
                static_cast<std::size_t>(available), sizeof(read_buf) );
754
            // we read from the internal buffer of buf into our buffer
755
0
            available = buf.sgetn( read_buf, available );
756
757
0
            std::size_t consumed = p.write_some(
758
0
                read_buf, static_cast<std::size_t>(available), ec );
759
            // if the parser hasn't consumed the entire input we've took from
760
            // buf, we put the remaining data back; this should succeed,
761
            // because we only read data from buf's internal buffer
762
0
            while( consumed++ < static_cast<std::size_t>(available) )
763
0
            {
764
0
                std::istream::int_type const status = buf.sungetc();
765
0
                BOOST_ASSERT( status != Traits::eof() );
766
0
                (void)status;
767
0
            }
768
769
0
            if( ec.failed() )
770
0
                break;
771
0
        }
772
0
    }
773
0
#ifndef BOOST_NO_EXCEPTIONS
774
0
    catch(...)
775
0
    {
776
0
        try
777
0
        {
778
0
            is.setstate(std::ios::badbit);
779
0
        }
780
        // we ignore the exception, because we need to throw the original
781
        // exception instead
782
0
        catch( std::ios::failure const& ) { }
783
784
0
        if( is.exceptions() & std::ios::badbit )
785
0
            throw;
786
0
    }
787
0
#endif
788
789
0
    is.setstate(err | std::ios::failbit);
790
0
    return is;
791
0
}
792
793
std::istream&
794
operator>>(
795
    std::istream& is,
796
    parse_options const& opts)
797
0
{
798
0
    is.iword(parse_flags_xalloc) = to_bitmask(opts);
799
0
    is.iword(parse_depth_xalloc) = static_cast<long>(opts.max_depth);
800
0
    return is;
801
0
}
802
803
//----------------------------------------------------------
804
//
805
// private
806
//
807
//----------------------------------------------------------
808
809
storage_ptr
810
value::
811
destroy() noexcept
812
0
{
813
0
    switch(kind())
814
0
    {
815
0
    case json::kind::null:
816
0
    case json::kind::bool_:
817
0
    case json::kind::int64:
818
0
    case json::kind::uint64:
819
0
    case json::kind::double_:
820
0
        break;
821
822
0
    case json::kind::string:
823
0
    {
824
0
        auto sp = str_.storage();
825
0
        str_.~string();
826
0
        return sp;
827
0
    }
828
829
0
    case json::kind::array:
830
0
    {
831
0
        auto sp = arr_.storage();
832
0
        arr_.~array();
833
0
        return sp;
834
0
    }
835
836
0
    case json::kind::object:
837
0
    {
838
0
        auto sp = obj_.storage();
839
0
        obj_.~object();
840
0
        return sp;
841
0
    }
842
843
0
    }
844
0
    return std::move(sp_);
845
0
}
846
847
bool
848
value::
849
equal(value const& other) const noexcept
850
0
{
851
0
    switch(kind())
852
0
    {
853
0
    default: // unreachable()?
854
0
    case json::kind::null:
855
0
        return other.kind() == json::kind::null;
856
857
0
    case json::kind::bool_:
858
0
        return
859
0
            other.kind() == json::kind::bool_ &&
860
0
            get_bool() == other.get_bool();
861
862
0
    case json::kind::int64:
863
0
        switch(other.kind())
864
0
        {
865
0
        case json::kind::int64:
866
0
            return get_int64() == other.get_int64();
867
0
        case json::kind::uint64:
868
0
            if(get_int64() < 0)
869
0
                return false;
870
0
            return static_cast<std::uint64_t>(
871
0
                get_int64()) == other.get_uint64();
872
0
        default:
873
0
            return false;
874
0
        }
875
876
0
    case json::kind::uint64:
877
0
        switch(other.kind())
878
0
        {
879
0
        case json::kind::uint64:
880
0
            return get_uint64() == other.get_uint64();
881
0
        case json::kind::int64:
882
0
            if(other.get_int64() < 0)
883
0
                return false;
884
0
            return static_cast<std::uint64_t>(
885
0
                other.get_int64()) == get_uint64();
886
0
        default:
887
0
            return false;
888
0
        }
889
890
0
    case json::kind::double_:
891
0
        return
892
0
            other.kind() == json::kind::double_ &&
893
0
            get_double() == other.get_double();
894
895
0
    case json::kind::string:
896
0
        return
897
0
            other.kind() == json::kind::string &&
898
0
            get_string() == other.get_string();
899
900
0
    case json::kind::array:
901
0
        return
902
0
            other.kind() == json::kind::array &&
903
0
            get_array() == other.get_array();
904
905
0
    case json::kind::object:
906
0
        return
907
0
            other.kind() == json::kind::object &&
908
0
            get_object() == other.get_object();
909
0
    }
910
0
}
911
912
//----------------------------------------------------------
913
//
914
// key_value_pair
915
//
916
//----------------------------------------------------------
917
918
// empty keys point here
919
BOOST_JSON_REQUIRE_CONST_INIT
920
char const
921
key_value_pair::empty_[1] = { 0 };
922
923
key_value_pair::
924
key_value_pair(
925
    pilfered<json::value> key,
926
    pilfered<json::value> value) noexcept
927
1.48M
    : value_(value)
928
1.48M
{
929
1.48M
    std::size_t len;
930
1.48M
    key_ = access::release_key(key.get(), len);
931
1.48M
    len_ = static_cast<std::uint32_t>(len);
932
1.48M
}
933
934
key_value_pair::
935
key_value_pair(
936
    key_value_pair const& other,
937
    storage_ptr sp)
938
0
    : value_(other.value_, std::move(sp))
939
0
{
940
0
    auto p = reinterpret_cast<
941
0
        char*>(value_.storage()->
942
0
            allocate(other.len_ + 1,
943
0
                alignof(char)));
944
0
    std::memcpy(
945
0
        p, other.key_, other.len_);
946
0
    len_ = other.len_;
947
0
    p[len_] = 0;
948
0
    key_ = p;
949
0
}
950
951
//----------------------------------------------------------
952
953
namespace detail
954
{
955
956
std::size_t
957
hash_value_impl( value const& jv ) noexcept
958
0
{
959
0
    std::size_t seed = 0;
960
961
0
    kind const k = jv.kind();
962
0
    boost::hash_combine( seed, k != kind::int64 ? k : kind::uint64 );
963
964
0
    visit( value_hasher{seed}, jv );
965
0
    return seed;
966
0
}
967
968
} // namespace detail
969
} // namespace json
970
} // namespace boost
971
972
//----------------------------------------------------------
973
//
974
// std::hash specialization
975
//
976
//----------------------------------------------------------
977
978
std::size_t
979
std::hash<::boost::json::value>::operator()(
980
    ::boost::json::value const& jv) const noexcept
981
0
{
982
0
    return ::boost::hash< ::boost::json::value >()( jv );
983
0
}
984
985
//----------------------------------------------------------
986
987
#endif