LCOV - code coverage report
Current view: top level - json/impl - serializer.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 97.8 % 182 178
Test Date: 2026-01-06 06:25:55 Functions: 96.9 % 64 62

            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
        

Generated by: LCOV version 2.1