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: 2025-12-23 17:20:51 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/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
        

Generated by: LCOV version 2.1