LCOV - code coverage report
Current view: top level - json/impl - serializer.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 97.8 % 182 178 4
Test Date: 2026-02-25 20:43:10 Functions: 96.9 % 64 62 2

           TLA  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 HIT       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 MIS           0 :     BOOST_ASSERT( w.p_ );
      77 HIT          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 MIS           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 HIT          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 MIS           0 :         string_view const sv = *reinterpret_cast<T const*>(w.p_);
     197 HIT          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.3