GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: impl/value.ipp
Date: 2025-12-23 17:22:01
Exec Total Coverage
Lines: 456 462 98.7%
Functions: 70 70 100.0%
Branches: 193 218 88.5%

Line Branch Exec Source
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/json
8 //
9
10 #ifndef BOOST_JSON_IMPL_VALUE_IPP
11 #define BOOST_JSON_IMPL_VALUE_IPP
12
13 #include <boost/container_hash/hash.hpp>
14 #include <boost/json/value.hpp>
15 #include <boost/json/parser.hpp>
16 #include <cstring>
17 #include <istream>
18 #include <limits>
19 #include <new>
20 #include <utility>
21
22 namespace boost {
23 namespace json {
24
25 namespace
26 {
27
28 int parse_depth_xalloc = std::ios::xalloc();
29 int parse_flags_xalloc = std::ios::xalloc();
30
31 struct value_hasher
32 {
33 std::size_t& seed;
34
35 template< class T >
36 496 void operator()( T&& t ) const noexcept
37 {
38 496 boost::hash_combine( seed, t );
39 496 }
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
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 (opts.allow_comments ?
55 3 static_cast<long>(E::allow_comments) : 0) |
56
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 (opts.allow_trailing_commas ?
57 static_cast<long>(E::allow_trailing_commas) : 0) |
58
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
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
1/1
✓ Branch 1 taken 9 times.
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 2178177 value::
81 ~value() noexcept
82 {
83
4/5
✓ Branch 1 taken 2112528 times.
✓ Branch 2 taken 27375 times.
✓ Branch 3 taken 3074 times.
✓ Branch 4 taken 35200 times.
✗ Branch 5 not taken.
2178177 switch(kind())
84 {
85 2112528 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 2112528 sca_.~scalar();
91 2112528 break;
92
93 27375 case json::kind::string:
94 27375 str_.~string();
95 27375 break;
96
97 3074 case json::kind::array:
98 3074 arr_.~array();
99 3074 break;
100
101 35200 case json::kind::object:
102 35200 obj_.~object();
103 35200 break;
104 }
105 2178177 }
106
107 9490 value::
108 value(
109 value const& other,
110 9490 storage_ptr sp)
111 {
112
8/9
✓ Branch 1 taken 2034 times.
✓ Branch 2 taken 121 times.
✓ Branch 3 taken 7006 times.
✓ Branch 4 taken 35 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 130 times.
✓ Branch 7 taken 122 times.
✓ Branch 8 taken 30 times.
✗ Branch 9 not taken.
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
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 ::new(&str_) string(
145 130 other.str_,
146
1/1
✓ Branch 4 taken 113 times.
164 std::move(sp));
147 113 break;
148
149 122 case json::kind::array:
150
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 ::new(&arr_) array(
151 122 other.arr_,
152
1/1
✓ Branch 4 taken 96 times.
174 std::move(sp));
153 96 break;
154
155 30 case json::kind::object:
156
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 ::new(&obj_) object(
157 30 other.obj_,
158
1/1
✓ Branch 4 taken 20 times.
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 11428 value::
171 value(
172 value&& other,
173 11428 storage_ptr sp)
174 {
175
8/9
✓ Branch 1 taken 77 times.
✓ Branch 2 taken 189 times.
✓ Branch 3 taken 10426 times.
✓ Branch 4 taken 75 times.
✓ Branch 5 taken 34 times.
✓ Branch 6 taken 339 times.
✓ Branch 7 taken 224 times.
✓ Branch 8 taken 64 times.
✗ Branch 9 not taken.
11428 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 189 case json::kind::bool_:
183 567 ::new(&sca_) scalar(
184 189 other.sca_.b, std::move(sp));
185 189 break;
186
187 10426 case json::kind::int64:
188 31278 ::new(&sca_) scalar(
189 10426 other.sca_.i, std::move(sp));
190 10426 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 339 case json::kind::string:
203
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 ::new(&str_) string(
204 339 std::move(other.str_),
205
1/1
✓ Branch 4 taken 335 times.
686 std::move(sp));
206 335 break;
207
208 224 case json::kind::array:
209
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 ::new(&arr_) array(
210 224 std::move(other.arr_),
211
1/1
✓ Branch 4 taken 219 times.
458 std::move(sp));
212 219 break;
213
214 64 case json::kind::object:
215
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 ::new(&obj_) object(
216 64 std::move(other.obj_),
217
1/1
✓ Branch 4 taken 51 times.
154 std::move(sp));
218 51 break;
219 }
220 11406 }
221
222 //----------------------------------------------------------
223 //
224 // Conversion
225 //
226 //----------------------------------------------------------
227
228 324 value::
229 value(
230 std::initializer_list<value_ref> init,
231 324 storage_ptr sp)
232 {
233
2/2
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 224 times.
324 if(value_ref::maybe_object(init))
234 {
235 ::new(&obj_) object(
236 value_ref::make_object(
237
1/1
✓ Branch 4 taken 100 times.
100 init, std::move(sp)));
238 }
239 else
240 {
241 #ifndef BOOST_JSON_LEGACY_INIT_LIST_BEHAVIOR
242
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 212 times.
224 if( init.size() == 1 )
243 {
244 12 ::new(&sca_) scalar();
245
1/1
✓ Branch 4 taken 12 times.
12 value temp = init.begin()->make_value( std::move(sp) );
246
1/1
✓ Branch 1 taken 12 times.
12 swap(temp);
247 12 }
248 else
249 #endif
250 {
251 ::new(&arr_) array(
252 value_ref::make_array(
253
1/1
✓ Branch 4 taken 212 times.
212 init, std::move(sp)));
254 }
255 }
256 324 }
257
258 //----------------------------------------------------------
259 //
260 // Assignment
261 //
262 //----------------------------------------------------------
263
264 value&
265 35 value::
266 operator=(value const& other)
267 {
268
1/1
✓ Branch 3 taken 29 times.
70 value(other,
269
1/1
✓ Branch 1 taken 29 times.
29 storage()).swap(*this);
270 29 return *this;
271 }
272
273 value&
274 72 value::
275 operator=(value&& other)
276 {
277
1/1
✓ Branch 4 taken 52 times.
144 value(std::move(other),
278
1/1
✓ Branch 1 taken 52 times.
53 storage()).swap(*this);
279 53 return *this;
280 }
281
282 value&
283 11 value::
284 operator=(
285 std::initializer_list<value_ref> init)
286 {
287
1/1
✓ Branch 3 taken 11 times.
22 value(init,
288
1/1
✓ Branch 1 taken 11 times.
11 storage()).swap(*this);
289 11 return *this;
290 }
291
292 value&
293 2 value::
294 operator=(string_view s)
295 {
296
2/2
✓ Branch 3 taken 2 times.
✓ Branch 6 taken 2 times.
2 value(s, storage()).swap(*this);
297 2 return *this;
298 }
299
300 value&
301 28 value::
302 operator=(char const* s)
303 {
304
2/2
✓ Branch 3 taken 28 times.
✓ Branch 6 taken 28 times.
28 value(s, storage()).swap(*this);
305 28 return *this;
306 }
307
308 value&
309 12 value::
310 operator=(string const& str)
311 {
312
2/2
✓ Branch 3 taken 12 times.
✓ Branch 6 taken 12 times.
12 value(str, storage()).swap(*this);
313 12 return *this;
314 }
315
316 value&
317 2 value::
318 operator=(string&& str)
319 {
320
1/1
✓ Branch 4 taken 2 times.
4 value(std::move(str),
321
1/1
✓ Branch 1 taken 2 times.
2 storage()).swap(*this);
322 2 return *this;
323 }
324
325 value&
326 1 value::
327 operator=(array const& arr)
328 {
329
2/2
✓ Branch 3 taken 1 times.
✓ Branch 6 taken 1 times.
1 value(arr, storage()).swap(*this);
330 1 return *this;
331 }
332
333 value&
334 5 value::
335 operator=(array&& arr)
336 {
337
1/1
✓ Branch 4 taken 5 times.
10 value(std::move(arr),
338
1/1
✓ Branch 1 taken 5 times.
5 storage()).swap(*this);
339 5 return *this;
340 }
341
342 value&
343 1 value::
344 operator=(object const& obj)
345 {
346
2/2
✓ Branch 3 taken 1 times.
✓ Branch 6 taken 1 times.
1 value(obj, storage()).swap(*this);
347 1 return *this;
348 }
349
350 value&
351 22 value::
352 operator=(object&& obj)
353 {
354
1/1
✓ Branch 4 taken 22 times.
44 value(std::move(obj),
355
1/1
✓ Branch 1 taken 22 times.
22 storage()).swap(*this);
356 22 return *this;
357 }
358
359 //----------------------------------------------------------
360 //
361 // Accessors
362 //
363 //----------------------------------------------------------
364
365 system::result<array&>
366 16 value::try_as_array() noexcept
367 {
368
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 7 times.
16 if( is_array() )
369 9 return arr_;
370
371 7 system::error_code ec;
372 7 BOOST_JSON_FAIL(ec, error::not_array);
373 7 return ec;
374 }
375
376 system::result<array const&>
377 183 value::try_as_array() const noexcept
378 {
379
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 28 times.
183 if( is_array() )
380 155 return arr_;
381
382 28 system::error_code ec;
383 28 BOOST_JSON_FAIL(ec, error::not_array);
384 28 return ec;
385 }
386
387 system::result<object&>
388 9 value::try_as_object() noexcept
389 {
390
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 7 times.
9 if( is_object() )
391 2 return obj_;
392
393 7 system::error_code ec;
394 7 BOOST_JSON_FAIL(ec, error::not_object);
395 7 return ec;
396 }
397
398 system::result<object const&>
399 206 value::try_as_object() const noexcept
400 {
401
2/2
✓ Branch 1 taken 178 times.
✓ Branch 2 taken 28 times.
206 if( is_object() )
402 178 return obj_;
403
404 28 system::error_code ec;
405 28 BOOST_JSON_FAIL(ec, error::not_object);
406 28 return ec;
407 }
408
409 system::result<string&>
410 9 value::try_as_string() noexcept
411 {
412
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 7 times.
9 if( is_string() )
413 2 return str_;
414
415 7 system::error_code ec;
416 7 BOOST_JSON_FAIL(ec, error::not_string);
417 7 return ec;
418 }
419
420 system::result<string const&>
421 121 value::try_as_string() const noexcept
422 {
423
2/2
✓ Branch 1 taken 92 times.
✓ Branch 2 taken 29 times.
121 if( is_string() )
424 92 return str_;
425
426 29 system::error_code ec;
427 29 BOOST_JSON_FAIL(ec, error::not_string);
428 29 return ec;
429 }
430
431 system::result<std::int64_t&>
432 52 value::try_as_int64() noexcept
433 {
434
2/2
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 14 times.
52 if( is_int64() )
435 38 return sca_.i;
436
437 14 system::error_code ec;
438 14 BOOST_JSON_FAIL(ec, error::not_int64);
439 14 return ec;
440 }
441
442 system::result<std::int64_t>
443 33 value::try_as_int64() const noexcept
444 {
445
2/2
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 14 times.
33 if( is_int64() )
446 19 return sca_.i;
447
448 14 system::error_code ec;
449 14 BOOST_JSON_FAIL(ec, error::not_int64);
450 14 return ec;
451 }
452
453 system::result<std::uint64_t&>
454 16 value::try_as_uint64() noexcept
455 {
456
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 14 times.
16 if( is_uint64() )
457 2 return sca_.u;
458
459 14 system::error_code ec;
460 14 BOOST_JSON_FAIL(ec, error::not_uint64);
461 14 return ec;
462 }
463
464 system::result<std::uint64_t>
465 16 value::try_as_uint64() const noexcept
466 {
467
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 14 times.
16 if( is_uint64() )
468 2 return sca_.u;
469
470 14 system::error_code ec;
471 14 BOOST_JSON_FAIL(ec, error::not_uint64);
472 14 return ec;
473 }
474
475 system::result<double&>
476 2000657 value::try_as_double() noexcept
477 {
478
2/2
✓ Branch 1 taken 2000643 times.
✓ Branch 2 taken 14 times.
2000657 if( is_double() )
479 2000643 return sca_.d;
480
481 14 system::error_code ec;
482 14 BOOST_JSON_FAIL(ec, error::not_double);
483 14 return ec;
484 }
485
486 system::result<double>
487 580 value::try_as_double() const noexcept
488 {
489
2/2
✓ Branch 1 taken 566 times.
✓ Branch 2 taken 14 times.
580 if( is_double() )
490 566 return sca_.d;
491
492 14 system::error_code ec;
493 14 BOOST_JSON_FAIL(ec, error::not_double);
494 14 return ec;
495 }
496
497 system::result<bool&>
498 19 value::try_as_bool() noexcept
499 {
500
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 15 times.
19 if( is_bool() )
501 4 return sca_.b;
502
503 15 system::error_code ec;
504 15 BOOST_JSON_FAIL(ec, error::not_bool);
505 15 return ec;
506 }
507
508 system::result<bool>
509 30 value::try_as_bool() const noexcept
510 {
511
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 14 times.
30 if( is_bool() )
512 16 return sca_.b;
513
514 14 system::error_code ec;
515 14 BOOST_JSON_FAIL(ec, error::not_bool);
516 14 return ec;
517 }
518
519 system::result<std::nullptr_t>
520 2 value::try_as_null() const noexcept
521 {
522
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if( is_null() )
523 1 return nullptr;
524
525 1 system::error_code ec;
526 1 BOOST_JSON_FAIL(ec, error::not_null);
527 1 return ec;
528 }
529
530 boost::system::result<value&>
531 1 value::try_at(string_view key) noexcept
532 {
533 1 auto r = try_as_object();
534
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if( !r )
535 return r.error();
536 1 return r->try_at(key);
537 }
538
539 boost::system::result<value const&>
540 3 value::try_at(string_view key) const noexcept
541 {
542 3 auto r = try_as_object();
543
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if( !r )
544 return r.error();
545 3 return r->try_at(key);
546 }
547
548 boost::system::result<value&>
549 8 value::try_at(std::size_t pos) noexcept
550 {
551 8 auto r = try_as_array();
552
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if( !r )
553 return r.error();
554 8 return r->try_at(pos);
555 }
556
557 boost::system::result<value const&>
558 2 value::try_at(std::size_t pos) const noexcept
559 {
560 2 auto r = try_as_array();
561
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if( !r )
562 return r.error();
563 2 return r->try_at(pos);
564 }
565
566 object const&
567 195 value::as_object(source_location const& loc) const&
568 {
569
1/1
✓ Branch 2 taken 174 times.
195 return try_as_object().value(loc);
570 }
571
572 array const&
573 173 value::as_array(source_location const& loc) const&
574 {
575
1/1
✓ Branch 2 taken 152 times.
173 return try_as_array().value(loc);
576 }
577
578 string const&
579 113 value::as_string(source_location const& loc) const&
580 {
581
1/1
✓ Branch 2 taken 91 times.
113 return try_as_string().value(loc);
582 }
583
584 std::int64_t&
585 44 value::as_int64(source_location const& loc)
586 {
587
1/1
✓ Branch 2 taken 37 times.
44 return try_as_int64().value(loc);
588 }
589
590 std::int64_t
591 26 value::as_int64(source_location const& loc) const
592 {
593
1/1
✓ Branch 2 taken 19 times.
26 return try_as_int64().value(loc);
594 }
595
596 std::uint64_t&
597 8 value::as_uint64(source_location const& loc)
598 {
599
1/1
✓ Branch 2 taken 1 times.
8 return try_as_uint64().value(loc);
600 }
601
602 std::uint64_t
603 8 value::as_uint64(source_location const& loc) const
604 {
605
1/1
✓ Branch 2 taken 1 times.
8 return try_as_uint64().value(loc);
606 }
607
608 double&
609 2000649 value::as_double(source_location const& loc)
610 {
611
1/1
✓ Branch 2 taken 2000642 times.
2000649 return try_as_double().value(loc);
612 }
613
614 double
615 572 value::as_double(source_location const& loc) const
616 {
617
1/1
✓ Branch 2 taken 565 times.
572 return try_as_double().value(loc);
618 }
619
620 bool&
621 10 value::as_bool(source_location const& loc)
622 {
623
1/1
✓ Branch 2 taken 3 times.
10 return try_as_bool().value(loc);
624 }
625
626 bool
627 22 value::as_bool(source_location const& loc) const
628 {
629
1/1
✓ Branch 2 taken 15 times.
22 return try_as_bool().value(loc);
630 }
631
632 //----------------------------------------------------------
633 //
634 // Modifiers
635 //
636 //----------------------------------------------------------
637
638 string&
639 98 value::
640 emplace_string() noexcept
641 {
642 98 return *::new(&str_) string(destroy());
643 }
644
645 array&
646 246 value::
647 emplace_array() noexcept
648 {
649 246 return *::new(&arr_) array(destroy());
650 }
651
652 object&
653 54 value::
654 emplace_object() noexcept
655 {
656 54 return *::new(&obj_) object(destroy());
657 }
658
659 void
660 184 value::
661 swap(value& other)
662 {
663
2/2
✓ Branch 5 taken 183 times.
✓ Branch 6 taken 1 times.
184 if(*storage() == *other.storage())
664 {
665 // fast path
666 union U
667 {
668 value tmp;
669 183 U(){}
670 183 ~U(){}
671 };
672 183 U u;
673 183 relocate(&u.tmp, *this);
674 183 relocate(this, other);
675 183 relocate(&other, u.tmp);
676 183 return;
677 183 }
678
679 // copy
680 value temp1(
681 1 std::move(*this),
682
1/1
✓ Branch 3 taken 1 times.
2 other.storage());
683 value temp2(
684 1 std::move(other),
685
1/1
✓ Branch 3 taken 1 times.
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
1/1
✓ Branch 1 taken 10 times.
10 std::istream::sentry sentry(is);
701
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 9 times.
10 if( !sentry )
702 1 return is;
703
704
1/1
✓ Branch 1 taken 9 times.
9 parse_options opts = get_parse_options( is );
705
3/4
✓ Branch 1 taken 9 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 6 times.
✗ Branch 2 not taken.
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
1/1
✓ Branch 2 taken 13 times.
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
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 10 times.
13 if( Traits::eq_int_type(c, Traits::eof()) )
730 {
731 3 err |= std::ios::eofbit;
732
1/1
✓ Branch 1 taken 3 times.
3 p.finish(ec);
733
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
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
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 9 times.
12 if( p.done() )
740 {
741
2/2
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
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
1/1
✓ Branch 1 taken 9 times.
9 std::streamsize available = buf.in_avail();
749 // if this assert fails, the streambuf is buggy
750
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
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
1/1
✓ Branch 1 taken 9 times.
9 available = buf.sgetn( read_buf, available );
756
757
1/1
✓ Branch 1 taken 9 times.
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
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 9 times.
21 while( consumed++ < static_cast<std::size_t>(available) )
763 {
764
1/1
✓ Branch 1 taken 12 times.
12 std::istream::int_type const status = buf.sungetc();
765
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 BOOST_ASSERT( status != Traits::eof() );
766 (void)status;
767 }
768
769
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 6 times.
9 if( ec.failed() )
770 3 break;
771 6 }
772 }
773 #ifndef BOOST_NO_EXCEPTIONS
774 2 catch(...)
775 {
776 try
777 {
778
1/1
✓ Branch 1 taken 1 times.
2 is.setstate(std::ios::badbit);
779 }
780 // we ignore the exception, because we need to throw the original
781 // exception instead
782
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 catch( std::ios::failure const& ) { }
783
784
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2 if( is.exceptions() & std::ios::badbit )
785 1 throw;
786 2 }
787 #endif
788
789
1/1
✓ Branch 2 taken 5 times.
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 416 value::
811 destroy() noexcept
812 {
813
4/5
✓ Branch 1 taken 397 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
416 switch(kind())
814 {
815 397 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 397 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 397 return std::move(sp_);
845 }
846
847 bool
848 4140 value::
849 equal(value const& other) const noexcept
850 {
851
8/8
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 3915 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 55 times.
✓ Branch 6 taken 45 times.
✓ Branch 7 taken 61 times.
✓ Branch 8 taken 20 times.
4140 switch(kind())
852 {
853 21 default: // unreachable()?
854 case json::kind::null:
855 21 return other.kind() == json::kind::null;
856
857 16 case json::kind::bool_:
858 return
859
4/4
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 2 times.
25 other.kind() == json::kind::bool_ &&
860 25 get_bool() == other.get_bool();
861
862 3915 case json::kind::int64:
863
3/3
✓ Branch 1 taken 3888 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 1 times.
3915 switch(other.kind())
864 {
865 3888 case json::kind::int64:
866 3888 return get_int64() == other.get_int64();
867 26 case json::kind::uint64:
868
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 25 times.
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
3/3
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
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
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
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
4/4
✓ Branch 1 taken 53 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 52 times.
✓ Branch 4 taken 1 times.
108 other.kind() == json::kind::double_ &&
893 108 get_double() == other.get_double();
894
895 45 case json::kind::string:
896 return
897
4/4
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 40 times.
✓ Branch 4 taken 2 times.
87 other.kind() == json::kind::string &&
898 87 get_string() == other.get_string();
899
900 61 case json::kind::array:
901 return
902
4/4
✓ Branch 1 taken 59 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 56 times.
✓ Branch 4 taken 3 times.
120 other.kind() == json::kind::array &&
903 120 get_array() == other.get_array();
904
905 20 case json::kind::object:
906 return
907
4/4
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 3 times.
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
1/1
✓ Branch 3 taken 6854 times.
6862 : value_(other.value_, std::move(sp))
939 {
940 auto p = reinterpret_cast<
941 6854 char*>(value_.storage()->
942
1/1
✓ Branch 2 taken 6596 times.
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
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 90 times.
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
988