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