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 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 2656 : if(StackEmpty || w.st_.empty())
220 : {
221 : #if defined(_MSC_VER)
222 : # pragma warning( pop )
223 : #endif
224 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 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 3494 : do_arr1:
247 3494 : if(BOOST_JSON_LIKELY(ss))
248 3424 : ss.append('[');
249 : else
250 70 : return w.suspend(writer::state::arr1, it, pt);
251 3424 : if(it == end)
252 507 : goto do_arr4;
253 : for(;;)
254 : {
255 4070 : w.p_ = std::addressof(*it);
256 6384 : do_arr2:
257 6384 : if( !write_impl<Elem, StackEmpty>(w, ss) )
258 2315 : return w.suspend(writer::state::arr2, it, pt);
259 4069 : if(BOOST_JSON_UNLIKELY( ++it == end ))
260 2916 : break;
261 1153 : do_arr3:
262 1193 : if(BOOST_JSON_LIKELY(ss))
263 1153 : ss.append(',');
264 : else
265 40 : return w.suspend(writer::state::arr3, it, pt);
266 : }
267 3655 : do_arr4:
268 3655 : if(BOOST_JSON_LIKELY(ss))
269 3423 : ss.append(']');
270 : else
271 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 9120 : if(StackEmpty || w.st_.empty())
292 : #if defined(_MSC_VER)
293 : # pragma warning( pop )
294 : #endif
295 : {
296 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 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 18184 : do_obj1:
321 18184 : if(BOOST_JSON_LIKELY( ss ))
322 18172 : ss.append('{');
323 : else
324 12 : return w.suspend(writer::state::obj1, it, pt);
325 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 19742 : 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 19792 : if(BOOST_JSON_LIKELY(ss))
347 19742 : ss.append(':');
348 : else
349 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 28442 : if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
356 8700 : return w.suspend(writer::state::obj4, it, pt);
357 19742 : ++it;
358 19742 : if(BOOST_JSON_UNLIKELY(it == end))
359 17609 : break;
360 2133 : do_obj5:
361 2149 : if(BOOST_JSON_LIKELY(ss))
362 2133 : ss.append(',');
363 : else
364 16 : return w.suspend(writer::state::obj5, it, pt);
365 : }
366 18218 : do_obj6:
367 18218 : if(BOOST_JSON_LIKELY( ss ))
368 : {
369 18172 : ss.append('}');
370 18172 : return true;
371 : }
372 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 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 : 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 35616 : write_impl(writer& w, stream& ss)
820 : {
821 : using cat = detail::generic_conversion_category<T, detail::no_context>;
822 35615 : return write_impl<T, StackEmpty>( cat(), w, ss );
823 : }
824 :
825 : } // namespace detail
826 :
827 : template<class T>
828 : void
829 219 : 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 219 : p_ = p;
835 219 : fn0_ = &detail::write_impl<T, true>;
836 219 : fn1_ = &detail::write_impl<T, false>;
837 219 : st_.clear();
838 219 : done_ = false;
839 219 : }
840 :
841 : } // namespace json
842 : } // namespace boost
843 :
844 : #endif // BOOST_JSON_IMPL_SERIALIZER_HPP
|