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