GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: impl/serializer.hpp
Date: 2025-12-23 17:20:53
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 6080 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 3424 times.
3424 BOOST_ASSERT( w.p_ );
225 3424 pt = reinterpret_cast<T const*>(w.p_);
226 3424 it = std::begin(*pt);
227 6848 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 3494 do_arr1:
247
3/4
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3354 times.
✓ Branch 5 taken 70 times.
3494 if(BOOST_JSON_LIKELY(ss))
248 3424 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 2846 times.
3424 if(it == end)
252 507 goto do_arr4;
253 for(;;)
254 {
255 4070 w.p_ = std::addressof(*it);
256 6384 do_arr2:
257
6/8
✓ Branch 1 taken 2517 times.
✓ Branch 3 taken 1079 times.
✓ Branch 4 taken 1438 times.
✓ Branch 6 taken 3867 times.
✓ Branch 8 taken 1236 times.
✓ Branch 9 taken 2631 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
6384 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 1610 times.
✓ Branch 3 taken 1000 times.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 44 times.
✓ Branch 0 taken 1299 times.
✓ Branch 1 taken 109 times.
4069 if(BOOST_JSON_UNLIKELY( ++it == end ))
260 2916 break;
261 1153 do_arr3:
262
4/4
✓ Branch 1 taken 149 times.
✓ Branch 2 taken 20 times.
✓ Branch 4 taken 1004 times.
✓ Branch 5 taken 20 times.
1193 if(BOOST_JSON_LIKELY(ss))
263 1153 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 3655 do_arr4:
268
4/4
✓ Branch 1 taken 1444 times.
✓ Branch 2 taken 113 times.
✓ Branch 4 taken 1979 times.
✓ Branch 5 taken 119 times.
3655 if(BOOST_JSON_LIKELY(ss))
269 3423 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 3423 return true;
273 6080 }
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 27292 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 18172 times.
18172 BOOST_ASSERT( w.p_ );
297 18172 pt = reinterpret_cast<T const*>(w.p_);
298 18172 it = std::begin(*pt);
299 36344 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 18184 do_obj1:
321
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18160 times.
✓ Branch 5 taken 12 times.
18184 if(BOOST_JSON_LIKELY( ss ))
322 18172 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 17569 times.
18172 if(BOOST_JSON_UNLIKELY( it == end ))
326 563 goto do_obj6;
327 2133 for(;;)
328 {
329 {
330 using std::get;
331 19742 string_view const sv = get<0>(*it);
332 19742 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 19543 times.
✓ Branch 8 taken 163 times.
✓ Branch 9 taken 19380 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
19742 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 19355 times.
✓ Branch 5 taken 25 times.
19792 if(BOOST_JSON_LIKELY(ss))
347 19742 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 28442 do_obj4:
351 {
352 using std::get;
353 28442 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 19355 times.
✓ Branch 8 taken 8354 times.
✓ Branch 9 taken 11001 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
28442 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 19742 ++it;
358
6/6
✓ Branch 1 taken 157 times.
✓ Branch 2 taken 9109 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 81 times.
✓ Branch 0 taken 8524 times.
✓ Branch 3 taken 1865 times.
19742 if(BOOST_JSON_UNLIKELY(it == end))
359 17609 break;
360 2133 do_obj5:
361
4/4
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 1938 times.
✓ Branch 5 taken 8 times.
2149 if(BOOST_JSON_LIKELY(ss))
362 2133 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 18218 do_obj6:
367
4/4
✓ Branch 1 taken 8587 times.
✓ Branch 2 taken 21 times.
✓ Branch 4 taken 9585 times.
✓ Branch 5 taken 25 times.
18218 if(BOOST_JSON_LIKELY( ss ))
368 {
369 18172 ss.append('}');
370 18172 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 27292 }
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 writer& w;
467 local_stream& ss;
468 T const* pt;
469 writer::state st;
470
471 template< std::size_t I >
472 writer::state
473 operator()( std::integral_constant<std::size_t, I> ) const
474 {
475 using Ds = described_members<T>;
476 using D = mp11::mp_at_c<Ds, I>;
477 using M = described_member_t<T, D>;
478
479 switch(st)
480 {
481 case writer::state::obj2: goto do_obj2;
482 case writer::state::obj3: goto do_obj3;
483 case writer::state::obj4: goto do_obj4;
484 default: break;
485 }
486
487 {
488 string_view const sv = D::name;
489 w.cs0_ = { sv.data(), sv.size() };
490 }
491 if( true )
492 {
493 if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
494 return writer::state::obj2;
495 }
496 else
497 {
498 do_obj2:
499 if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
500 return writer::state::obj2;
501 }
502 do_obj3:
503 if(BOOST_JSON_LIKELY(ss))
504 ss.append(':');
505 else
506 return writer::state::obj3;
507 do_obj4:
508 w.p_ = std::addressof( pt->* D::pointer );
509 if(BOOST_JSON_UNLIKELY((
510 !write_impl<M, StackEmpty>(w, ss) )))
511 return writer::state::obj4;
512
513 return writer::state{};
514 }
515 };
516
517 template<class T, bool StackEmpty>
518 BOOST_FORCEINLINE
519 bool
520 write_impl(described_class_conversion_tag, writer& w, stream& ss0)
521 {
522 using Ds = described_members<T>;
523
524 T const* pt;
525 local_stream ss(ss0);
526 std::size_t cur;
527 constexpr std::size_t N = mp11::mp_size<Ds>::value;
528 writer::state st;
529 #if defined(_MSC_VER)
530 # pragma warning( push )
531 # pragma warning( disable : 4127 )
532 #endif
533 if(StackEmpty || w.st_.empty())
534 #if defined(_MSC_VER)
535 # pragma warning( pop )
536 #endif
537 {
538 BOOST_ASSERT( w.p_ );
539 pt = reinterpret_cast<T const*>(w.p_);
540 cur = 0;
541 }
542 else
543 {
544 w.st_.pop(st);
545 w.st_.pop(cur);
546 w.st_.pop(pt);
547 switch(st)
548 {
549 default:
550 case writer::state::obj1: goto do_obj1;
551 case writer::state::obj2: // fall through
552 case writer::state::obj3: // fall through
553 case writer::state::obj4: goto do_obj2;
554 case writer::state::obj5: goto do_obj5;
555 case writer::state::obj6: goto do_obj6;
556 break;
557 }
558 }
559 do_obj1:
560 if(BOOST_JSON_LIKELY( ss ))
561 ss.append('{');
562 else
563 return w.suspend(writer::state::obj1, cur, pt);
564 if(BOOST_JSON_UNLIKELY( cur == N ))
565 goto do_obj6;
566 for(;;)
567 {
568 st = {};
569 do_obj2:
570 st = mp11::mp_with_index<N>(
571 cur,
572 serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st});
573 if(BOOST_JSON_UNLIKELY( st != writer::state{} ))
574 return w.suspend(st, cur, pt);
575 ++cur;
576 if(BOOST_JSON_UNLIKELY(cur == N))
577 break;
578 do_obj5:
579 if(BOOST_JSON_LIKELY(ss))
580 ss.append(',');
581 else
582 return w.suspend(writer::state::obj5, cur, pt);
583 }
584 do_obj6:
585 if(BOOST_JSON_LIKELY( ss ))
586 {
587 ss.append('}');
588 return true;
589 }
590 return w.suspend(writer::state::obj6, cur, pt);
591 }
592
593 template<class T, bool StackEmpty>
594 BOOST_FORCEINLINE
595 bool
596 write_impl(described_enum_conversion_tag, writer& w, stream& ss)
597 {
598 #ifdef BOOST_DESCRIBE_CXX14
599 using Integer = typename std::underlying_type<T>::type;
600
601 #if defined(_MSC_VER)
602 # pragma warning( push )
603 # pragma warning( disable : 4127 )
604 #endif
605 if(StackEmpty || w.st_.empty())
606 #if defined(_MSC_VER)
607 # pragma warning( pop )
608 #endif
609 {
610 BOOST_ASSERT( w.p_ );
611 T const* pt = reinterpret_cast<T const*>(w.p_);
612 char const* const name = describe::enum_to_string(*pt, nullptr);
613 if( name )
614 {
615 string_view const sv = name;
616 w.cs0_ = { sv.data(), sv.size() };
617 return write_string(w, ss);
618 }
619 else
620 {
621 Integer n = static_cast<Integer>(*pt);
622 w.p_ = &n;
623 return write_impl<Integer, true>(w, ss);
624 }
625 }
626 else
627 {
628 writer::state st;
629 w.st_.peek(st);
630 if( st == writer::state::lit )
631 return write_impl<Integer, false>(w, ss);
632 else
633 return resume_string(w, ss);
634 }
635 #else // BOOST_DESCRIBE_CXX14
636 (void)w;
637 (void)ss;
638 static_assert(
639 !std::is_same<T, T>::value,
640 "described enums require C++14 support");
641 return false;
642 #endif // BOOST_DESCRIBE_CXX14
643 }
644
645 template< class T, bool StackEmpty >
646 struct serialize_variant_elem_helper
647 {
648 writer& w;
649 stream& ss;
650
651 template<class Elem>
652 bool
653 operator()(Elem const& x) const
654 {
655 w.p_ = std::addressof(x);
656 return write_impl<Elem, true>(w, ss);
657 }
658 };
659
660 template< class T >
661 struct serialize_variant_elem_helper<T, false>
662 {
663 writer& w;
664 stream& ss;
665
666 template< std::size_t I >
667 bool
668 operator()( std::integral_constant<std::size_t, I> ) const
669 {
670 using std::get;
671 using Elem = remove_cvref<decltype(get<I>(
672 std::declval<T const&>() ))>;
673 return write_impl<Elem, false>(w, ss);
674 }
675 };
676
677 template<class T, bool StackEmpty>
678 BOOST_FORCEINLINE
679 bool
680 write_impl(variant_conversion_tag, writer& w, stream& ss)
681 {
682 T const* pt;
683
684 using Index = remove_cvref<decltype( pt->index() )>;
685
686 #if defined(_MSC_VER)
687 # pragma warning( push )
688 # pragma warning( disable : 4127 )
689 #endif
690 if(StackEmpty || w.st_.empty())
691 #if defined(_MSC_VER)
692 # pragma warning( pop )
693 #endif
694 {
695 BOOST_ASSERT( w.p_ );
696 pt = reinterpret_cast<T const*>(w.p_);
697 if(BOOST_JSON_LIKELY((
698 visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt))))
699 return true;
700
701 Index const ix = pt->index();
702 w.st_.push(ix);
703 return false;
704 }
705 else
706 {
707 Index ix;
708 w.st_.pop(ix);
709
710 constexpr std::size_t N = mp11::mp_size<T>::value;
711 if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>(
712 ix,
713 serialize_variant_elem_helper<T, false>{w, ss}))))
714 return true;
715
716 w.st_.push(ix);
717 return false;
718 }
719 }
720
721 template<class T, bool StackEmpty>
722 BOOST_FORCEINLINE
723 bool
724 write_impl(optional_conversion_tag, writer& w, stream& ss)
725 {
726 using Elem = value_result_type<T>;
727
728 bool done;
729 bool has_value;
730
731 #if defined(_MSC_VER)
732 # pragma warning( push )
733 # pragma warning( disable : 4127 )
734 #endif
735 if(StackEmpty || w.st_.empty())
736 #if defined(_MSC_VER)
737 # pragma warning( pop )
738 #endif
739 {
740 BOOST_ASSERT( w.p_ );
741 T const* pt = reinterpret_cast<T const*>(w.p_);
742 has_value = static_cast<bool>(*pt);
743 if( has_value )
744 {
745 w.p_ = std::addressof( *(*pt) );
746 done = write_impl<Elem, true>(w, ss);
747 }
748 else
749 {
750 w.p_ = nullptr;
751 done = write_impl<std::nullptr_t, true>(w, ss);;
752 }
753 }
754 else
755 {
756 w.st_.pop(has_value);
757
758 if( has_value )
759 done = write_impl<Elem, false>(w, ss);
760 else
761 done = write_impl<std::nullptr_t, false>(w, ss);
762 }
763
764 if(BOOST_JSON_UNLIKELY( !done ))
765 w.st_.push(has_value);
766
767 return done;
768 }
769
770 template<class T, bool StackEmpty>
771 BOOST_FORCEINLINE
772 bool
773 write_impl(path_conversion_tag, writer& w, stream& ss)
774 {
775 #if defined(_MSC_VER)
776 # pragma warning( push )
777 # pragma warning( disable : 4127 )
778 #endif
779 if(StackEmpty || w.st_.empty())
780 #if defined(_MSC_VER)
781 # pragma warning( pop )
782 #endif
783 {
784 BOOST_ASSERT( w.p_ );
785 T const* pt = reinterpret_cast<T const*>(w.p_);
786
787 std::string const s = pt->generic_string();
788 w.cs0_ = { s.data(), s.size() };
789 if(BOOST_JSON_LIKELY( write_string(w, ss) ))
790 return true;
791
792 std::size_t const used = w.cs0_.used( s.data() );
793 w.st_.push( used );
794 w.st_.push( std::move(s) );
795 return false;
796 }
797 else
798 {
799 std::string s;
800 std::size_t used;
801 w.st_.pop( s );
802 w.st_.pop( used );
803
804 w.cs0_ = { s.data(), s.size() };
805 w.cs0_.skip(used);
806
807 if(BOOST_JSON_LIKELY( resume_string(w, ss) ))
808 return true;
809
810 used = w.cs0_.used( s.data() );
811 w.st_.push( used );
812 w.st_.push( std::move(s) );
813 return false;
814 }
815 }
816
817 template<class T, bool StackEmpty>
818 bool
819
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 269 times.
36677 write_impl(writer& w, stream& ss)
820 {
821 using cat = detail::generic_conversion_category<T, detail::no_context>;
822 36676 return write_impl<T, StackEmpty>( cat(), w, ss );
823 }
824
825 } // namespace detail
826
827 template<class T>
828 void
829 437 serializer::reset(T const* p) noexcept
830 {
831 BOOST_STATIC_ASSERT( !std::is_pointer<T>::value );
832 BOOST_STATIC_ASSERT( std::is_object<T>::value );
833
834 437 p_ = p;
835 437 fn0_ = &detail::write_impl<T, true>;
836 437 fn1_ = &detail::write_impl<T, false>;
837 437 st_.clear();
838 437 done_ = false;
839 437 }
840
841 } // namespace json
842 } // namespace boost
843
844 #endif // BOOST_JSON_IMPL_SERIALIZER_HPP
845