Coverage Report

Created: 2025-06-13 06:26

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