TLA Line data Source code
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 HIT 11328 : writer::
33 : suspend(state st)
34 : {
35 11328 : st_.push(st);
36 11327 : return false;
37 : }
38 :
39 : template<class U, class T>
40 : bool
41 11947 : writer::
42 : suspend(state st, U u, T const* pt)
43 : {
44 11947 : st_.push(pt);
45 11946 : st_.push(u);
46 11946 : st_.push(st);
47 11946 : 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 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 MIS 0 : BOOST_ASSERT( w.p_ );
77 HIT 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 61 : if( StackEmpty || w.st_.empty() )
84 : #if defined(_MSC_VER)
85 : # pragma warning( pop )
86 : #endif
87 : {
88 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 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 134 : if( t < 0 )
126 : {
127 : // T is obviously signed, so this comparison is safe
128 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 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 MIS 0 : double d = t;
152 0 : return write_double(w, ss0, d);
153 : #if defined(_MSC_VER)
154 : # pragma warning( pop )
155 : #endif
156 : }
157 :
158 HIT 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 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 112 : if( StackEmpty || w.st_.empty() )
192 : #if defined(_MSC_VER)
193 : # pragma warning( pop )
194 : #endif
195 : {
196 MIS 0 : string_view const sv = *reinterpret_cast<T const*>(w.p_);
197 HIT 91 : w.cs0_ = { sv.data(), sv.size() };
198 91 : w.buf_[2] = false;
199 91 : return write_string(w, ss0);
200 : }
201 :
202 112 : return resume_string(w, ss0);
203 : }
204 :
205 : template<class T, bool StackEmpty>
206 : BOOST_FORCEINLINE
207 : bool
208 : write_impl(sequence_conversion_tag, writer& w, stream& ss0)
209 : {
210 : using It = iterator_type<T const>;
211 : using Elem = value_type<T>;
212 :
213 : T const* pt;
214 6125 : local_stream ss(ss0);
215 37 : It it;
216 17 : It end;
217 : #if defined(_MSC_VER)
218 : # pragma warning( push )
219 : # pragma warning( disable : 4127 )
220 : #endif
221 2684 : if(StackEmpty || w.st_.empty())
222 : {
223 : #if defined(_MSC_VER)
224 : # pragma warning( pop )
225 : #endif
226 3441 : BOOST_ASSERT( w.p_ );
227 3441 : pt = reinterpret_cast<T const*>(w.p_);
228 3441 : it = std::begin(*pt);
229 6882 : end = std::end(*pt);
230 : }
231 : else
232 : {
233 : writer::state st;
234 2684 : w.st_.pop(st);
235 2684 : w.st_.pop(it);
236 2684 : w.st_.pop(pt);
237 2684 : end = std::end(*pt);
238 2684 : switch(st)
239 : {
240 70 : default:
241 70 : case writer::state::arr1: goto do_arr1;
242 2338 : case writer::state::arr2: goto do_arr2;
243 42 : case writer::state::arr3: goto do_arr3;
244 234 : case writer::state::arr4: goto do_arr4;
245 : break;
246 : }
247 : }
248 3511 : do_arr1:
249 3511 : if(BOOST_JSON_LIKELY(ss))
250 3441 : ss.append('[');
251 : else
252 70 : return w.suspend(writer::state::arr1, it, pt);
253 3441 : if(it == end)
254 507 : goto do_arr4;
255 : for(;;)
256 : {
257 4102 : w.p_ = std::addressof(*it);
258 6440 : do_arr2:
259 6440 : if( !write_impl<Elem, StackEmpty>(w, ss) )
260 2339 : return w.suspend(writer::state::arr2, it, pt);
261 4101 : if(BOOST_JSON_UNLIKELY( ++it == end ))
262 2933 : break;
263 1168 : do_arr3:
264 1210 : if(BOOST_JSON_LIKELY(ss))
265 1168 : ss.append(',');
266 : else
267 42 : return w.suspend(writer::state::arr3, it, pt);
268 : }
269 3674 : do_arr4:
270 3674 : if(BOOST_JSON_LIKELY(ss))
271 3440 : ss.append(']');
272 : else
273 234 : return w.suspend(writer::state::arr4, it, pt);
274 3440 : return true;
275 6125 : }
276 :
277 : template<class T, bool StackEmpty>
278 : BOOST_FORCEINLINE
279 : bool
280 : write_impl(map_like_conversion_tag, writer& w, stream& ss0)
281 : {
282 : using It = iterator_type<T const>;
283 : using Mapped = mapped_type<T>;
284 :
285 : T const* pt;
286 27361 : local_stream ss(ss0);
287 96 : It it;
288 96 : It end;
289 : #if defined(_MSC_VER)
290 : # pragma warning( push )
291 : # pragma warning( disable : 4127 )
292 : #endif
293 9164 : if(StackEmpty || w.st_.empty())
294 : #if defined(_MSC_VER)
295 : # pragma warning( pop )
296 : #endif
297 : {
298 18197 : BOOST_ASSERT( w.p_ );
299 18197 : pt = reinterpret_cast<T const*>(w.p_);
300 18197 : it = std::begin(*pt);
301 36394 : end = std::end(*pt);
302 : }
303 : else
304 : {
305 : writer::state st;
306 9164 : w.st_.pop(st);
307 9164 : w.st_.pop(it);
308 9164 : w.st_.pop(pt);
309 9164 : end = std::end(*pt);
310 9164 : switch(st)
311 : {
312 12 : default:
313 12 : case writer::state::obj1: goto do_obj1;
314 308 : case writer::state::obj2: goto do_obj2;
315 54 : case writer::state::obj3: goto do_obj3;
316 8724 : case writer::state::obj4: goto do_obj4;
317 18 : case writer::state::obj5: goto do_obj5;
318 48 : case writer::state::obj6: goto do_obj6;
319 : break;
320 : }
321 : }
322 18209 : do_obj1:
323 18209 : if(BOOST_JSON_LIKELY( ss ))
324 18197 : ss.append('{');
325 : else
326 12 : return w.suspend(writer::state::obj1, it, pt);
327 18197 : if(BOOST_JSON_UNLIKELY( it == end ))
328 563 : goto do_obj6;
329 2156 : for(;;)
330 : {
331 : {
332 : using std::get;
333 19790 : string_view const sv = get<0>(*it);
334 19790 : w.cs0_ = { sv.data(), sv.size() };
335 19790 : w.buf_[2] = false;
336 : }
337 : if( true )
338 : {
339 19790 : if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
340 181 : return w.suspend(writer::state::obj2, it, pt);
341 : }
342 : else
343 : {
344 308 : do_obj2:
345 308 : if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
346 127 : return w.suspend(writer::state::obj2, it, pt);
347 : }
348 181 : do_obj3:
349 19844 : if(BOOST_JSON_LIKELY(ss))
350 19790 : ss.append(':');
351 : else
352 54 : return w.suspend(writer::state::obj3, it, pt);
353 28514 : do_obj4:
354 : {
355 : using std::get;
356 28514 : w.p_ = std::addressof( get<1>(*it) );
357 : }
358 28514 : if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
359 8724 : return w.suspend(writer::state::obj4, it, pt);
360 19790 : ++it;
361 19790 : if(BOOST_JSON_UNLIKELY(it == end))
362 17634 : break;
363 2156 : do_obj5:
364 2174 : if(BOOST_JSON_LIKELY(ss))
365 2156 : ss.append(',');
366 : else
367 18 : return w.suspend(writer::state::obj5, it, pt);
368 : }
369 18245 : do_obj6:
370 18245 : if(BOOST_JSON_LIKELY( ss ))
371 : {
372 18197 : ss.append('}');
373 18197 : return true;
374 : }
375 48 : return w.suspend(writer::state::obj6, it, pt);
376 27361 : }
377 :
378 : template< class T, bool StackEmpty >
379 : struct serialize_tuple_elem_helper
380 : {
381 : writer& w;
382 : stream& ss;
383 : T const* pt;
384 :
385 : template< std::size_t I >
386 : bool
387 258 : operator()( std::integral_constant<std::size_t, I> ) const
388 : {
389 : using std::get;
390 258 : w.p_ = std::addressof( get<I>(*pt) );
391 :
392 : using Elem = tuple_element_t<I, T>;
393 258 : return write_impl<Elem, StackEmpty>(w, ss);
394 : }
395 : };
396 :
397 : template<class T, bool StackEmpty>
398 : BOOST_FORCEINLINE
399 : bool
400 : write_impl(tuple_conversion_tag, writer& w, stream& ss0)
401 : {
402 : T const* pt;
403 174 : local_stream ss(ss0);
404 : std::size_t cur;
405 64 : constexpr std::size_t N = std::tuple_size<T>::value;
406 : #if defined(_MSC_VER)
407 : # pragma warning( push )
408 : # pragma warning( disable : 4127 )
409 : #endif
410 110 : if(StackEmpty || w.st_.empty())
411 : {
412 : #if defined(_MSC_VER)
413 : # pragma warning( pop )
414 : #endif
415 76 : BOOST_ASSERT( w.p_ );
416 76 : pt = reinterpret_cast<T const*>(w.p_);
417 76 : cur = 0;
418 : }
419 : else
420 : {
421 : writer::state st;
422 98 : w.st_.pop(st);
423 98 : w.st_.pop(cur);
424 98 : w.st_.pop(pt);
425 98 : switch(st)
426 : {
427 2 : default:
428 2 : case writer::state::arr1: goto do_arr1;
429 82 : case writer::state::arr2: goto do_arr2;
430 8 : case writer::state::arr3: goto do_arr3;
431 6 : case writer::state::arr4: goto do_arr4;
432 : break;
433 : }
434 : }
435 78 : do_arr1:
436 78 : if(BOOST_JSON_LIKELY(ss))
437 76 : ss.append('[');
438 : else
439 2 : return w.suspend(writer::state::arr1, cur, pt);
440 100 : for(;;)
441 : {
442 258 : do_arr2:
443 : {
444 258 : bool const stop = !mp11::mp_with_index<N>(
445 : cur,
446 : serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt});
447 258 : if(BOOST_JSON_UNLIKELY( stop ))
448 82 : return w.suspend(writer::state::arr2, cur, pt);
449 : }
450 176 : if(BOOST_JSON_UNLIKELY( ++cur == N ))
451 76 : break;
452 100 : do_arr3:
453 108 : if(BOOST_JSON_LIKELY(ss))
454 100 : ss.append(',');
455 : else
456 8 : return w.suspend(writer::state::arr3, cur, pt);
457 : }
458 82 : do_arr4:
459 82 : if(BOOST_JSON_LIKELY(ss))
460 76 : ss.append(']');
461 : else
462 6 : return w.suspend(writer::state::arr4, cur, pt);
463 76 : return true;
464 174 : }
465 :
466 : template< class T, bool StackEmpty >
467 : struct serialize_struct_elem_helper
468 : {
469 : static_assert(
470 : uniquely_named_members<T>::value,
471 : "The type has several described members with the same name.");
472 :
473 : writer& w;
474 : local_stream& ss;
475 : T const* pt;
476 : writer::state st;
477 :
478 : template< std::size_t I >
479 : writer::state
480 : operator()( std::integral_constant<std::size_t, I> ) const
481 : {
482 : using Ds = described_members<T>;
483 : using D = mp11::mp_at_c<Ds, I>;
484 : using M = described_member_t<T, D>;
485 :
486 : switch(st)
487 : {
488 : case writer::state::obj2: goto do_obj2;
489 : case writer::state::obj3: goto do_obj3;
490 : case writer::state::obj4: goto do_obj4;
491 : default: break;
492 : }
493 :
494 : {
495 : string_view const sv = D::name;
496 : w.cs0_ = { sv.data(), sv.size() };
497 : w.buf_[2] = false;
498 : }
499 : if( true )
500 : {
501 : if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
502 : return writer::state::obj2;
503 : }
504 : else
505 : {
506 : do_obj2:
507 : if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
508 : return writer::state::obj2;
509 : }
510 : do_obj3:
511 : if(BOOST_JSON_LIKELY(ss))
512 : ss.append(':');
513 : else
514 : return writer::state::obj3;
515 : do_obj4:
516 : w.p_ = std::addressof( pt->* D::pointer );
517 : if(BOOST_JSON_UNLIKELY((
518 : !write_impl<M, StackEmpty>(w, ss) )))
519 : return writer::state::obj4;
520 :
521 : return writer::state{};
522 : }
523 : };
524 :
525 : template<class T, bool StackEmpty>
526 : BOOST_FORCEINLINE
527 : bool
528 : write_impl(described_class_conversion_tag, writer& w, stream& ss0)
529 : {
530 : using Ds = described_members<T>;
531 :
532 : T const* pt;
533 : local_stream ss(ss0);
534 : std::size_t cur;
535 : constexpr std::size_t N = mp11::mp_size<Ds>::value;
536 : writer::state st;
537 : #if defined(_MSC_VER)
538 : # pragma warning( push )
539 : # pragma warning( disable : 4127 )
540 : #endif
541 : if(StackEmpty || w.st_.empty())
542 : #if defined(_MSC_VER)
543 : # pragma warning( pop )
544 : #endif
545 : {
546 : BOOST_ASSERT( w.p_ );
547 : pt = reinterpret_cast<T const*>(w.p_);
548 : cur = 0;
549 : }
550 : else
551 : {
552 : w.st_.pop(st);
553 : w.st_.pop(cur);
554 : w.st_.pop(pt);
555 : switch(st)
556 : {
557 : default:
558 : case writer::state::obj1: goto do_obj1;
559 : case writer::state::obj2: // fall through
560 : case writer::state::obj3: // fall through
561 : case writer::state::obj4: goto do_obj2;
562 : case writer::state::obj5: goto do_obj5;
563 : case writer::state::obj6: goto do_obj6;
564 : break;
565 : }
566 : }
567 : do_obj1:
568 : if(BOOST_JSON_LIKELY( ss ))
569 : ss.append('{');
570 : else
571 : return w.suspend(writer::state::obj1, cur, pt);
572 : if(BOOST_JSON_UNLIKELY( cur == N ))
573 : goto do_obj6;
574 : for(;;)
575 : {
576 : st = {};
577 : do_obj2:
578 : st = mp11::mp_with_index<N>(
579 : cur,
580 : serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st});
581 : if(BOOST_JSON_UNLIKELY( st != writer::state{} ))
582 : return w.suspend(st, cur, pt);
583 : ++cur;
584 : if(BOOST_JSON_UNLIKELY(cur == N))
585 : break;
586 : do_obj5:
587 : if(BOOST_JSON_LIKELY(ss))
588 : ss.append(',');
589 : else
590 : return w.suspend(writer::state::obj5, cur, pt);
591 : }
592 : do_obj6:
593 : if(BOOST_JSON_LIKELY( ss ))
594 : {
595 : ss.append('}');
596 : return true;
597 : }
598 : return w.suspend(writer::state::obj6, cur, pt);
599 : }
600 :
601 : template<class T, bool StackEmpty>
602 : BOOST_FORCEINLINE
603 : bool
604 : write_impl(described_enum_conversion_tag, writer& w, stream& ss)
605 : {
606 : #ifdef BOOST_DESCRIBE_CXX14
607 : using Integer = typename std::underlying_type<T>::type;
608 :
609 : #if defined(_MSC_VER)
610 : # pragma warning( push )
611 : # pragma warning( disable : 4127 )
612 : #endif
613 : if(StackEmpty || w.st_.empty())
614 : #if defined(_MSC_VER)
615 : # pragma warning( pop )
616 : #endif
617 : {
618 : BOOST_ASSERT( w.p_ );
619 : T const* pt = reinterpret_cast<T const*>(w.p_);
620 : char const* const name = describe::enum_to_string(*pt, nullptr);
621 : if( name )
622 : {
623 : string_view const sv = name;
624 : w.cs0_ = { sv.data(), sv.size() };
625 : w.buf_[2] = false;
626 : return write_string(w, ss);
627 : }
628 : else
629 : {
630 : Integer n = static_cast<Integer>(*pt);
631 : w.p_ = &n;
632 : return write_impl<Integer, true>(w, ss);
633 : }
634 : }
635 : else
636 : {
637 : writer::state st;
638 : w.st_.peek(st);
639 : if( st == writer::state::lit )
640 : return write_impl<Integer, false>(w, ss);
641 : else
642 : return resume_string(w, ss);
643 : }
644 : #else // BOOST_DESCRIBE_CXX14
645 : (void)w;
646 : (void)ss;
647 : static_assert(
648 : !std::is_same<T, T>::value,
649 : "described enums require C++14 support");
650 : return false;
651 : #endif // BOOST_DESCRIBE_CXX14
652 : }
653 :
654 : template< class T, bool StackEmpty >
655 : struct serialize_variant_elem_helper
656 : {
657 : writer& w;
658 : stream& ss;
659 :
660 : template<class Elem>
661 : bool
662 : operator()(Elem const& x) const
663 : {
664 : w.p_ = std::addressof(x);
665 : return write_impl<Elem, true>(w, ss);
666 : }
667 : };
668 :
669 : template< class T >
670 : struct serialize_variant_elem_helper<T, false>
671 : {
672 : writer& w;
673 : stream& ss;
674 :
675 : template< std::size_t I >
676 : bool
677 : operator()( std::integral_constant<std::size_t, I> ) const
678 : {
679 : using std::get;
680 : using Elem = remove_cvref<decltype(get<I>(
681 : std::declval<T const&>() ))>;
682 : return write_impl<Elem, false>(w, ss);
683 : }
684 : };
685 :
686 : template<class T, bool StackEmpty>
687 : BOOST_FORCEINLINE
688 : bool
689 : write_impl(variant_conversion_tag, writer& w, stream& ss)
690 : {
691 : T const* pt;
692 :
693 : using Index = remove_cvref<decltype( pt->index() )>;
694 :
695 : #if defined(_MSC_VER)
696 : # pragma warning( push )
697 : # pragma warning( disable : 4127 )
698 : #endif
699 : if(StackEmpty || w.st_.empty())
700 : #if defined(_MSC_VER)
701 : # pragma warning( pop )
702 : #endif
703 : {
704 : BOOST_ASSERT( w.p_ );
705 : pt = reinterpret_cast<T const*>(w.p_);
706 : if(BOOST_JSON_LIKELY((
707 : visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt))))
708 : return true;
709 :
710 : Index const ix = pt->index();
711 : w.st_.push(ix);
712 : return false;
713 : }
714 : else
715 : {
716 : Index ix;
717 : w.st_.pop(ix);
718 :
719 : constexpr std::size_t N = mp11::mp_size<T>::value;
720 : if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>(
721 : ix,
722 : serialize_variant_elem_helper<T, false>{w, ss}))))
723 : return true;
724 :
725 : w.st_.push(ix);
726 : return false;
727 : }
728 : }
729 :
730 : template<class T, bool StackEmpty>
731 : BOOST_FORCEINLINE
732 : bool
733 : write_impl(optional_conversion_tag, writer& w, stream& ss)
734 : {
735 : using Elem = value_result_type<T>;
736 :
737 : bool done;
738 : bool has_value;
739 :
740 : #if defined(_MSC_VER)
741 : # pragma warning( push )
742 : # pragma warning( disable : 4127 )
743 : #endif
744 : if(StackEmpty || w.st_.empty())
745 : #if defined(_MSC_VER)
746 : # pragma warning( pop )
747 : #endif
748 : {
749 : BOOST_ASSERT( w.p_ );
750 : T const* pt = reinterpret_cast<T const*>(w.p_);
751 : has_value = static_cast<bool>(*pt);
752 : if( has_value )
753 : {
754 : w.p_ = std::addressof( *(*pt) );
755 : done = write_impl<Elem, true>(w, ss);
756 : }
757 : else
758 : {
759 : w.p_ = nullptr;
760 : done = write_impl<std::nullptr_t, true>(w, ss);;
761 : }
762 : }
763 : else
764 : {
765 : w.st_.pop(has_value);
766 :
767 : if( has_value )
768 : done = write_impl<Elem, false>(w, ss);
769 : else
770 : done = write_impl<std::nullptr_t, false>(w, ss);
771 : }
772 :
773 : if(BOOST_JSON_UNLIKELY( !done ))
774 : w.st_.push(has_value);
775 :
776 : return done;
777 : }
778 :
779 : template<class T, bool StackEmpty>
780 : BOOST_FORCEINLINE
781 : bool
782 : write_impl(path_conversion_tag, writer& w, stream& ss)
783 : {
784 : w.buf_[2] = false;
785 : #if defined(_MSC_VER)
786 : # pragma warning( push )
787 : # pragma warning( disable : 4127 )
788 : #endif
789 : if(StackEmpty || w.st_.empty())
790 : #if defined(_MSC_VER)
791 : # pragma warning( pop )
792 : #endif
793 : {
794 : BOOST_ASSERT( w.p_ );
795 : T const* pt = reinterpret_cast<T const*>(w.p_);
796 :
797 : std::string const s = pt->generic_string();
798 : w.cs0_ = { s.data(), s.size() };
799 : if(BOOST_JSON_LIKELY( write_string(w, ss) ))
800 : return true;
801 :
802 : std::size_t const used = w.cs0_.used( s.data() );
803 : w.st_.push( used );
804 : w.st_.push( std::move(s) );
805 : return false;
806 : }
807 : else
808 : {
809 : std::string s;
810 : std::size_t used;
811 : w.st_.pop( s );
812 : w.st_.pop( used );
813 :
814 : w.cs0_ = { s.data(), s.size() };
815 : w.cs0_.skip(used);
816 :
817 : if(BOOST_JSON_LIKELY( resume_string(w, ss) ))
818 : return true;
819 :
820 : used = w.cs0_.used( s.data() );
821 : w.st_.push( used );
822 : w.st_.push( std::move(s) );
823 : return false;
824 : }
825 : }
826 :
827 : template<class T, bool StackEmpty>
828 : bool
829 35744 : write_impl(writer& w, stream& ss)
830 : {
831 : using cat = detail::generic_conversion_category<T>;
832 35743 : return write_impl<T, StackEmpty>( cat(), w, ss );
833 : }
834 :
835 : } // namespace detail
836 :
837 : template<class T>
838 : void
839 219 : serializer::reset(T const* p) noexcept
840 : {
841 : BOOST_CORE_STATIC_ASSERT( !std::is_pointer<T>::value );
842 : BOOST_CORE_STATIC_ASSERT( std::is_object<T>::value );
843 :
844 219 : p_ = p;
845 219 : fn0_ = &detail::write_impl<T, true>;
846 219 : fn1_ = &detail::write_impl<T, false>;
847 219 : st_.clear();
848 219 : done_ = false;
849 219 : }
850 :
851 : } // namespace json
852 : } // namespace boost
853 :
854 : #endif // BOOST_JSON_IMPL_SERIALIZER_HPP
|