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/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 11875 : writer::
41 : suspend(state st, U u, T const* pt)
42 : {
43 11875 : st_.push(pt);
44 11874 : st_.push(u);
45 11874 : st_.push(st);
46 11874 : 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 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 0 : 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 61 : if( StackEmpty || w.st_.empty() )
83 : #if defined(_MSC_VER)
84 : # pragma warning( pop )
85 : #endif
86 : {
87 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 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 134 : if( t < 0 )
125 : {
126 : // T is obviously signed, so this comparison is safe
127 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 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 0 : double d = t;
151 0 : 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 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 112 : if( StackEmpty || w.st_.empty() )
191 : #if defined(_MSC_VER)
192 : # pragma warning( pop )
193 : #endif
194 : {
195 0 : string_view const sv = *reinterpret_cast<T const*>(w.p_);
196 91 : w.cs0_ = { sv.data(), sv.size() };
197 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 2656 : if(StackEmpty || w.st_.empty())
220 : {
221 : #if defined(_MSC_VER)
222 : # pragma warning( pop )
223 : #endif
224 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 2656 : w.st_.pop(st);
233 2656 : w.st_.pop(it);
234 2656 : w.st_.pop(pt);
235 2656 : end = std::end(*pt);
236 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 3492 : if(BOOST_JSON_LIKELY(ss))
248 3422 : ss.append('[');
249 : else
250 70 : return w.suspend(writer::state::arr1, it, pt);
251 3422 : if(it == end)
252 507 : goto do_arr4;
253 : for(;;)
254 : {
255 4064 : w.p_ = std::addressof(*it);
256 6378 : do_arr2:
257 6378 : if( !write_impl<Elem, StackEmpty>(w, ss) )
258 2315 : return w.suspend(writer::state::arr2, it, pt);
259 4063 : if(BOOST_JSON_UNLIKELY( ++it == end ))
260 2914 : break;
261 1149 : do_arr3:
262 1189 : if(BOOST_JSON_LIKELY(ss))
263 1149 : ss.append(',');
264 : else
265 40 : return w.suspend(writer::state::arr3, it, pt);
266 : }
267 3653 : do_arr4:
268 3653 : if(BOOST_JSON_LIKELY(ss))
269 3421 : ss.append(']');
270 : else
271 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 9120 : if(StackEmpty || w.st_.empty())
292 : #if defined(_MSC_VER)
293 : # pragma warning( pop )
294 : #endif
295 : {
296 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 9120 : w.st_.pop(st);
305 9120 : w.st_.pop(it);
306 9120 : w.st_.pop(pt);
307 9120 : end = std::end(*pt);
308 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 18182 : if(BOOST_JSON_LIKELY( ss ))
322 18170 : ss.append('{');
323 : else
324 12 : return w.suspend(writer::state::obj1, it, pt);
325 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 19736 : if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
337 173 : return w.suspend(writer::state::obj2, it, pt);
338 : }
339 : else
340 : {
341 296 : do_obj2:
342 296 : if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
343 123 : return w.suspend(writer::state::obj2, it, pt);
344 : }
345 173 : do_obj3:
346 19786 : if(BOOST_JSON_LIKELY(ss))
347 19736 : ss.append(':');
348 : else
349 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 28436 : if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
356 8700 : return w.suspend(writer::state::obj4, it, pt);
357 19736 : ++it;
358 19736 : if(BOOST_JSON_UNLIKELY(it == end))
359 17607 : break;
360 2129 : do_obj5:
361 2145 : if(BOOST_JSON_LIKELY(ss))
362 2129 : ss.append(',');
363 : else
364 16 : return w.suspend(writer::state::obj5, it, pt);
365 : }
366 18216 : do_obj6:
367 18216 : if(BOOST_JSON_LIKELY( ss ))
368 : {
369 18170 : ss.append('}');
370 18170 : return true;
371 : }
372 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 258 : operator()( std::integral_constant<std::size_t, I> ) const
385 : {
386 : using std::get;
387 258 : w.p_ = std::addressof( get<I>(*pt) );
388 :
389 : using Elem = tuple_element_t<I, T>;
390 258 : 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 110 : if(StackEmpty || w.st_.empty())
408 : {
409 : #if defined(_MSC_VER)
410 : # pragma warning( pop )
411 : #endif
412 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 98 : w.st_.pop(st);
420 98 : w.st_.pop(cur);
421 98 : w.st_.pop(pt);
422 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 78 : if(BOOST_JSON_LIKELY(ss))
434 76 : ss.append('[');
435 : else
436 2 : return w.suspend(writer::state::arr1, cur, pt);
437 100 : for(;;)
438 : {
439 258 : do_arr2:
440 : {
441 258 : bool const stop = !mp11::mp_with_index<N>(
442 : cur,
443 : serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt});
444 258 : if(BOOST_JSON_UNLIKELY( stop ))
445 82 : return w.suspend(writer::state::arr2, cur, pt);
446 : }
447 176 : if(BOOST_JSON_UNLIKELY( ++cur == N ))
448 76 : break;
449 100 : do_arr3:
450 108 : if(BOOST_JSON_LIKELY(ss))
451 100 : ss.append(',');
452 : else
453 8 : return w.suspend(writer::state::arr3, cur, pt);
454 : }
455 82 : do_arr4:
456 82 : if(BOOST_JSON_LIKELY(ss))
457 76 : ss.append(']');
458 : else
459 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 35604 : write_impl(writer& w, stream& ss)
824 : {
825 : using cat = detail::generic_conversion_category<T>;
826 35603 : return write_impl<T, StackEmpty>( cat(), w, ss );
827 : }
828 :
829 : } // namespace detail
830 :
831 : template<class T>
832 : void
833 219 : 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 219 : p_ = p;
839 219 : fn0_ = &detail::write_impl<T, true>;
840 219 : fn1_ = &detail::write_impl<T, false>;
841 219 : st_.clear();
842 219 : done_ = false;
843 219 : }
844 :
845 : } // namespace json
846 : } // namespace boost
847 :
848 : #endif // BOOST_JSON_IMPL_SERIALIZER_HPP
|