GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: impl/value.ipp
Date: 2025-12-23 17:20:53
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 2178831 value::
81 ~value() noexcept
82 {
83
4/5
✓ Branch 1 taken 2112821 times.
✓ Branch 2 taken 27658 times.
✓ Branch 3 taken 3123 times.
✓ Branch 4 taken 35229 times.
✗ Branch 5 not taken.
2178831 switch(kind())
84 {
85 2112821 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 2112821 sca_.~scalar();
91 2112821 break;
92
93 27658 case json::kind::string:
94 27658 str_.~string();
95 27658 break;
96
97 3123 case json::kind::array:
98 3123 arr_.~array();
99 3123 break;
100
101 35229 case json::kind::object:
102 35229 obj_.~object();
103 35229 break;
104 }
105 2178831 }
106
107 9508 value::
108 value(
109 value const& other,
110 9508 storage_ptr sp)
111 {
112
8/9
✓ Branch 1 taken 2034 times.
✓ Branch 2 taken 121 times.
✓ Branch 3 taken 7018 times.
✓ Branch 4 taken 35 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 136 times.
✓ Branch 7 taken 122 times.
✓ Branch 8 taken 30 times.
✗ Branch 9 not taken.
9508 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 7018 case json::kind::int64:
126 21054 ::new(&sca_) scalar(
127 7018 other.sca_.i,
128 7018 std::move(sp));
129 7018 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 136 case json::kind::string:
144
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 ::new(&str_) string(
145 136 other.str_,
146
1/1
✓ Branch 4 taken 119 times.
170 std::move(sp));
147 119 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 9455 }
162
163 3802 value::
164 3802 value(value&& other) noexcept
165 {
166 3802 relocate(this, other);
167 3802 ::new(&other.sca_) scalar(sp_);
168 3802 }
169
170 11593 value::
171 value(
172 value&& other,
173 11593 storage_ptr sp)
174 {
175
8/9
✓ Branch 1 taken 77 times.
✓ Branch 2 taken 189 times.
✓ Branch 3 taken 10465 times.
✓ Branch 4 taken 75 times.
✓ Branch 5 taken 34 times.
✓ Branch 6 taken 454 times.
✓ Branch 7 taken 233 times.
✓ Branch 8 taken 66 times.
✗ Branch 9 not taken.
11593 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 10465 case json::kind::int64:
188 31395 ::new(&sca_) scalar(
189 10465 other.sca_.i, std::move(sp));
190 10465 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 454 case json::kind::string:
203
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 ::new(&str_) string(
204 454 std::move(other.str_),
205
1/1
✓ Branch 4 taken 450 times.
916 std::move(sp));
206 450 break;
207
208 233 case json::kind::array:
209
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 ::new(&arr_) array(
210 233 std::move(other.arr_),
211
1/1
✓ Branch 4 taken 228 times.
476 std::move(sp));
212 228 break;
213
214 66 case json::kind::object:
215
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 ::new(&obj_) object(
216 66 std::move(other.obj_),
217
1/1
✓ Branch 4 taken 53 times.
158 std::move(sp));
218 53 break;
219 }
220 11571 }
221
222 //----------------------------------------------------------
223 //
224 // Conversion
225 //
226 //----------------------------------------------------------
227
228 358 value::
229 value(
230 std::initializer_list<value_ref> init,
231 358 storage_ptr sp)
232 {
233
2/2
✓ Branch 1 taken 109 times.
✓ Branch 2 taken 249 times.
358 if(value_ref::maybe_object(init))
234 {
235 ::new(&obj_) object(
236 value_ref::make_object(
237
1/1
✓ Branch 4 taken 109 times.
109 init, std::move(sp)));
238 }
239 else
240 {
241
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 237 times.
249 if( init.size() == 1 )
242 {
243 12 ::new(&sca_) scalar();
244
1/1
✓ Branch 4 taken 12 times.
12 value temp = init.begin()->make_value( std::move(sp) );
245
1/1
✓ Branch 1 taken 12 times.
12 swap(temp);
246 12 }
247 else
248 {
249 ::new(&arr_) array(
250 value_ref::make_array(
251
1/1
✓ Branch 4 taken 237 times.
237 init, std::move(sp)));
252 }
253 }
254 358 }
255
256 //----------------------------------------------------------
257 //
258 // Assignment
259 //
260 //----------------------------------------------------------
261
262 value&
263 35 value::
264 operator=(value const& other)
265 {
266
1/1
✓ Branch 3 taken 29 times.
70 value(other,
267
1/1
✓ Branch 1 taken 29 times.
29 storage()).swap(*this);
268 29 return *this;
269 }
270
271 value&
272 92 value::
273 operator=(value&& other)
274 {
275
1/1
✓ Branch 4 taken 72 times.
184 value(std::move(other),
276
1/1
✓ Branch 1 taken 72 times.
73 storage()).swap(*this);
277 73 return *this;
278 }
279
280 value&
281 11 value::
282 operator=(
283 std::initializer_list<value_ref> init)
284 {
285
1/1
✓ Branch 3 taken 11 times.
22 value(init,
286
1/1
✓ Branch 1 taken 11 times.
11 storage()).swap(*this);
287 11 return *this;
288 }
289
290 value&
291 2 value::
292 operator=(string_view s)
293 {
294
2/2
✓ Branch 3 taken 2 times.
✓ Branch 6 taken 2 times.
2 value(s, storage()).swap(*this);
295 2 return *this;
296 }
297
298 value&
299 28 value::
300 operator=(char const* s)
301 {
302
2/2
✓ Branch 3 taken 28 times.
✓ Branch 6 taken 28 times.
28 value(s, storage()).swap(*this);
303 28 return *this;
304 }
305
306 value&
307 12 value::
308 operator=(string const& str)
309 {
310
2/2
✓ Branch 3 taken 12 times.
✓ Branch 6 taken 12 times.
12 value(str, storage()).swap(*this);
311 12 return *this;
312 }
313
314 value&
315 2 value::
316 operator=(string&& str)
317 {
318
1/1
✓ Branch 4 taken 2 times.
4 value(std::move(str),
319
1/1
✓ Branch 1 taken 2 times.
2 storage()).swap(*this);
320 2 return *this;
321 }
322
323 value&
324 1 value::
325 operator=(array const& arr)
326 {
327
2/2
✓ Branch 3 taken 1 times.
✓ Branch 6 taken 1 times.
1 value(arr, storage()).swap(*this);
328 1 return *this;
329 }
330
331 value&
332 5 value::
333 operator=(array&& arr)
334 {
335
1/1
✓ Branch 4 taken 5 times.
10 value(std::move(arr),
336
1/1
✓ Branch 1 taken 5 times.
5 storage()).swap(*this);
337 5 return *this;
338 }
339
340 value&
341 1 value::
342 operator=(object const& obj)
343 {
344
2/2
✓ Branch 3 taken 1 times.
✓ Branch 6 taken 1 times.
1 value(obj, storage()).swap(*this);
345 1 return *this;
346 }
347
348 value&
349 22 value::
350 operator=(object&& obj)
351 {
352
1/1
✓ Branch 4 taken 22 times.
44 value(std::move(obj),
353
1/1
✓ Branch 1 taken 22 times.
22 storage()).swap(*this);
354 22 return *this;
355 }
356
357 //----------------------------------------------------------
358 //
359 // Accessors
360 //
361 //----------------------------------------------------------
362
363 system::result<array&>
364 16 value::try_as_array() noexcept
365 {
366
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 7 times.
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 183 value::try_as_array() const noexcept
376 {
377
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 28 times.
183 if( is_array() )
378 155 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
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 7 times.
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 206 value::try_as_object() const noexcept
398 {
399
2/2
✓ Branch 1 taken 178 times.
✓ Branch 2 taken 28 times.
206 if( is_object() )
400 178 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
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 7 times.
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
2/2
✓ Branch 1 taken 92 times.
✓ Branch 2 taken 29 times.
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
2/2
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 14 times.
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
2/2
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 14 times.
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
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 14 times.
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
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 14 times.
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
2/2
✓ Branch 1 taken 2000643 times.
✓ Branch 2 taken 14 times.
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
2/2
✓ Branch 1 taken 566 times.
✓ Branch 2 taken 14 times.
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
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 15 times.
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
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 14 times.
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/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
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/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if( !r )
533 return r.error();
534 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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if( !r )
542 return r.error();
543 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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if( !r )
551 return r.error();
552 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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if( !r )
560 return r.error();
561 2 return r->try_at(pos);
562 }
563
564 object const&
565 195 value::as_object(source_location const& loc) const&
566 {
567
1/1
✓ Branch 2 taken 174 times.
195 return try_as_object().value(loc);
568 }
569
570 array const&
571 173 value::as_array(source_location const& loc) const&
572 {
573
1/1
✓ Branch 2 taken 152 times.
173 return try_as_array().value(loc);
574 }
575
576 string const&
577 113 value::as_string(source_location const& loc) const&
578 {
579
1/1
✓ Branch 2 taken 91 times.
113 return try_as_string().value(loc);
580 }
581
582 std::int64_t&
583 44 value::as_int64(source_location const& loc)
584 {
585
1/1
✓ Branch 2 taken 37 times.
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
1/1
✓ Branch 2 taken 19 times.
26 return try_as_int64().value(loc);
592 }
593
594 std::uint64_t&
595 8 value::as_uint64(source_location const& loc)
596 {
597
1/1
✓ Branch 2 taken 1 times.
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
1/1
✓ Branch 2 taken 1 times.
8 return try_as_uint64().value(loc);
604 }
605
606 double&
607 2000649 value::as_double(source_location const& loc)
608 {
609
1/1
✓ Branch 2 taken 2000642 times.
2000649 return try_as_double().value(loc);
610 }
611
612 double
613 572 value::as_double(source_location const& loc) const
614 {
615
1/1
✓ Branch 2 taken 565 times.
572 return try_as_double().value(loc);
616 }
617
618 bool&
619 10 value::as_bool(source_location const& loc)
620 {
621
1/1
✓ Branch 2 taken 3 times.
10 return try_as_bool().value(loc);
622 }
623
624 bool
625 22 value::as_bool(source_location const& loc) const
626 {
627
1/1
✓ Branch 2 taken 15 times.
22 return try_as_bool().value(loc);
628 }
629
630 //----------------------------------------------------------
631 //
632 // Modifiers
633 //
634 //----------------------------------------------------------
635
636 string&
637 158 value::
638 emplace_string() noexcept
639 {
640 158 return *::new(&str_) string(destroy());
641 }
642
643 array&
644 260 value::
645 emplace_array() noexcept
646 {
647 260 return *::new(&arr_) array(destroy());
648 }
649
650 object&
651 64 value::
652 emplace_object() noexcept
653 {
654 64 return *::new(&obj_) object(destroy());
655 }
656
657 void
658 204 value::
659 swap(value& other)
660 {
661
2/2
✓ Branch 5 taken 203 times.
✓ Branch 6 taken 1 times.
204 if(*storage() == *other.storage())
662 {
663 // fast path
664 union U
665 {
666 value tmp;
667 203 U(){}
668 203 ~U(){}
669 };
670 203 U u;
671 203 relocate(&u.tmp, *this);
672 203 relocate(this, other);
673 203 relocate(&other, u.tmp);
674 203 return;
675 203 }
676
677 // copy
678 value temp1(
679 1 std::move(*this),
680
1/1
✓ Branch 3 taken 1 times.
2 other.storage());
681 value temp2(
682 1 std::move(other),
683
1/1
✓ Branch 3 taken 1 times.
2 this->storage());
684 1 other.~value();
685 1 ::new(&other) value(pilfer(temp1));
686 1 this->~value();
687 1 ::new(this) value(pilfer(temp2));
688 1 }
689
690 std::istream&
691 10 operator>>(
692 std::istream& is,
693 value& jv)
694 {
695 using Traits = std::istream::traits_type;
696
697 // sentry prepares the stream for reading and finalizes it in destructor
698
1/1
✓ Branch 1 taken 10 times.
10 std::istream::sentry sentry(is);
699
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 9 times.
10 if( !sentry )
700 1 return is;
701
702
1/1
✓ Branch 1 taken 9 times.
9 parse_options opts = get_parse_options( is );
703
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) ) )
704 3 opts.max_depth = depth;
705
706 unsigned char parser_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
707 9 stream_parser p( {}, opts, parser_buf );
708 9 p.reset( jv.storage() );
709
710 char read_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
711 9 std::streambuf& buf = *is.rdbuf();
712 9 std::ios::iostate err = std::ios::goodbit;
713 #ifndef BOOST_NO_EXCEPTIONS
714 try
715 #endif
716 {
717 while( true )
718 {
719 15 system::error_code ec;
720
721 // we peek the buffer; this either makes sure that there's no
722 // more input, or makes sure there's something in the internal
723 // buffer (so in_avail will return a positive number)
724
1/1
✓ Branch 2 taken 13 times.
15 std::istream::int_type c = is.rdbuf()->sgetc();
725 // if we indeed reached EOF, we check if we parsed a full JSON
726 // document; if not, we error out
727
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 10 times.
13 if( Traits::eq_int_type(c, Traits::eof()) )
728 {
729 3 err |= std::ios::eofbit;
730
1/1
✓ Branch 1 taken 3 times.
3 p.finish(ec);
731
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
3 if( ec.failed() )
732 4 break;
733 }
734
735 // regardless of reaching EOF, we might have parsed a full JSON
736 // document; if so, we successfully finish
737
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 9 times.
12 if( p.done() )
738 {
739
2/2
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
3 jv = p.release();
740 3 return is;
741 }
742
743 // at this point we definitely have more input, specifically in
744 // buf's internal buffer; we also definitely haven't parsed a whole
745 // document
746
1/1
✓ Branch 1 taken 9 times.
9 std::streamsize available = buf.in_avail();
747 // if this assert fails, the streambuf is buggy
748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 BOOST_ASSERT( available > 0 );
749
750 18 available = ( std::min )(
751 9 static_cast<std::size_t>(available), sizeof(read_buf) );
752 // we read from the internal buffer of buf into our buffer
753
1/1
✓ Branch 1 taken 9 times.
9 available = buf.sgetn( read_buf, available );
754
755
1/1
✓ Branch 1 taken 9 times.
9 std::size_t consumed = p.write_some(
756 read_buf, static_cast<std::size_t>(available), ec );
757 // if the parser hasn't consumed the entire input we've took from
758 // buf, we put the remaining data back; this should succeed,
759 // because we only read data from buf's internal buffer
760
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 9 times.
21 while( consumed++ < static_cast<std::size_t>(available) )
761 {
762
1/1
✓ Branch 1 taken 12 times.
12 std::istream::int_type const status = buf.sungetc();
763
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 BOOST_ASSERT( status != Traits::eof() );
764 (void)status;
765 }
766
767
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 6 times.
9 if( ec.failed() )
768 3 break;
769 6 }
770 }
771 #ifndef BOOST_NO_EXCEPTIONS
772 2 catch(...)
773 {
774 try
775 {
776
1/1
✓ Branch 1 taken 1 times.
2 is.setstate(std::ios::badbit);
777 }
778 // we ignore the exception, because we need to throw the original
779 // exception instead
780
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 catch( std::ios::failure const& ) { }
781
782
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2 if( is.exceptions() & std::ios::badbit )
783 1 throw;
784 2 }
785 #endif
786
787
1/1
✓ Branch 2 taken 5 times.
5 is.setstate(err | std::ios::failbit);
788 5 return is;
789 9 }
790
791 std::istream&
792 3 operator>>(
793 std::istream& is,
794 parse_options const& opts)
795 {
796 3 is.iword(parse_flags_xalloc) = to_bitmask(opts);
797 3 is.iword(parse_depth_xalloc) = static_cast<long>(opts.max_depth);
798 3 return is;
799 }
800
801 //----------------------------------------------------------
802 //
803 // private
804 //
805 //----------------------------------------------------------
806
807 storage_ptr
808 500 value::
809 destroy() noexcept
810 {
811
4/5
✓ Branch 1 taken 481 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
500 switch(kind())
812 {
813 481 case json::kind::null:
814 case json::kind::bool_:
815 case json::kind::int64:
816 case json::kind::uint64:
817 case json::kind::double_:
818 481 break;
819
820 14 case json::kind::string:
821 {
822 14 auto sp = str_.storage();
823 14 str_.~string();
824 14 return sp;
825 14 }
826
827 2 case json::kind::array:
828 {
829 2 auto sp = arr_.storage();
830 2 arr_.~array();
831 2 return sp;
832 2 }
833
834 3 case json::kind::object:
835 {
836 3 auto sp = obj_.storage();
837 3 obj_.~object();
838 3 return sp;
839 3 }
840
841 }
842 481 return std::move(sp_);
843 }
844
845 bool
846 4226 value::
847 equal(value const& other) const noexcept
848 {
849
8/8
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 3933 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 55 times.
✓ Branch 6 taken 93 times.
✓ Branch 7 taken 73 times.
✓ Branch 8 taken 28 times.
4226 switch(kind())
850 {
851 21 default: // unreachable()?
852 case json::kind::null:
853 21 return other.kind() == json::kind::null;
854
855 16 case json::kind::bool_:
856 return
857
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_ &&
858 25 get_bool() == other.get_bool();
859
860 3933 case json::kind::int64:
861
3/3
✓ Branch 1 taken 3906 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 1 times.
3933 switch(other.kind())
862 {
863 3906 case json::kind::int64:
864 3906 return get_int64() == other.get_int64();
865 26 case json::kind::uint64:
866
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 25 times.
26 if(get_int64() < 0)
867 1 return false;
868 25 return static_cast<std::uint64_t>(
869 25 get_int64()) == other.get_uint64();
870 1 default:
871 1 return false;
872 }
873
874 7 case json::kind::uint64:
875
3/3
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
7 switch(other.kind())
876 {
877 2 case json::kind::uint64:
878 2 return get_uint64() == other.get_uint64();
879 3 case json::kind::int64:
880
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
3 if(other.get_int64() < 0)
881 2 return false;
882 1 return static_cast<std::uint64_t>(
883 1 other.get_int64()) == get_uint64();
884 2 default:
885 2 return false;
886 }
887
888 55 case json::kind::double_:
889 return
890
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_ &&
891 108 get_double() == other.get_double();
892
893 93 case json::kind::string:
894 return
895
4/4
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 88 times.
✓ Branch 4 taken 2 times.
183 other.kind() == json::kind::string &&
896 183 get_string() == other.get_string();
897
898 73 case json::kind::array:
899 return
900
4/4
✓ Branch 1 taken 71 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 68 times.
✓ Branch 4 taken 3 times.
144 other.kind() == json::kind::array &&
901 144 get_array() == other.get_array();
902
903 28 case json::kind::object:
904 return
905
4/4
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 3 times.
53 other.kind() == json::kind::object &&
906 53 get_object() == other.get_object();
907 }
908 }
909
910 //----------------------------------------------------------
911 //
912 // key_value_pair
913 //
914 //----------------------------------------------------------
915
916 // empty keys point here
917 BOOST_JSON_REQUIRE_CONST_INIT
918 char const
919 key_value_pair::empty_[1] = { 0 };
920
921 38150 key_value_pair::
922 key_value_pair(
923 pilfered<json::value> key,
924 38150 pilfered<json::value> value) noexcept
925 38150 : value_(value)
926 {
927 std::size_t len;
928 38150 key_ = access::release_key(key.get(), len);
929 38150 len_ = static_cast<std::uint32_t>(len);
930 38150 }
931
932 6876 key_value_pair::
933 key_value_pair(
934 key_value_pair const& other,
935 6876 storage_ptr sp)
936
1/1
✓ Branch 3 taken 6872 times.
6880 : value_(other.value_, std::move(sp))
937 {
938 auto p = reinterpret_cast<
939 6872 char*>(value_.storage()->
940
1/1
✓ Branch 2 taken 6614 times.
6872 allocate(other.len_ + 1,
941 alignof(char)));
942 6614 std::memcpy(
943 6614 p, other.key_, other.len_);
944 6614 len_ = other.len_;
945 6614 p[len_] = 0;
946 6614 key_ = p;
947 6872 }
948
949 //----------------------------------------------------------
950
951 namespace detail
952 {
953
954 std::size_t
955 248 hash_value_impl( value const& jv ) noexcept
956 {
957 248 std::size_t seed = 0;
958
959 248 kind const k = jv.kind();
960
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 90 times.
248 boost::hash_combine( seed, k != kind::int64 ? k : kind::uint64 );
961
962 248 visit( value_hasher{seed}, jv );
963 248 return seed;
964 }
965
966 } // namespace detail
967 } // namespace json
968 } // namespace boost
969
970 //----------------------------------------------------------
971 //
972 // std::hash specialization
973 //
974 //----------------------------------------------------------
975
976 std::size_t
977 62 std::hash<::boost::json::value>::operator()(
978 ::boost::json::value const& jv) const noexcept
979 {
980 62 return ::boost::hash< ::boost::json::value >()( jv );
981 }
982
983 //----------------------------------------------------------
984
985 #endif
986