GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: impl/serializer.hpp
Date: 2026-01-02 17:31:41
Exec Total Coverage
Lines: 178 182 97.8%
Functions: 58 60 96.7%
Branches: 235 304 77.3%

Line Branch Exec Source
1 //
2 // Copyright (c) 2024 Dmitry Arkhipov (grisumbras@yandex.ru)
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_SERIALIZER_HPP
11 #define BOOST_JSON_IMPL_SERIALIZER_HPP
12
13 #include <boost/core/detail/static_assert.hpp>
14 #include <boost/describe/enum_to_string.hpp>
15 #include <boost/json/conversion.hpp>
16 #include <cstddef>
17
18 namespace boost {
19 namespace json {
20 namespace detail {
21
22 enum class writer::state : char
23 {
24 str1, str2, str3, esc1, utf1,
25 utf2, utf3, utf4, utf5,
26 lit,
27 arr1, arr2, arr3, arr4,
28 obj1, obj2, obj3, obj4, obj5, obj6
29 };
30
31 bool
32 11258 writer::
33 suspend(state st)
34 {
35 11258 st_.push(st);
36 11257 return false;
37 }
38
39 template<class U, class T>
40 bool
41 23750 writer::
42 suspend(state st, U u, T const* pt)
43 {
44 23750 st_.push(pt);
45 23748 st_.push(u);
46 23748 st_.push(st);
47 23748 return false;
48 }
49
50 template<class T, bool StackEmpty>
51 bool
52 write_impl(writer& w, stream& ss);
53
54 template<class T, bool StackEmpty>
55 BOOST_FORCEINLINE
56 bool
57 write_impl(null_like_conversion_tag, writer& w, stream& ss)
58 {
59 #if defined(_MSC_VER)
60 # pragma warning( push )
61 # pragma warning( disable : 4127 )
62 #endif
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if( StackEmpty || w.st_.empty() )
64 20 return write_null(w, ss);
65 #if defined(_MSC_VER)
66 # pragma warning( pop )
67 #endif
68 14 return resume_buffer(w, ss);
69 }
70
71 template<class T, bool StackEmpty>
72 BOOST_FORCEINLINE
73 bool
74 write_impl(bool_conversion_tag, writer& w, stream& ss)
75 {
76 BOOST_ASSERT( w.p_ );
77 97 auto const t = *reinterpret_cast<T const*>(w.p_);
78
79 #if defined(_MSC_VER)
80 # pragma warning( push )
81 # pragma warning( disable : 4127 )
82 #endif
83
2/2
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 30 times.
61 if( StackEmpty || w.st_.empty() )
84 #if defined(_MSC_VER)
85 # pragma warning( pop )
86 #endif
87 {
88
3/4
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 9 times.
67 if( t )
89 58 return write_true(w, ss);
90 else
91 9 return write_false(w, ss);
92 }
93
94 30 return resume_buffer(w, ss);
95 }
96
97 template<class T, bool StackEmpty>
98 BOOST_FORCEINLINE
99 bool
100 write_impl(integral_conversion_tag, writer& w, stream& ss0)
101 {
102 #if defined(_MSC_VER)
103 # pragma warning( push )
104 # pragma warning( disable : 4127 )
105 #endif
106
4/6
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 36 times.
200 if( StackEmpty || w.st_.empty() )
107 #if defined(_MSC_VER)
108 # pragma warning( pop )
109 #endif
110 {
111 6 auto const& t = *reinterpret_cast<T const*>(w.p_);
112
113 #if defined(__clang__)
114 # pragma clang diagnostic push
115 # pragma clang diagnostic ignored "-Wsign-compare"
116 #elif defined(__GNUC__)
117 # pragma GCC diagnostic push
118 # pragma GCC diagnostic ignored "-Wsign-compare"
119 #elif defined(_MSC_VER)
120 # pragma warning( push )
121 # pragma warning( disable : 4018 )
122 # pragma warning( disable : 4127 )
123 #endif
124
125
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
134 if( t < 0 )
126 {
127 // T is obviously signed, so this comparison is safe
128
1/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
6 if( t >= (std::numeric_limits<std::int64_t>::min)() )
129 {
130 6 std::int64_t i = t;
131 6 return write_int64(w, ss0, i);
132 }
133 }
134
3/12
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 172 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 16 taken 28 times.
✗ Branch 17 not taken.
334 else if( t <= (std::numeric_limits<std::uint64_t>::max)() )
135 {
136 334 std::uint64_t u = t;
137 334 return write_uint64(w, ss0, u);
138 }
139 #if defined(__clang__)
140 # pragma clang diagnostic pop
141 #elif defined(__GNUC__)
142 # pragma GCC diagnostic pop
143 #elif defined(_MSC_VER)
144 # pragma warning( pop )
145 #endif
146
147 #if defined(_MSC_VER)
148 # pragma warning( push )
149 # pragma warning( disable : 4244 )
150 #endif
151 double d = t;
152 return write_double(w, ss0, d);
153 #if defined(_MSC_VER)
154 # pragma warning( pop )
155 #endif
156 }
157
158 66 return resume_buffer(w, ss0);
159 }
160
161 template<class T, bool StackEmpty>
162 BOOST_FORCEINLINE
163 bool
164 write_impl(floating_point_conversion_tag, writer& w, stream& ss0)
165 {
166 #if defined(_MSC_VER)
167 # pragma warning( push )
168 # pragma warning( disable : 4127 )
169 #endif
170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if( StackEmpty || w.st_.empty() )
171 #if defined(_MSC_VER)
172 # pragma warning( pop )
173 #endif
174 {
175 10 double d = *reinterpret_cast<T const*>(w.p_);
176 10 return write_double(w, ss0, d);
177 }
178
179 10 return resume_buffer(w, ss0);
180 }
181
182 template<class T, bool StackEmpty>
183 BOOST_FORCEINLINE
184 bool
185 write_impl(string_like_conversion_tag, writer& w, stream& ss0)
186 {
187 #if defined(_MSC_VER)
188 # pragma warning( push )
189 # pragma warning( disable : 4127 )
190 #endif
191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if( StackEmpty || w.st_.empty() )
192 #if defined(_MSC_VER)
193 # pragma warning( pop )
194 #endif
195 {
196 string_view const sv = *reinterpret_cast<T const*>(w.p_);
197 91 w.cs0_ = { sv.data(), sv.size() };
198
1/2
✗ Branch 1 not taken.
✓ Branch 4 taken 91 times.
91 return write_string(w, ss0);
199 }
200
201 112 return resume_string(w, ss0);
202 }
203
204 template<class T, bool StackEmpty>
205 BOOST_FORCEINLINE
206 bool
207 write_impl(sequence_conversion_tag, writer& w, stream& ss0)
208 {
209 using It = iterator_type<T const>;
210 using Elem = value_type<T>;
211
212 T const* pt;
213 6078 local_stream ss(ss0);
214 37 It it;
215 17 It end;
216 #if defined(_MSC_VER)
217 # pragma warning( push )
218 # pragma warning( disable : 4127 )
219 #endif
220
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2656 times.
2656 if(StackEmpty || w.st_.empty())
221 {
222 #if defined(_MSC_VER)
223 # pragma warning( pop )
224 #endif
225
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3422 times.
3422 BOOST_ASSERT( w.p_ );
226 3422 pt = reinterpret_cast<T const*>(w.p_);
227 3422 it = std::begin(*pt);
228 6844 end = std::end(*pt);
229 }
230 else
231 {
232 writer::state st;
233
1/1
✓ Branch 1 taken 2656 times.
2656 w.st_.pop(st);
234
1/1
✓ Branch 1 taken 2656 times.
2656 w.st_.pop(it);
235
1/1
✓ Branch 1 taken 2656 times.
2656 w.st_.pop(pt);
236 2656 end = std::end(*pt);
237
4/4
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 2314 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 232 times.
2656 switch(st)
238 {
239 70 default:
240 70 case writer::state::arr1: goto do_arr1;
241 2314 case writer::state::arr2: goto do_arr2;
242 40 case writer::state::arr3: goto do_arr3;
243 232 case writer::state::arr4: goto do_arr4;
244 break;
245 }
246 }
247 3492 do_arr1:
248
3/4
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3352 times.
✓ Branch 5 taken 70 times.
3492 if(BOOST_JSON_LIKELY(ss))
249 3422 ss.append('[');
250 else
251
1/2
✗ Branch 1 not taken.
✓ Branch 4 taken 70 times.
70 return w.suspend(writer::state::arr1, it, pt);
252
5/6
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 491 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 17 times.
✓ Branch 0 taken 16 times.
✓ Branch 3 taken 2844 times.
3422 if(it == end)
253 507 goto do_arr4;
254 for(;;)
255 {
256 4064 w.p_ = std::addressof(*it);
257 6378 do_arr2:
258
6/8
✓ Branch 1 taken 2517 times.
✓ Branch 3 taken 1079 times.
✓ Branch 4 taken 1438 times.
✓ Branch 6 taken 3861 times.
✓ Branch 8 taken 1236 times.
✓ Branch 9 taken 2625 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
6378 if( !write_impl<Elem, StackEmpty>(w, ss) )
259
2/2
✓ Branch 1 taken 1079 times.
✓ Branch 4 taken 1235 times.
2315 return w.suspend(writer::state::arr2, it, pt);
260
6/6
✓ Branch 2 taken 1608 times.
✓ Branch 3 taken 996 times.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 44 times.
✓ Branch 0 taken 1299 times.
✓ Branch 1 taken 109 times.
4063 if(BOOST_JSON_UNLIKELY( ++it == end ))
261 2914 break;
262 1149 do_arr3:
263
4/4
✓ Branch 1 taken 149 times.
✓ Branch 2 taken 20 times.
✓ Branch 4 taken 1000 times.
✓ Branch 5 taken 20 times.
1189 if(BOOST_JSON_LIKELY(ss))
264 1149 ss.append(',');
265 else
266
2/2
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
40 return w.suspend(writer::state::arr3, it, pt);
267 }
268 3653 do_arr4:
269
4/4
✓ Branch 1 taken 1444 times.
✓ Branch 2 taken 113 times.
✓ Branch 4 taken 1977 times.
✓ Branch 5 taken 119 times.
3653 if(BOOST_JSON_LIKELY(ss))
270 3421 ss.append(']');
271 else
272
2/2
✓ Branch 1 taken 113 times.
✓ Branch 4 taken 119 times.
232 return w.suspend(writer::state::arr4, it, pt);
273 3421 return true;
274 6078 }
275
276 template<class T, bool StackEmpty>
277 BOOST_FORCEINLINE
278 bool
279 write_impl(map_like_conversion_tag, writer& w, stream& ss0)
280 {
281 using It = iterator_type<T const>;
282 using Mapped = mapped_type<T>;
283
284 T const* pt;
285 27290 local_stream ss(ss0);
286 96 It it;
287 96 It end;
288 #if defined(_MSC_VER)
289 # pragma warning( push )
290 # pragma warning( disable : 4127 )
291 #endif
292
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9120 times.
9120 if(StackEmpty || w.st_.empty())
293 #if defined(_MSC_VER)
294 # pragma warning( pop )
295 #endif
296 {
297
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 18170 times.
18170 BOOST_ASSERT( w.p_ );
298 18170 pt = reinterpret_cast<T const*>(w.p_);
299 18170 it = std::begin(*pt);
300 36340 end = std::end(*pt);
301 }
302 else
303 {
304 writer::state st;
305
1/1
✓ Branch 1 taken 9120 times.
9120 w.st_.pop(st);
306
1/1
✓ Branch 1 taken 9120 times.
9120 w.st_.pop(it);
307
1/1
✓ Branch 1 taken 9120 times.
9120 w.st_.pop(pt);
308 9120 end = std::end(*pt);
309
6/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 296 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 8700 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 46 times.
9120 switch(st)
310 {
311 12 default:
312 12 case writer::state::obj1: goto do_obj1;
313 296 case writer::state::obj2: goto do_obj2;
314 50 case writer::state::obj3: goto do_obj3;
315 8700 case writer::state::obj4: goto do_obj4;
316 16 case writer::state::obj5: goto do_obj5;
317 46 case writer::state::obj6: goto do_obj6;
318 break;
319 }
320 }
321 18182 do_obj1:
322
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18158 times.
✓ Branch 5 taken 12 times.
18182 if(BOOST_JSON_LIKELY( ss ))
323 18170 ss.append('{');
324 else
325
1/2
✗ Branch 1 not taken.
✓ Branch 4 taken 12 times.
12 return w.suspend(writer::state::obj1, it, pt);
326
5/6
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 555 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 36 times.
✓ Branch 0 taken 8 times.
✓ Branch 3 taken 17567 times.
18170 if(BOOST_JSON_UNLIKELY( it == end ))
327 563 goto do_obj6;
328 2129 for(;;)
329 {
330 {
331 using std::get;
332 19736 string_view const sv = get<0>(*it);
333 19736 w.cs0_ = { sv.data(), sv.size() };
334 }
335 if( true )
336 {
337
6/8
✓ Branch 1 taken 199 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 189 times.
✓ Branch 6 taken 19537 times.
✓ Branch 8 taken 163 times.
✓ Branch 9 taken 19374 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
19736 if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
338
2/2
✓ Branch 1 taken 10 times.
✓ Branch 4 taken 163 times.
173 return w.suspend(writer::state::obj2, it, pt);
339 }
340 else
341 {
342 296 do_obj2:
343
3/4
✓ Branch 1 taken 296 times.
✓ Branch 3 taken 123 times.
✓ Branch 4 taken 173 times.
✗ Branch 2 not taken.
296 if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
344
1/1
✓ Branch 1 taken 123 times.
123 return w.suspend(writer::state::obj2, it, pt);
345 }
346 173 do_obj3:
347
4/4
✓ Branch 1 taken 387 times.
✓ Branch 2 taken 25 times.
✓ Branch 4 taken 19349 times.
✓ Branch 5 taken 25 times.
19786 if(BOOST_JSON_LIKELY(ss))
348 19736 ss.append(':');
349 else
350
2/2
✓ Branch 1 taken 25 times.
✓ Branch 4 taken 25 times.
50 return w.suspend(writer::state::obj3, it, pt);
351 28436 do_obj4:
352 {
353 using std::get;
354 28436 w.p_ = std::addressof( get<1>(*it) );
355 }
356
6/8
✓ Branch 1 taken 9087 times.
✓ Branch 3 taken 346 times.
✓ Branch 4 taken 8741 times.
✓ Branch 6 taken 19349 times.
✓ Branch 8 taken 8354 times.
✓ Branch 9 taken 10995 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
28436 if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
357
2/2
✓ Branch 1 taken 346 times.
✓ Branch 4 taken 8354 times.
8700 return w.suspend(writer::state::obj4, it, pt);
358 19736 ++it;
359
6/6
✓ Branch 1 taken 157 times.
✓ Branch 2 taken 9107 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 81 times.
✓ Branch 0 taken 8524 times.
✓ Branch 3 taken 1861 times.
19736 if(BOOST_JSON_UNLIKELY(it == end))
360 17607 break;
361 2129 do_obj5:
362
4/4
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 1934 times.
✓ Branch 5 taken 8 times.
2145 if(BOOST_JSON_LIKELY(ss))
363 2129 ss.append(',');
364 else
365
2/2
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
16 return w.suspend(writer::state::obj5, it, pt);
366 }
367 18216 do_obj6:
368
4/4
✓ Branch 1 taken 8587 times.
✓ Branch 2 taken 21 times.
✓ Branch 4 taken 9583 times.
✓ Branch 5 taken 25 times.
18216 if(BOOST_JSON_LIKELY( ss ))
369 {
370 18170 ss.append('}');
371 18170 return true;
372 }
373
2/2
✓ Branch 1 taken 21 times.
✓ Branch 4 taken 25 times.
46 return w.suspend(writer::state::obj6, it, pt);
374 27290 }
375
376 template< class T, bool StackEmpty >
377 struct serialize_tuple_elem_helper
378 {
379 writer& w;
380 stream& ss;
381 T const* pt;
382
383 template< std::size_t I >
384 bool
385 516 operator()( std::integral_constant<std::size_t, I> ) const
386 {
387 using std::get;
388 516 w.p_ = std::addressof( get<I>(*pt) );
389
390 using Elem = tuple_element_t<I, T>;
391 516 return write_impl<Elem, StackEmpty>(w, ss);
392 }
393 };
394
395 template<class T, bool StackEmpty>
396 BOOST_FORCEINLINE
397 bool
398 write_impl(tuple_conversion_tag, writer& w, stream& ss0)
399 {
400 T const* pt;
401 174 local_stream ss(ss0);
402 std::size_t cur;
403 64 constexpr std::size_t N = std::tuple_size<T>::value;
404 #if defined(_MSC_VER)
405 # pragma warning( push )
406 # pragma warning( disable : 4127 )
407 #endif
408
4/6
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 18 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 42 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 38 times.
110 if(StackEmpty || w.st_.empty())
409 {
410 #if defined(_MSC_VER)
411 # pragma warning( pop )
412 #endif
413
4/12
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 26 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 24 times.
76 BOOST_ASSERT( w.p_ );
414 76 pt = reinterpret_cast<T const*>(w.p_);
415 76 cur = 0;
416 }
417 else
418 {
419 writer::state st;
420
3/3
✓ Branch 1 taken 18 times.
✓ Branch 4 taken 42 times.
✓ Branch 7 taken 38 times.
98 w.st_.pop(st);
421
3/3
✓ Branch 1 taken 18 times.
✓ Branch 4 taken 42 times.
✓ Branch 7 taken 38 times.
98 w.st_.pop(cur);
422
3/3
✓ Branch 1 taken 18 times.
✓ Branch 4 taken 42 times.
✓ Branch 7 taken 38 times.
98 w.st_.pop(pt);
423
10/12
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 38 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 32 times.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 2 times.
98 switch(st)
424 {
425 2 default:
426 2 case writer::state::arr1: goto do_arr1;
427 82 case writer::state::arr2: goto do_arr2;
428 8 case writer::state::arr3: goto do_arr3;
429 6 case writer::state::arr4: goto do_arr4;
430 break;
431 }
432 }
433 78 do_arr1:
434
6/12
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 10 taken 26 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 16 taken 24 times.
✗ Branch 17 not taken.
78 if(BOOST_JSON_LIKELY(ss))
435 76 ss.append('[');
436 else
437
2/6
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 10 not taken.
✗ Branch 13 not taken.
✗ Branch 16 not taken.
2 return w.suspend(writer::state::arr1, cur, pt);
438 100 for(;;)
439 {
440 258 do_arr2:
441 {
442
6/6
✓ Branch 1 taken 41 times.
✓ Branch 4 taken 23 times.
✓ Branch 7 taken 50 times.
✓ Branch 10 taken 40 times.
✓ Branch 13 taken 59 times.
✓ Branch 16 taken 45 times.
258 bool const stop = !mp11::mp_with_index<N>(
443 cur,
444 serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt});
445
12/12
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 32 times.
✓ Branch 6 taken 20 times.
✓ Branch 7 taken 20 times.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 44 times.
✓ Branch 10 taken 17 times.
✓ Branch 11 taken 28 times.
258 if(BOOST_JSON_UNLIKELY( stop ))
446
6/6
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
✓ Branch 7 taken 18 times.
✓ Branch 10 taken 20 times.
✓ Branch 13 taken 15 times.
✓ Branch 16 taken 17 times.
82 return w.suspend(writer::state::arr2, cur, pt);
447 }
448
12/12
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 11 times.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 15 times.
✓ Branch 8 taken 19 times.
✓ Branch 9 taken 25 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 23 times.
176 if(BOOST_JSON_UNLIKELY( ++cur == N ))
449 76 break;
450 100 do_arr3:
451
12/12
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 1 times.
✓ Branch 7 taken 12 times.
✓ Branch 8 taken 1 times.
✓ Branch 10 taken 14 times.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 27 times.
✓ Branch 14 taken 2 times.
✓ Branch 16 taken 21 times.
✓ Branch 17 taken 2 times.
108 if(BOOST_JSON_LIKELY(ss))
452 100 ss.append(',');
453 else
454
6/6
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 10 taken 1 times.
✓ Branch 13 taken 2 times.
✓ Branch 16 taken 2 times.
8 return w.suspend(writer::state::arr3, cur, pt);
455 }
456 82 do_arr4:
457
12/12
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
✓ Branch 7 taken 22 times.
✓ Branch 8 taken 1 times.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 20 times.
✓ Branch 14 taken 1 times.
✓ Branch 16 taken 4 times.
✓ Branch 17 taken 1 times.
82 if(BOOST_JSON_LIKELY(ss))
458 76 ss.append(']');
459 else
460
6/6
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 10 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 16 taken 1 times.
6 return w.suspend(writer::state::arr4, cur, pt);
461 76 return true;
462 174 }
463
464 template< class T, bool StackEmpty >
465 struct serialize_struct_elem_helper
466 {
467 static_assert(
468 uniquely_named_members<T>::value,
469 "The type has several described members with the same name.");
470
471 writer& w;
472 local_stream& ss;
473 T const* pt;
474 writer::state st;
475
476 template< std::size_t I >
477 writer::state
478 operator()( std::integral_constant<std::size_t, I> ) const
479 {
480 using Ds = described_members<T>;
481 using D = mp11::mp_at_c<Ds, I>;
482 using M = described_member_t<T, D>;
483
484 switch(st)
485 {
486 case writer::state::obj2: goto do_obj2;
487 case writer::state::obj3: goto do_obj3;
488 case writer::state::obj4: goto do_obj4;
489 default: break;
490 }
491
492 {
493 string_view const sv = D::name;
494 w.cs0_ = { sv.data(), sv.size() };
495 }
496 if( true )
497 {
498 if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
499 return writer::state::obj2;
500 }
501 else
502 {
503 do_obj2:
504 if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
505 return writer::state::obj2;
506 }
507 do_obj3:
508 if(BOOST_JSON_LIKELY(ss))
509 ss.append(':');
510 else
511 return writer::state::obj3;
512 do_obj4:
513 w.p_ = std::addressof( pt->* D::pointer );
514 if(BOOST_JSON_UNLIKELY((
515 !write_impl<M, StackEmpty>(w, ss) )))
516 return writer::state::obj4;
517
518 return writer::state{};
519 }
520 };
521
522 template<class T, bool StackEmpty>
523 BOOST_FORCEINLINE
524 bool
525 write_impl(described_class_conversion_tag, writer& w, stream& ss0)
526 {
527 using Ds = described_members<T>;
528
529 T const* pt;
530 local_stream ss(ss0);
531 std::size_t cur;
532 constexpr std::size_t N = mp11::mp_size<Ds>::value;
533 writer::state st;
534 #if defined(_MSC_VER)
535 # pragma warning( push )
536 # pragma warning( disable : 4127 )
537 #endif
538 if(StackEmpty || w.st_.empty())
539 #if defined(_MSC_VER)
540 # pragma warning( pop )
541 #endif
542 {
543 BOOST_ASSERT( w.p_ );
544 pt = reinterpret_cast<T const*>(w.p_);
545 cur = 0;
546 }
547 else
548 {
549 w.st_.pop(st);
550 w.st_.pop(cur);
551 w.st_.pop(pt);
552 switch(st)
553 {
554 default:
555 case writer::state::obj1: goto do_obj1;
556 case writer::state::obj2: // fall through
557 case writer::state::obj3: // fall through
558 case writer::state::obj4: goto do_obj2;
559 case writer::state::obj5: goto do_obj5;
560 case writer::state::obj6: goto do_obj6;
561 break;
562 }
563 }
564 do_obj1:
565 if(BOOST_JSON_LIKELY( ss ))
566 ss.append('{');
567 else
568 return w.suspend(writer::state::obj1, cur, pt);
569 if(BOOST_JSON_UNLIKELY( cur == N ))
570 goto do_obj6;
571 for(;;)
572 {
573 st = {};
574 do_obj2:
575 st = mp11::mp_with_index<N>(
576 cur,
577 serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st});
578 if(BOOST_JSON_UNLIKELY( st != writer::state{} ))
579 return w.suspend(st, cur, pt);
580 ++cur;
581 if(BOOST_JSON_UNLIKELY(cur == N))
582 break;
583 do_obj5:
584 if(BOOST_JSON_LIKELY(ss))
585 ss.append(',');
586 else
587 return w.suspend(writer::state::obj5, cur, pt);
588 }
589 do_obj6:
590 if(BOOST_JSON_LIKELY( ss ))
591 {
592 ss.append('}');
593 return true;
594 }
595 return w.suspend(writer::state::obj6, cur, pt);
596 }
597
598 template<class T, bool StackEmpty>
599 BOOST_FORCEINLINE
600 bool
601 write_impl(described_enum_conversion_tag, writer& w, stream& ss)
602 {
603 #ifdef BOOST_DESCRIBE_CXX14
604 using Integer = typename std::underlying_type<T>::type;
605
606 #if defined(_MSC_VER)
607 # pragma warning( push )
608 # pragma warning( disable : 4127 )
609 #endif
610 if(StackEmpty || w.st_.empty())
611 #if defined(_MSC_VER)
612 # pragma warning( pop )
613 #endif
614 {
615 BOOST_ASSERT( w.p_ );
616 T const* pt = reinterpret_cast<T const*>(w.p_);
617 char const* const name = describe::enum_to_string(*pt, nullptr);
618 if( name )
619 {
620 string_view const sv = name;
621 w.cs0_ = { sv.data(), sv.size() };
622 return write_string(w, ss);
623 }
624 else
625 {
626 Integer n = static_cast<Integer>(*pt);
627 w.p_ = &n;
628 return write_impl<Integer, true>(w, ss);
629 }
630 }
631 else
632 {
633 writer::state st;
634 w.st_.peek(st);
635 if( st == writer::state::lit )
636 return write_impl<Integer, false>(w, ss);
637 else
638 return resume_string(w, ss);
639 }
640 #else // BOOST_DESCRIBE_CXX14
641 (void)w;
642 (void)ss;
643 static_assert(
644 !std::is_same<T, T>::value,
645 "described enums require C++14 support");
646 return false;
647 #endif // BOOST_DESCRIBE_CXX14
648 }
649
650 template< class T, bool StackEmpty >
651 struct serialize_variant_elem_helper
652 {
653 writer& w;
654 stream& ss;
655
656 template<class Elem>
657 bool
658 operator()(Elem const& x) const
659 {
660 w.p_ = std::addressof(x);
661 return write_impl<Elem, true>(w, ss);
662 }
663 };
664
665 template< class T >
666 struct serialize_variant_elem_helper<T, false>
667 {
668 writer& w;
669 stream& ss;
670
671 template< std::size_t I >
672 bool
673 operator()( std::integral_constant<std::size_t, I> ) const
674 {
675 using std::get;
676 using Elem = remove_cvref<decltype(get<I>(
677 std::declval<T const&>() ))>;
678 return write_impl<Elem, false>(w, ss);
679 }
680 };
681
682 template<class T, bool StackEmpty>
683 BOOST_FORCEINLINE
684 bool
685 write_impl(variant_conversion_tag, writer& w, stream& ss)
686 {
687 T const* pt;
688
689 using Index = remove_cvref<decltype( pt->index() )>;
690
691 #if defined(_MSC_VER)
692 # pragma warning( push )
693 # pragma warning( disable : 4127 )
694 #endif
695 if(StackEmpty || w.st_.empty())
696 #if defined(_MSC_VER)
697 # pragma warning( pop )
698 #endif
699 {
700 BOOST_ASSERT( w.p_ );
701 pt = reinterpret_cast<T const*>(w.p_);
702 if(BOOST_JSON_LIKELY((
703 visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt))))
704 return true;
705
706 Index const ix = pt->index();
707 w.st_.push(ix);
708 return false;
709 }
710 else
711 {
712 Index ix;
713 w.st_.pop(ix);
714
715 constexpr std::size_t N = mp11::mp_size<T>::value;
716 if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>(
717 ix,
718 serialize_variant_elem_helper<T, false>{w, ss}))))
719 return true;
720
721 w.st_.push(ix);
722 return false;
723 }
724 }
725
726 template<class T, bool StackEmpty>
727 BOOST_FORCEINLINE
728 bool
729 write_impl(optional_conversion_tag, writer& w, stream& ss)
730 {
731 using Elem = value_result_type<T>;
732
733 bool done;
734 bool has_value;
735
736 #if defined(_MSC_VER)
737 # pragma warning( push )
738 # pragma warning( disable : 4127 )
739 #endif
740 if(StackEmpty || w.st_.empty())
741 #if defined(_MSC_VER)
742 # pragma warning( pop )
743 #endif
744 {
745 BOOST_ASSERT( w.p_ );
746 T const* pt = reinterpret_cast<T const*>(w.p_);
747 has_value = static_cast<bool>(*pt);
748 if( has_value )
749 {
750 w.p_ = std::addressof( *(*pt) );
751 done = write_impl<Elem, true>(w, ss);
752 }
753 else
754 {
755 w.p_ = nullptr;
756 done = write_impl<std::nullptr_t, true>(w, ss);;
757 }
758 }
759 else
760 {
761 w.st_.pop(has_value);
762
763 if( has_value )
764 done = write_impl<Elem, false>(w, ss);
765 else
766 done = write_impl<std::nullptr_t, false>(w, ss);
767 }
768
769 if(BOOST_JSON_UNLIKELY( !done ))
770 w.st_.push(has_value);
771
772 return done;
773 }
774
775 template<class T, bool StackEmpty>
776 BOOST_FORCEINLINE
777 bool
778 write_impl(path_conversion_tag, writer& w, stream& ss)
779 {
780 #if defined(_MSC_VER)
781 # pragma warning( push )
782 # pragma warning( disable : 4127 )
783 #endif
784 if(StackEmpty || w.st_.empty())
785 #if defined(_MSC_VER)
786 # pragma warning( pop )
787 #endif
788 {
789 BOOST_ASSERT( w.p_ );
790 T const* pt = reinterpret_cast<T const*>(w.p_);
791
792 std::string const s = pt->generic_string();
793 w.cs0_ = { s.data(), s.size() };
794 if(BOOST_JSON_LIKELY( write_string(w, ss) ))
795 return true;
796
797 std::size_t const used = w.cs0_.used( s.data() );
798 w.st_.push( used );
799 w.st_.push( std::move(s) );
800 return false;
801 }
802 else
803 {
804 std::string s;
805 std::size_t used;
806 w.st_.pop( s );
807 w.st_.pop( used );
808
809 w.cs0_ = { s.data(), s.size() };
810 w.cs0_.skip(used);
811
812 if(BOOST_JSON_LIKELY( resume_string(w, ss) ))
813 return true;
814
815 used = w.cs0_.used( s.data() );
816 w.st_.push( used );
817 w.st_.push( std::move(s) );
818 return false;
819 }
820 }
821
822 template<class T, bool StackEmpty>
823 bool
824
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 269 times.
36665 write_impl(writer& w, stream& ss)
825 {
826 using cat = detail::generic_conversion_category<T>;
827 36664 return write_impl<T, StackEmpty>( cat(), w, ss );
828 }
829
830 } // namespace detail
831
832 template<class T>
833 void
834 437 serializer::reset(T const* p) noexcept
835 {
836 BOOST_CORE_STATIC_ASSERT( !std::is_pointer<T>::value );
837 BOOST_CORE_STATIC_ASSERT( std::is_object<T>::value );
838
839 437 p_ = p;
840 437 fn0_ = &detail::write_impl<T, true>;
841 437 fn1_ = &detail::write_impl<T, false>;
842 437 st_.clear();
843 437 done_ = false;
844 437 }
845
846 } // namespace json
847 } // namespace boost
848
849 #endif // BOOST_JSON_IMPL_SERIALIZER_HPP
850