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:38:56 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         6078 :     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         3422 :         BOOST_ASSERT( w.p_ );
     225         3422 :         pt = reinterpret_cast<T const*>(w.p_);
     226         3422 :         it = std::begin(*pt);
     227         6844 :         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         3492 : do_arr1:
     247         3492 :     if(BOOST_JSON_LIKELY(ss))
     248         3422 :         ss.append('[');
     249              :     else
     250           70 :         return w.suspend(writer::state::arr1, it, pt);
     251         3422 :     if(it == end)
     252          507 :         goto do_arr4;
     253              :     for(;;)
     254              :     {
     255         4064 :         w.p_ = std::addressof(*it);
     256         6378 : do_arr2:
     257         6378 :         if( !write_impl<Elem, StackEmpty>(w, ss) )
     258         2315 :             return w.suspend(writer::state::arr2, it, pt);
     259         4063 :         if(BOOST_JSON_UNLIKELY( ++it == end ))
     260         2914 :             break;
     261         1149 : do_arr3:
     262         1189 :         if(BOOST_JSON_LIKELY(ss))
     263         1149 :             ss.append(',');
     264              :         else
     265           40 :             return w.suspend(writer::state::arr3, it, pt);
     266              :     }
     267         3653 : do_arr4:
     268         3653 :     if(BOOST_JSON_LIKELY(ss))
     269         3421 :         ss.append(']');
     270              :     else
     271          232 :         return w.suspend(writer::state::arr4, it, pt);
     272         3421 :     return true;
     273         6078 : }
     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        27290 :     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        18170 :         BOOST_ASSERT( w.p_ );
     297        18170 :         pt = reinterpret_cast<T const*>(w.p_);
     298        18170 :         it = std::begin(*pt);
     299        36340 :         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        18182 : do_obj1:
     321        18182 :     if(BOOST_JSON_LIKELY( ss ))
     322        18170 :         ss.append('{');
     323              :     else
     324           12 :         return w.suspend(writer::state::obj1, it, pt);
     325        18170 :     if(BOOST_JSON_UNLIKELY( it == end ))
     326          563 :         goto do_obj6;
     327         2129 :     for(;;)
     328              :     {
     329              :         {
     330              :             using std::get;
     331        19736 :             string_view const sv = get<0>(*it);
     332        19736 :             w.cs0_ = { sv.data(), sv.size() };
     333              :         }
     334              :         if( true )
     335              :         {
     336        19736 :             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        19786 :         if(BOOST_JSON_LIKELY(ss))
     347        19736 :             ss.append(':');
     348              :         else
     349           50 :             return w.suspend(writer::state::obj3, it, pt);
     350        28436 : do_obj4:
     351              :         {
     352              :             using std::get;
     353        28436 :             w.p_ = std::addressof( get<1>(*it) );
     354              :         }
     355        28436 :         if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
     356         8700 :             return w.suspend(writer::state::obj4, it, pt);
     357        19736 :         ++it;
     358        19736 :         if(BOOST_JSON_UNLIKELY(it == end))
     359        17607 :             break;
     360         2129 : do_obj5:
     361         2145 :         if(BOOST_JSON_LIKELY(ss))
     362         2129 :             ss.append(',');
     363              :         else
     364           16 :             return w.suspend(writer::state::obj5, it, pt);
     365              :     }
     366        18216 : do_obj6:
     367        18216 :     if(BOOST_JSON_LIKELY( ss ))
     368              :     {
     369        18170 :         ss.append('}');
     370        18170 :         return true;
     371              :     }
     372           46 :     return w.suspend(writer::state::obj6, it, pt);
     373        27290 : }
     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              :     static_assert(
     467              :         uniquely_named_members<T>::value,
     468              :         "The type has several described members with the same name.");
     469              : 
     470              :     writer& w;
     471              :     local_stream& ss;
     472              :     T const* pt;
     473              :     writer::state st;
     474              : 
     475              :     template< std::size_t I >
     476              :     writer::state
     477              :     operator()( std::integral_constant<std::size_t, I> ) const
     478              :     {
     479              :         using Ds = described_members<T>;
     480              :         using D = mp11::mp_at_c<Ds, I>;
     481              :         using M = described_member_t<T, D>;
     482              : 
     483              :         switch(st)
     484              :         {
     485              :         case writer::state::obj2: goto do_obj2;
     486              :         case writer::state::obj3: goto do_obj3;
     487              :         case writer::state::obj4: goto do_obj4;
     488              :         default: break;
     489              :         }
     490              : 
     491              :         {
     492              :             string_view const sv = D::name;
     493              :             w.cs0_ = { sv.data(), sv.size() };
     494              :         }
     495              :         if( true )
     496              :         {
     497              :             if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
     498              :                 return writer::state::obj2;
     499              :         }
     500              :         else
     501              :         {
     502              : do_obj2:
     503              :             if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
     504              :                 return writer::state::obj2;
     505              :         }
     506              : do_obj3:
     507              :         if(BOOST_JSON_LIKELY(ss))
     508              :             ss.append(':');
     509              :         else
     510              :             return writer::state::obj3;
     511              : do_obj4:
     512              :         w.p_ = std::addressof( pt->* D::pointer );
     513              :         if(BOOST_JSON_UNLIKELY((
     514              :                 !write_impl<M, StackEmpty>(w, ss) )))
     515              :             return writer::state::obj4;
     516              : 
     517              :         return writer::state{};
     518              :     }
     519              : };
     520              : 
     521              : template<class T, bool StackEmpty>
     522              : BOOST_FORCEINLINE
     523              : bool
     524              : write_impl(described_class_conversion_tag, writer& w, stream& ss0)
     525              : {
     526              :     using Ds = described_members<T>;
     527              : 
     528              :     T const* pt;
     529              :     local_stream ss(ss0);
     530              :     std::size_t cur;
     531              :     constexpr std::size_t N = mp11::mp_size<Ds>::value;
     532              :     writer::state st;
     533              : #if defined(_MSC_VER)
     534              : # pragma warning( push )
     535              : # pragma warning( disable : 4127 )
     536              : #endif
     537              :     if(StackEmpty || w.st_.empty())
     538              : #if defined(_MSC_VER)
     539              : # pragma warning( pop )
     540              : #endif
     541              :     {
     542              :         BOOST_ASSERT( w.p_ );
     543              :         pt = reinterpret_cast<T const*>(w.p_);
     544              :         cur = 0;
     545              :     }
     546              :     else
     547              :     {
     548              :         w.st_.pop(st);
     549              :         w.st_.pop(cur);
     550              :         w.st_.pop(pt);
     551              :         switch(st)
     552              :         {
     553              :         default:
     554              :         case writer::state::obj1: goto do_obj1;
     555              :         case writer::state::obj2: // fall through
     556              :         case writer::state::obj3: // fall through
     557              :         case writer::state::obj4: goto do_obj2;
     558              :         case writer::state::obj5: goto do_obj5;
     559              :         case writer::state::obj6: goto do_obj6;
     560              :             break;
     561              :         }
     562              :     }
     563              : do_obj1:
     564              :     if(BOOST_JSON_LIKELY( ss ))
     565              :         ss.append('{');
     566              :     else
     567              :         return w.suspend(writer::state::obj1, cur, pt);
     568              :     if(BOOST_JSON_UNLIKELY( cur == N ))
     569              :         goto do_obj6;
     570              :     for(;;)
     571              :     {
     572              :         st = {};
     573              : do_obj2:
     574              :         st = mp11::mp_with_index<N>(
     575              :             cur,
     576              :             serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st});
     577              :         if(BOOST_JSON_UNLIKELY( st != writer::state{} ))
     578              :             return w.suspend(st, cur, pt);
     579              :         ++cur;
     580              :         if(BOOST_JSON_UNLIKELY(cur == N))
     581              :             break;
     582              : do_obj5:
     583              :         if(BOOST_JSON_LIKELY(ss))
     584              :             ss.append(',');
     585              :         else
     586              :             return w.suspend(writer::state::obj5, cur, pt);
     587              :     }
     588              : do_obj6:
     589              :     if(BOOST_JSON_LIKELY( ss ))
     590              :     {
     591              :         ss.append('}');
     592              :         return true;
     593              :     }
     594              :     return w.suspend(writer::state::obj6, cur, pt);
     595              : }
     596              : 
     597              : template<class T, bool StackEmpty>
     598              : BOOST_FORCEINLINE
     599              : bool
     600              : write_impl(described_enum_conversion_tag, writer& w, stream& ss)
     601              : {
     602              : #ifdef BOOST_DESCRIBE_CXX14
     603              :     using Integer = typename std::underlying_type<T>::type;
     604              : 
     605              : #if defined(_MSC_VER)
     606              : # pragma warning( push )
     607              : # pragma warning( disable : 4127 )
     608              : #endif
     609              :     if(StackEmpty || w.st_.empty())
     610              : #if defined(_MSC_VER)
     611              : # pragma warning( pop )
     612              : #endif
     613              :     {
     614              :         BOOST_ASSERT( w.p_ );
     615              :         T const* pt = reinterpret_cast<T const*>(w.p_);
     616              :         char const* const name = describe::enum_to_string(*pt, nullptr);
     617              :         if( name )
     618              :         {
     619              :             string_view const sv = name;
     620              :             w.cs0_ = { sv.data(), sv.size() };
     621              :             return write_string(w, ss);
     622              :         }
     623              :         else
     624              :         {
     625              :             Integer n = static_cast<Integer>(*pt);
     626              :             w.p_ = &n;
     627              :             return write_impl<Integer, true>(w, ss);
     628              :         }
     629              :     }
     630              :     else
     631              :     {
     632              :         writer::state st;
     633              :         w.st_.peek(st);
     634              :         if( st == writer::state::lit )
     635              :             return write_impl<Integer, false>(w, ss);
     636              :         else
     637              :             return resume_string(w, ss);
     638              :     }
     639              : #else // BOOST_DESCRIBE_CXX14
     640              :     (void)w;
     641              :     (void)ss;
     642              :     static_assert(
     643              :         !std::is_same<T, T>::value,
     644              :         "described enums require C++14 support");
     645              :     return false;
     646              : #endif // BOOST_DESCRIBE_CXX14
     647              : }
     648              : 
     649              : template< class T, bool StackEmpty >
     650              : struct serialize_variant_elem_helper
     651              : {
     652              :     writer& w;
     653              :     stream& ss;
     654              : 
     655              :     template<class Elem>
     656              :     bool
     657              :     operator()(Elem const& x) const
     658              :     {
     659              :         w.p_ = std::addressof(x);
     660              :         return write_impl<Elem, true>(w, ss);
     661              :     }
     662              : };
     663              : 
     664              : template< class T >
     665              : struct serialize_variant_elem_helper<T, false>
     666              : {
     667              :     writer& w;
     668              :     stream& ss;
     669              : 
     670              :     template< std::size_t I >
     671              :     bool
     672              :     operator()( std::integral_constant<std::size_t, I> ) const
     673              :     {
     674              :         using std::get;
     675              :         using Elem = remove_cvref<decltype(get<I>(
     676              :             std::declval<T const&>() ))>;
     677              :         return write_impl<Elem, false>(w, ss);
     678              :     }
     679              : };
     680              : 
     681              : template<class T, bool StackEmpty>
     682              : BOOST_FORCEINLINE
     683              : bool
     684              : write_impl(variant_conversion_tag, writer& w, stream& ss)
     685              : {
     686              :     T const* pt;
     687              : 
     688              :     using Index = remove_cvref<decltype( pt->index() )>;
     689              : 
     690              : #if defined(_MSC_VER)
     691              : # pragma warning( push )
     692              : # pragma warning( disable : 4127 )
     693              : #endif
     694              :     if(StackEmpty || w.st_.empty())
     695              : #if defined(_MSC_VER)
     696              : # pragma warning( pop )
     697              : #endif
     698              :     {
     699              :         BOOST_ASSERT( w.p_ );
     700              :         pt = reinterpret_cast<T const*>(w.p_);
     701              :         if(BOOST_JSON_LIKELY((
     702              :                 visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt))))
     703              :             return true;
     704              : 
     705              :         Index const ix = pt->index();
     706              :         w.st_.push(ix);
     707              :         return false;
     708              :     }
     709              :     else
     710              :     {
     711              :         Index ix;
     712              :         w.st_.pop(ix);
     713              : 
     714              :         constexpr std::size_t N = mp11::mp_size<T>::value;
     715              :         if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>(
     716              :                 ix,
     717              :                 serialize_variant_elem_helper<T, false>{w, ss}))))
     718              :             return true;
     719              : 
     720              :         w.st_.push(ix);
     721              :         return false;
     722              :     }
     723              : }
     724              : 
     725              : template<class T, bool StackEmpty>
     726              : BOOST_FORCEINLINE
     727              : bool
     728              : write_impl(optional_conversion_tag, writer& w, stream& ss)
     729              : {
     730              :     using Elem = value_result_type<T>;
     731              : 
     732              :     bool done;
     733              :     bool has_value;
     734              : 
     735              : #if defined(_MSC_VER)
     736              : # pragma warning( push )
     737              : # pragma warning( disable : 4127 )
     738              : #endif
     739              :     if(StackEmpty || w.st_.empty())
     740              : #if defined(_MSC_VER)
     741              : # pragma warning( pop )
     742              : #endif
     743              :     {
     744              :         BOOST_ASSERT( w.p_ );
     745              :         T const* pt = reinterpret_cast<T const*>(w.p_);
     746              :         has_value = static_cast<bool>(*pt);
     747              :         if( has_value )
     748              :         {
     749              :             w.p_ = std::addressof( *(*pt) );
     750              :             done = write_impl<Elem, true>(w, ss);
     751              :         }
     752              :         else
     753              :         {
     754              :             w.p_ = nullptr;
     755              :             done = write_impl<std::nullptr_t, true>(w, ss);;
     756              :         }
     757              :     }
     758              :     else
     759              :     {
     760              :         w.st_.pop(has_value);
     761              : 
     762              :         if( has_value )
     763              :             done = write_impl<Elem, false>(w, ss);
     764              :         else
     765              :             done = write_impl<std::nullptr_t, false>(w, ss);
     766              :     }
     767              : 
     768              :     if(BOOST_JSON_UNLIKELY( !done ))
     769              :         w.st_.push(has_value);
     770              : 
     771              :     return done;
     772              : }
     773              : 
     774              : template<class T, bool StackEmpty>
     775              : BOOST_FORCEINLINE
     776              : bool
     777              : write_impl(path_conversion_tag, writer& w, stream& ss)
     778              : {
     779              : #if defined(_MSC_VER)
     780              : # pragma warning( push )
     781              : # pragma warning( disable : 4127 )
     782              : #endif
     783              :     if(StackEmpty || w.st_.empty())
     784              : #if defined(_MSC_VER)
     785              : # pragma warning( pop )
     786              : #endif
     787              :     {
     788              :         BOOST_ASSERT( w.p_ );
     789              :         T const* pt = reinterpret_cast<T const*>(w.p_);
     790              : 
     791              :         std::string const s = pt->generic_string();
     792              :         w.cs0_ = { s.data(), s.size() };
     793              :         if(BOOST_JSON_LIKELY( write_string(w, ss) ))
     794              :             return true;
     795              : 
     796              :         std::size_t const used = w.cs0_.used( s.data() );
     797              :         w.st_.push( used );
     798              :         w.st_.push( std::move(s) );
     799              :         return false;
     800              :     }
     801              :     else
     802              :     {
     803              :         std::string s;
     804              :         std::size_t used;
     805              :         w.st_.pop( s );
     806              :         w.st_.pop( used );
     807              : 
     808              :         w.cs0_ = { s.data(), s.size() };
     809              :         w.cs0_.skip(used);
     810              : 
     811              :         if(BOOST_JSON_LIKELY( resume_string(w, ss) ))
     812              :             return true;
     813              : 
     814              :         used = w.cs0_.used( s.data() );
     815              :         w.st_.push( used );
     816              :         w.st_.push( std::move(s) );
     817              :         return false;
     818              :     }
     819              : }
     820              : 
     821              : template<class T, bool StackEmpty>
     822              : bool
     823        35604 : write_impl(writer& w, stream& ss)
     824              : {
     825              :     using cat = detail::generic_conversion_category<T>;
     826        35603 :     return write_impl<T, StackEmpty>( cat(), w, ss );
     827              : }
     828              : 
     829              : } // namespace detail
     830              : 
     831              : template<class T>
     832              : void
     833          219 : serializer::reset(T const* p) noexcept
     834              : {
     835              :     BOOST_STATIC_ASSERT( !std::is_pointer<T>::value );
     836              :     BOOST_STATIC_ASSERT( std::is_object<T>::value );
     837              : 
     838          219 :     p_ = p;
     839          219 :     fn0_ = &detail::write_impl<T, true>;
     840          219 :     fn1_ = &detail::write_impl<T, false>;
     841          219 :     st_.clear();
     842          219 :     done_ = false;
     843          219 : }
     844              : 
     845              : } // namespace json
     846              : } // namespace boost
     847              : 
     848              : #endif // BOOST_JSON_IMPL_SERIALIZER_HPP
        

Generated by: LCOV version 2.1