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