GCC Code Coverage Report


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