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