Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:34:45

0001 //
0002 // Copyright (c) 2024 Dmitry Arkhipov (grisumbras@yandex.ru)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/json
0008 //
0009 
0010 #ifndef BOOST_JSON_IMPL_SERIALIZER_HPP
0011 #define BOOST_JSON_IMPL_SERIALIZER_HPP
0012 
0013 #include <boost/describe/enum_to_string.hpp>
0014 #include <boost/json/conversion.hpp>
0015 #include <cstddef>
0016 
0017 namespace boost {
0018 namespace json {
0019 namespace detail {
0020 
0021 enum class writer::state : char
0022 {
0023     str1, str2, str3, esc1, utf1,
0024     utf2, utf3, utf4, utf5,
0025     lit,
0026     arr1, arr2, arr3, arr4,
0027     obj1, obj2, obj3, obj4, obj5, obj6
0028 };
0029 
0030 bool
0031 writer::
0032 suspend(state st)
0033 {
0034     st_.push(st);
0035     return false;
0036 }
0037 
0038 template<class U, class T>
0039 bool
0040 writer::
0041 suspend(state st, U u, T const* pt)
0042 {
0043     st_.push(pt);
0044     st_.push(u);
0045     st_.push(st);
0046     return false;
0047 }
0048 
0049 template<class T, bool StackEmpty>
0050 bool
0051 write_impl(writer& w, stream& ss);
0052 
0053 template<class T, bool StackEmpty>
0054 BOOST_FORCEINLINE
0055 bool
0056 write_impl(null_like_conversion_tag, writer& w, stream& ss)
0057 {
0058 #if defined(_MSC_VER)
0059 # pragma warning( push )
0060 # pragma warning( disable : 4127 )
0061 #endif
0062     if( StackEmpty || w.st_.empty() )
0063         return write_null(w, ss);
0064 #if defined(_MSC_VER)
0065 # pragma warning( pop )
0066 #endif
0067     return resume_buffer(w, ss);
0068 }
0069 
0070 template<class T, bool StackEmpty>
0071 BOOST_FORCEINLINE
0072 bool
0073 write_impl(bool_conversion_tag, writer& w, stream& ss)
0074 {
0075     BOOST_ASSERT( w.p_ );
0076     auto const t = *reinterpret_cast<T const*>(w.p_);
0077 
0078 #if defined(_MSC_VER)
0079 # pragma warning( push )
0080 # pragma warning( disable : 4127 )
0081 #endif
0082     if( StackEmpty || w.st_.empty() )
0083 #if defined(_MSC_VER)
0084 # pragma warning( pop )
0085 #endif
0086     {
0087         if( t )
0088             return write_true(w, ss);
0089         else
0090             return write_false(w, ss);
0091     }
0092 
0093     return resume_buffer(w, ss);
0094 }
0095 
0096 template<class T, bool StackEmpty>
0097 BOOST_FORCEINLINE
0098 bool
0099 write_impl(integral_conversion_tag, writer& w, stream& ss0)
0100 {
0101 #if defined(_MSC_VER)
0102 # pragma warning( push )
0103 # pragma warning( disable : 4127 )
0104 #endif
0105     if( StackEmpty || w.st_.empty() )
0106 #if defined(_MSC_VER)
0107 # pragma warning( pop )
0108 #endif
0109     {
0110         auto const& t = *reinterpret_cast<T const*>(w.p_);
0111 
0112 #if defined(__clang__)
0113 # pragma clang diagnostic push
0114 # pragma clang diagnostic ignored "-Wsign-compare"
0115 #elif defined(__GNUC__)
0116 # pragma GCC diagnostic push
0117 # pragma GCC  diagnostic ignored "-Wsign-compare"
0118 #elif defined(_MSC_VER)
0119 # pragma warning( push )
0120 # pragma warning( disable : 4018 )
0121 # pragma warning( disable : 4127 )
0122 #endif
0123 
0124         if( t < 0 )
0125         {
0126             // T is obviously signed, so this comparison is safe
0127             if( t >= (std::numeric_limits<std::int64_t>::min)() )
0128             {
0129                 std::int64_t i = t;
0130                 return write_int64(w, ss0, i);
0131             }
0132         }
0133         else if( t <= (std::numeric_limits<std::uint64_t>::max)() )
0134         {
0135             std::uint64_t u = t;
0136             return write_uint64(w, ss0, u);
0137         }
0138 #if defined(__clang__)
0139 # pragma clang diagnostic pop
0140 #elif defined(__GNUC__)
0141 # pragma GCC diagnostic pop
0142 #elif defined(_MSC_VER)
0143 # pragma warning( pop )
0144 #endif
0145 
0146 #if defined(_MSC_VER)
0147 # pragma warning( push )
0148 # pragma warning( disable : 4244 )
0149 #endif
0150         double d = t;
0151         return write_double(w, ss0, d);
0152 #if defined(_MSC_VER)
0153 # pragma warning( pop )
0154 #endif
0155     }
0156 
0157     return resume_buffer(w, ss0);
0158 }
0159 
0160 template<class T, bool StackEmpty>
0161 BOOST_FORCEINLINE
0162 bool
0163 write_impl(floating_point_conversion_tag, writer& w, stream& ss0)
0164 {
0165 #if defined(_MSC_VER)
0166 # pragma warning( push )
0167 # pragma warning( disable : 4127 )
0168 #endif
0169     if( StackEmpty || w.st_.empty() )
0170 #if defined(_MSC_VER)
0171 # pragma warning( pop )
0172 #endif
0173     {
0174         double d = *reinterpret_cast<T const*>(w.p_);
0175         return write_double(w, ss0, d);
0176     }
0177 
0178     return resume_buffer(w, ss0);
0179 }
0180 
0181 template<class T, bool StackEmpty>
0182 BOOST_FORCEINLINE
0183 bool
0184 write_impl(string_like_conversion_tag, writer& w, stream& ss0)
0185 {
0186 #if defined(_MSC_VER)
0187 # pragma warning( push )
0188 # pragma warning( disable : 4127 )
0189 #endif
0190     if( StackEmpty || w.st_.empty() )
0191 #if defined(_MSC_VER)
0192 # pragma warning( pop )
0193 #endif
0194     {
0195         string_view const sv = *reinterpret_cast<T const*>(w.p_);
0196         w.cs0_ = { sv.data(), sv.size() };
0197         return write_string(w, ss0);
0198     }
0199 
0200     return resume_string(w, ss0);
0201 }
0202 
0203 template<class T, bool StackEmpty>
0204 BOOST_FORCEINLINE
0205 bool
0206 write_impl(sequence_conversion_tag, writer& w, stream& ss0)
0207 {
0208     using It = iterator_type<T const>;
0209     using Elem = value_type<T>;
0210 
0211     T const* pt;
0212     local_stream ss(ss0);
0213     It it;
0214     It end;
0215 #if defined(_MSC_VER)
0216 # pragma warning( push )
0217 # pragma warning( disable : 4127 )
0218 #endif
0219     if(StackEmpty || w.st_.empty())
0220     {
0221 #if defined(_MSC_VER)
0222 # pragma warning( pop )
0223 #endif
0224         BOOST_ASSERT( w.p_ );
0225         pt = reinterpret_cast<T const*>(w.p_);
0226         it = std::begin(*pt);
0227         end = std::end(*pt);
0228     }
0229     else
0230     {
0231         writer::state st;
0232         w.st_.pop(st);
0233         w.st_.pop(it);
0234         w.st_.pop(pt);
0235         end = std::end(*pt);
0236         switch(st)
0237         {
0238         default:
0239         case writer::state::arr1: goto do_arr1;
0240         case writer::state::arr2: goto do_arr2;
0241         case writer::state::arr3: goto do_arr3;
0242         case writer::state::arr4: goto do_arr4;
0243             break;
0244         }
0245     }
0246 do_arr1:
0247     if(BOOST_JSON_LIKELY(ss))
0248         ss.append('[');
0249     else
0250         return w.suspend(writer::state::arr1, it, pt);
0251     if(it == end)
0252         goto do_arr4;
0253     for(;;)
0254     {
0255         w.p_ = std::addressof(*it);
0256 do_arr2:
0257         if( !write_impl<Elem, StackEmpty>(w, ss) )
0258             return w.suspend(writer::state::arr2, it, pt);
0259         if(BOOST_JSON_UNLIKELY( ++it == end ))
0260             break;
0261 do_arr3:
0262         if(BOOST_JSON_LIKELY(ss))
0263             ss.append(',');
0264         else
0265             return w.suspend(writer::state::arr3, it, pt);
0266     }
0267 do_arr4:
0268     if(BOOST_JSON_LIKELY(ss))
0269         ss.append(']');
0270     else
0271         return w.suspend(writer::state::arr4, it, pt);
0272     return true;
0273 }
0274 
0275 template<class T, bool StackEmpty>
0276 BOOST_FORCEINLINE
0277 bool
0278 write_impl(map_like_conversion_tag, writer& w, stream& ss0)
0279 {
0280     using It = iterator_type<T const>;
0281     using Mapped = mapped_type<T>;
0282 
0283     T const* pt;
0284     local_stream ss(ss0);
0285     It it;
0286     It end;
0287 #if defined(_MSC_VER)
0288 # pragma warning( push )
0289 # pragma warning( disable : 4127 )
0290 #endif
0291     if(StackEmpty || w.st_.empty())
0292 #if defined(_MSC_VER)
0293 # pragma warning( pop )
0294 #endif
0295     {
0296         BOOST_ASSERT( w.p_ );
0297         pt = reinterpret_cast<T const*>(w.p_);
0298         it = std::begin(*pt);
0299         end = std::end(*pt);
0300     }
0301     else
0302     {
0303         writer::state st;
0304         w.st_.pop(st);
0305         w.st_.pop(it);
0306         w.st_.pop(pt);
0307         end = std::end(*pt);
0308         switch(st)
0309         {
0310         default:
0311         case writer::state::obj1: goto do_obj1;
0312         case writer::state::obj2: goto do_obj2;
0313         case writer::state::obj3: goto do_obj3;
0314         case writer::state::obj4: goto do_obj4;
0315         case writer::state::obj5: goto do_obj5;
0316         case writer::state::obj6: goto do_obj6;
0317             break;
0318         }
0319     }
0320 do_obj1:
0321     if(BOOST_JSON_LIKELY( ss ))
0322         ss.append('{');
0323     else
0324         return w.suspend(writer::state::obj1, it, pt);
0325     if(BOOST_JSON_UNLIKELY( it == end ))
0326         goto do_obj6;
0327     for(;;)
0328     {
0329         {
0330             using std::get;
0331             string_view const sv = get<0>(*it);
0332             w.cs0_ = { sv.data(), sv.size() };
0333         }
0334         if( true )
0335         {
0336             if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
0337                 return w.suspend(writer::state::obj2, it, pt);
0338         }
0339         else
0340         {
0341 do_obj2:
0342             if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
0343                 return w.suspend(writer::state::obj2, it, pt);
0344         }
0345 do_obj3:
0346         if(BOOST_JSON_LIKELY(ss))
0347             ss.append(':');
0348         else
0349             return w.suspend(writer::state::obj3, it, pt);
0350 do_obj4:
0351         {
0352             using std::get;
0353             w.p_ = std::addressof( get<1>(*it) );
0354         }
0355         if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
0356             return w.suspend(writer::state::obj4, it, pt);
0357         ++it;
0358         if(BOOST_JSON_UNLIKELY(it == end))
0359             break;
0360 do_obj5:
0361         if(BOOST_JSON_LIKELY(ss))
0362             ss.append(',');
0363         else
0364             return w.suspend(writer::state::obj5, it, pt);
0365     }
0366 do_obj6:
0367     if(BOOST_JSON_LIKELY( ss ))
0368     {
0369         ss.append('}');
0370         return true;
0371     }
0372     return w.suspend(writer::state::obj6, it, pt);
0373 }
0374 
0375 template< class T, bool StackEmpty >
0376 struct serialize_tuple_elem_helper
0377 {
0378     writer& w;
0379     stream& ss;
0380     T const* pt;
0381 
0382     template< std::size_t I >
0383     bool
0384     operator()( std::integral_constant<std::size_t, I> ) const
0385     {
0386         using std::get;
0387         w.p_ = std::addressof( get<I>(*pt) );
0388 
0389         using Elem = tuple_element_t<I, T>;
0390         return write_impl<Elem, StackEmpty>(w, ss);
0391     }
0392 };
0393 
0394 template<class T, bool StackEmpty>
0395 BOOST_FORCEINLINE
0396 bool
0397 write_impl(tuple_conversion_tag, writer& w, stream& ss0)
0398 {
0399     T const* pt;
0400     local_stream ss(ss0);
0401     std::size_t cur;
0402     constexpr std::size_t N = std::tuple_size<T>::value;
0403 #if defined(_MSC_VER)
0404 # pragma warning( push )
0405 # pragma warning( disable : 4127 )
0406 #endif
0407     if(StackEmpty || w.st_.empty())
0408     {
0409 #if defined(_MSC_VER)
0410 # pragma warning( pop )
0411 #endif
0412         BOOST_ASSERT( w.p_ );
0413         pt = reinterpret_cast<T const*>(w.p_);
0414         cur = 0;
0415     }
0416     else
0417     {
0418         writer::state st;
0419         w.st_.pop(st);
0420         w.st_.pop(cur);
0421         w.st_.pop(pt);
0422         switch(st)
0423         {
0424         default:
0425         case writer::state::arr1: goto do_arr1;
0426         case writer::state::arr2: goto do_arr2;
0427         case writer::state::arr3: goto do_arr3;
0428         case writer::state::arr4: goto do_arr4;
0429             break;
0430         }
0431     }
0432 do_arr1:
0433     if(BOOST_JSON_LIKELY(ss))
0434         ss.append('[');
0435     else
0436         return w.suspend(writer::state::arr1, cur, pt);
0437     for(;;)
0438     {
0439 do_arr2:
0440         {
0441             bool const stop = !mp11::mp_with_index<N>(
0442                 cur,
0443                 serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt});
0444             if(BOOST_JSON_UNLIKELY( stop ))
0445                 return w.suspend(writer::state::arr2, cur, pt);
0446         }
0447         if(BOOST_JSON_UNLIKELY( ++cur == N ))
0448             break;
0449 do_arr3:
0450         if(BOOST_JSON_LIKELY(ss))
0451             ss.append(',');
0452         else
0453             return w.suspend(writer::state::arr3, cur, pt);
0454     }
0455 do_arr4:
0456     if(BOOST_JSON_LIKELY(ss))
0457         ss.append(']');
0458     else
0459         return w.suspend(writer::state::arr4, cur, pt);
0460     return true;
0461 }
0462 
0463 template< class T, bool StackEmpty >
0464 struct serialize_struct_elem_helper
0465 {
0466     writer& w;
0467     local_stream& ss;
0468     T const* pt;
0469     writer::state st;
0470 
0471     template< std::size_t I >
0472     writer::state
0473     operator()( std::integral_constant<std::size_t, I> ) const
0474     {
0475         using Ds = described_members<T>;
0476         using D = mp11::mp_at_c<Ds, I>;
0477         using M = described_member_t<T, D>;
0478 
0479         switch(st)
0480         {
0481         case writer::state::obj2: goto do_obj2;
0482         case writer::state::obj3: goto do_obj3;
0483         case writer::state::obj4: goto do_obj4;
0484         default: break;
0485         }
0486 
0487         {
0488             string_view const sv = D::name;
0489             w.cs0_ = { sv.data(), sv.size() };
0490         }
0491         if( true )
0492         {
0493             if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
0494                 return writer::state::obj2;
0495         }
0496         else
0497         {
0498 do_obj2:
0499             if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
0500                 return writer::state::obj2;
0501         }
0502 do_obj3:
0503         if(BOOST_JSON_LIKELY(ss))
0504             ss.append(':');
0505         else
0506             return writer::state::obj3;
0507 do_obj4:
0508         w.p_ = std::addressof( pt->* D::pointer );
0509         if(BOOST_JSON_UNLIKELY((
0510                 !write_impl<M, StackEmpty>(w, ss) )))
0511             return writer::state::obj4;
0512 
0513         return writer::state{};
0514     }
0515 };
0516 
0517 template<class T, bool StackEmpty>
0518 BOOST_FORCEINLINE
0519 bool
0520 write_impl(described_class_conversion_tag, writer& w, stream& ss0)
0521 {
0522     using Ds = described_members<T>;
0523 
0524     T const* pt;
0525     local_stream ss(ss0);
0526     std::size_t cur;
0527     constexpr std::size_t N = mp11::mp_size<Ds>::value;
0528     writer::state st;
0529 #if defined(_MSC_VER)
0530 # pragma warning( push )
0531 # pragma warning( disable : 4127 )
0532 #endif
0533     if(StackEmpty || w.st_.empty())
0534 #if defined(_MSC_VER)
0535 # pragma warning( pop )
0536 #endif
0537     {
0538         BOOST_ASSERT( w.p_ );
0539         pt = reinterpret_cast<T const*>(w.p_);
0540         cur = 0;
0541     }
0542     else
0543     {
0544         w.st_.pop(st);
0545         w.st_.pop(cur);
0546         w.st_.pop(pt);
0547         switch(st)
0548         {
0549         default:
0550         case writer::state::obj1: goto do_obj1;
0551         case writer::state::obj2: // fall through
0552         case writer::state::obj3: // fall through
0553         case writer::state::obj4: goto do_obj2;
0554         case writer::state::obj5: goto do_obj5;
0555         case writer::state::obj6: goto do_obj6;
0556             break;
0557         }
0558     }
0559 do_obj1:
0560     if(BOOST_JSON_LIKELY( ss ))
0561         ss.append('{');
0562     else
0563         return w.suspend(writer::state::obj1, cur, pt);
0564     if(BOOST_JSON_UNLIKELY( cur == N ))
0565         goto do_obj6;
0566     for(;;)
0567     {
0568         st = {};
0569 do_obj2:
0570         st = mp11::mp_with_index<N>(
0571             cur,
0572             serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st});
0573         if(BOOST_JSON_UNLIKELY( st != writer::state{} ))
0574             return w.suspend(st, cur, pt);
0575         ++cur;
0576         if(BOOST_JSON_UNLIKELY(cur == N))
0577             break;
0578 do_obj5:
0579         if(BOOST_JSON_LIKELY(ss))
0580             ss.append(',');
0581         else
0582             return w.suspend(writer::state::obj5, cur, pt);
0583     }
0584 do_obj6:
0585     if(BOOST_JSON_LIKELY( ss ))
0586     {
0587         ss.append('}');
0588         return true;
0589     }
0590     return w.suspend(writer::state::obj6, cur, pt);
0591 }
0592 
0593 template<class T, bool StackEmpty>
0594 BOOST_FORCEINLINE
0595 bool
0596 write_impl(described_enum_conversion_tag, writer& w, stream& ss)
0597 {
0598 #ifdef BOOST_DESCRIBE_CXX14
0599     using Integer = typename std::underlying_type<T>::type;
0600 
0601 #if defined(_MSC_VER)
0602 # pragma warning( push )
0603 # pragma warning( disable : 4127 )
0604 #endif
0605     if(StackEmpty || w.st_.empty())
0606 #if defined(_MSC_VER)
0607 # pragma warning( pop )
0608 #endif
0609     {
0610         BOOST_ASSERT( w.p_ );
0611         T const* pt = reinterpret_cast<T const*>(w.p_);
0612         char const* const name = describe::enum_to_string(*pt, nullptr);
0613         if( name )
0614         {
0615             string_view const sv = name;
0616             w.cs0_ = { sv.data(), sv.size() };
0617             return write_string(w, ss);
0618         }
0619         else
0620         {
0621             Integer n = static_cast<Integer>(*pt);
0622             w.p_ = &n;
0623             return write_impl<Integer, true>(w, ss);
0624         }
0625     }
0626     else
0627     {
0628         writer::state st;
0629         w.st_.peek(st);
0630         if( st == writer::state::lit )
0631             return write_impl<Integer, false>(w, ss);
0632         else
0633             return resume_string(w, ss);
0634     }
0635 #else // BOOST_DESCRIBE_CXX14
0636     (void)w;
0637     (void)ss;
0638     static_assert(
0639         !std::is_same<T, T>::value,
0640         "described enums require C++14 support");
0641     return false;
0642 #endif // BOOST_DESCRIBE_CXX14
0643 }
0644 
0645 template< class T, bool StackEmpty >
0646 struct serialize_variant_elem_helper
0647 {
0648     writer& w;
0649     stream& ss;
0650 
0651     template<class Elem>
0652     bool
0653     operator()(Elem const& x) const
0654     {
0655         w.p_ = std::addressof(x);
0656         return write_impl<Elem, true>(w, ss);
0657     }
0658 };
0659 
0660 template< class T >
0661 struct serialize_variant_elem_helper<T, false>
0662 {
0663     writer& w;
0664     stream& ss;
0665 
0666     template< std::size_t I >
0667     bool
0668     operator()( std::integral_constant<std::size_t, I> ) const
0669     {
0670         using std::get;
0671         using Elem = remove_cvref<decltype(get<I>(
0672             std::declval<T const&>() ))>;
0673         return write_impl<Elem, false>(w, ss);
0674     }
0675 };
0676 
0677 template<class T, bool StackEmpty>
0678 BOOST_FORCEINLINE
0679 bool
0680 write_impl(variant_conversion_tag, writer& w, stream& ss)
0681 {
0682     T const* pt;
0683 
0684     using Index = remove_cvref<decltype( pt->index() )>;
0685 
0686 #if defined(_MSC_VER)
0687 # pragma warning( push )
0688 # pragma warning( disable : 4127 )
0689 #endif
0690     if(StackEmpty || w.st_.empty())
0691 #if defined(_MSC_VER)
0692 # pragma warning( pop )
0693 #endif
0694     {
0695         BOOST_ASSERT( w.p_ );
0696         pt = reinterpret_cast<T const*>(w.p_);
0697         if(BOOST_JSON_LIKELY((
0698                 visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt))))
0699             return true;
0700 
0701         Index const ix = pt->index();
0702         w.st_.push(ix);
0703         return false;
0704     }
0705     else
0706     {
0707         Index ix;
0708         w.st_.pop(ix);
0709 
0710         constexpr std::size_t N = mp11::mp_size<T>::value;
0711         if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>(
0712                 ix,
0713                 serialize_variant_elem_helper<T, false>{w, ss}))))
0714             return true;
0715 
0716         w.st_.push(ix);
0717         return false;
0718     }
0719 }
0720 
0721 template<class T, bool StackEmpty>
0722 BOOST_FORCEINLINE
0723 bool
0724 write_impl(optional_conversion_tag, writer& w, stream& ss)
0725 {
0726     using Elem = value_result_type<T>;
0727 
0728     bool done;
0729     bool has_value;
0730 
0731 #if defined(_MSC_VER)
0732 # pragma warning( push )
0733 # pragma warning( disable : 4127 )
0734 #endif
0735     if(StackEmpty || w.st_.empty())
0736 #if defined(_MSC_VER)
0737 # pragma warning( pop )
0738 #endif
0739     {
0740         BOOST_ASSERT( w.p_ );
0741         T const* pt = reinterpret_cast<T const*>(w.p_);
0742         has_value = static_cast<bool>(*pt);
0743         if( has_value )
0744         {
0745             w.p_ = std::addressof( *(*pt) );
0746             done = write_impl<Elem, true>(w, ss);
0747         }
0748         else
0749         {
0750             w.p_ = nullptr;
0751             done = write_impl<std::nullptr_t, true>(w, ss);;
0752         }
0753     }
0754     else
0755     {
0756         w.st_.pop(has_value);
0757 
0758         if( has_value )
0759             done = write_impl<Elem, false>(w, ss);
0760         else
0761             done = write_impl<std::nullptr_t, false>(w, ss);
0762     }
0763 
0764     if(BOOST_JSON_UNLIKELY( !done ))
0765         w.st_.push(has_value);
0766 
0767     return done;
0768 }
0769 
0770 template<class T, bool StackEmpty>
0771 BOOST_FORCEINLINE
0772 bool
0773 write_impl(path_conversion_tag, writer& w, stream& ss)
0774 {
0775 #if defined(_MSC_VER)
0776 # pragma warning( push )
0777 # pragma warning( disable : 4127 )
0778 #endif
0779     if(StackEmpty || w.st_.empty())
0780 #if defined(_MSC_VER)
0781 # pragma warning( pop )
0782 #endif
0783     {
0784         BOOST_ASSERT( w.p_ );
0785         T const* pt = reinterpret_cast<T const*>(w.p_);
0786 
0787         std::string const s = pt->generic_string();
0788         w.cs0_ = { s.data(), s.size() };
0789         if(BOOST_JSON_LIKELY( write_string(w, ss) ))
0790             return true;
0791 
0792         std::size_t const used = w.cs0_.used( s.data() );
0793         w.st_.push( used );
0794         w.st_.push( std::move(s) );
0795         return false;
0796     }
0797     else
0798     {
0799         std::string s;
0800         std::size_t used;
0801         w.st_.pop( s );
0802         w.st_.pop( used );
0803 
0804         w.cs0_ = { s.data(), s.size() };
0805         w.cs0_.skip(used);
0806 
0807         if(BOOST_JSON_LIKELY( resume_string(w, ss) ))
0808             return true;
0809 
0810         used = w.cs0_.used( s.data() );
0811         w.st_.push( used );
0812         w.st_.push( std::move(s) );
0813         return false;
0814     }
0815 }
0816 
0817 template<class T, bool StackEmpty>
0818 bool
0819 write_impl(writer& w, stream& ss)
0820 {
0821     using cat = detail::generic_conversion_category<T>;
0822     return write_impl<T, StackEmpty>( cat(), w, ss );
0823 }
0824 
0825 } // namespace detail
0826 
0827 template<class T>
0828 void
0829 serializer::reset(T const* p) noexcept
0830 {
0831     BOOST_STATIC_ASSERT( !std::is_pointer<T>::value );
0832     BOOST_STATIC_ASSERT( std::is_object<T>::value );
0833 
0834     p_ = p;
0835     fn0_ = &detail::write_impl<T, true>;
0836     fn1_ = &detail::write_impl<T, false>;
0837     st_.clear();
0838     done_ = false;
0839 }
0840 
0841 } // namespace json
0842 } // namespace boost
0843 
0844 #endif // BOOST_JSON_IMPL_SERIALIZER_HPP