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 % 184 180 4
Test Date: 2026-07-17 09:08:41 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       11328 : writer::
      33                 : suspend(state st)
      34                 : {
      35           11328 :     st_.push(st);
      36           11327 :     return false;
      37                 : }
      38                 : 
      39                 : template<class U, class T>
      40                 : bool
      41           11947 : writer::
      42                 : suspend(state st, U u, T const* pt)
      43                 : {
      44           11947 :     st_.push(pt);
      45           11946 :     st_.push(u);
      46           11946 :     st_.push(st);
      47           11946 :     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 :         w.buf_[2] = false;
     199              91 :         return write_string(w, ss0);
     200                 :     }
     201                 : 
     202             112 :     return resume_string(w, ss0);
     203                 : }
     204                 : 
     205                 : template<class T, bool StackEmpty>
     206                 : BOOST_FORCEINLINE
     207                 : bool
     208                 : write_impl(sequence_conversion_tag, writer& w, stream& ss0)
     209                 : {
     210                 :     using It = iterator_type<T const>;
     211                 :     using Elem = value_type<T>;
     212                 : 
     213                 :     T const* pt;
     214            6125 :     local_stream ss(ss0);
     215              37 :     It it;
     216              17 :     It end;
     217                 : #if defined(_MSC_VER)
     218                 : # pragma warning( push )
     219                 : # pragma warning( disable : 4127 )
     220                 : #endif
     221            2684 :     if(StackEmpty || w.st_.empty())
     222                 :     {
     223                 : #if defined(_MSC_VER)
     224                 : # pragma warning( pop )
     225                 : #endif
     226            3441 :         BOOST_ASSERT( w.p_ );
     227            3441 :         pt = reinterpret_cast<T const*>(w.p_);
     228            3441 :         it = std::begin(*pt);
     229            6882 :         end = std::end(*pt);
     230                 :     }
     231                 :     else
     232                 :     {
     233                 :         writer::state st;
     234            2684 :         w.st_.pop(st);
     235            2684 :         w.st_.pop(it);
     236            2684 :         w.st_.pop(pt);
     237            2684 :         end = std::end(*pt);
     238            2684 :         switch(st)
     239                 :         {
     240              70 :         default:
     241              70 :         case writer::state::arr1: goto do_arr1;
     242            2338 :         case writer::state::arr2: goto do_arr2;
     243              42 :         case writer::state::arr3: goto do_arr3;
     244             234 :         case writer::state::arr4: goto do_arr4;
     245                 :             break;
     246                 :         }
     247                 :     }
     248            3511 : do_arr1:
     249            3511 :     if(BOOST_JSON_LIKELY(ss))
     250            3441 :         ss.append('[');
     251                 :     else
     252              70 :         return w.suspend(writer::state::arr1, it, pt);
     253            3441 :     if(it == end)
     254             507 :         goto do_arr4;
     255                 :     for(;;)
     256                 :     {
     257            4102 :         w.p_ = std::addressof(*it);
     258            6440 : do_arr2:
     259            6440 :         if( !write_impl<Elem, StackEmpty>(w, ss) )
     260            2339 :             return w.suspend(writer::state::arr2, it, pt);
     261            4101 :         if(BOOST_JSON_UNLIKELY( ++it == end ))
     262            2933 :             break;
     263            1168 : do_arr3:
     264            1210 :         if(BOOST_JSON_LIKELY(ss))
     265            1168 :             ss.append(',');
     266                 :         else
     267              42 :             return w.suspend(writer::state::arr3, it, pt);
     268                 :     }
     269            3674 : do_arr4:
     270            3674 :     if(BOOST_JSON_LIKELY(ss))
     271            3440 :         ss.append(']');
     272                 :     else
     273             234 :         return w.suspend(writer::state::arr4, it, pt);
     274            3440 :     return true;
     275            6125 : }
     276                 : 
     277                 : template<class T, bool StackEmpty>
     278                 : BOOST_FORCEINLINE
     279                 : bool
     280                 : write_impl(map_like_conversion_tag, writer& w, stream& ss0)
     281                 : {
     282                 :     using It = iterator_type<T const>;
     283                 :     using Mapped = mapped_type<T>;
     284                 : 
     285                 :     T const* pt;
     286           27361 :     local_stream ss(ss0);
     287              96 :     It it;
     288              96 :     It end;
     289                 : #if defined(_MSC_VER)
     290                 : # pragma warning( push )
     291                 : # pragma warning( disable : 4127 )
     292                 : #endif
     293            9164 :     if(StackEmpty || w.st_.empty())
     294                 : #if defined(_MSC_VER)
     295                 : # pragma warning( pop )
     296                 : #endif
     297                 :     {
     298           18197 :         BOOST_ASSERT( w.p_ );
     299           18197 :         pt = reinterpret_cast<T const*>(w.p_);
     300           18197 :         it = std::begin(*pt);
     301           36394 :         end = std::end(*pt);
     302                 :     }
     303                 :     else
     304                 :     {
     305                 :         writer::state st;
     306            9164 :         w.st_.pop(st);
     307            9164 :         w.st_.pop(it);
     308            9164 :         w.st_.pop(pt);
     309            9164 :         end = std::end(*pt);
     310            9164 :         switch(st)
     311                 :         {
     312              12 :         default:
     313              12 :         case writer::state::obj1: goto do_obj1;
     314             308 :         case writer::state::obj2: goto do_obj2;
     315              54 :         case writer::state::obj3: goto do_obj3;
     316            8724 :         case writer::state::obj4: goto do_obj4;
     317              18 :         case writer::state::obj5: goto do_obj5;
     318              48 :         case writer::state::obj6: goto do_obj6;
     319                 :             break;
     320                 :         }
     321                 :     }
     322           18209 : do_obj1:
     323           18209 :     if(BOOST_JSON_LIKELY( ss ))
     324           18197 :         ss.append('{');
     325                 :     else
     326              12 :         return w.suspend(writer::state::obj1, it, pt);
     327           18197 :     if(BOOST_JSON_UNLIKELY( it == end ))
     328             563 :         goto do_obj6;
     329            2156 :     for(;;)
     330                 :     {
     331                 :         {
     332                 :             using std::get;
     333           19790 :             string_view const sv = get<0>(*it);
     334           19790 :             w.cs0_ = { sv.data(), sv.size() };
     335           19790 :             w.buf_[2] = false;
     336                 :         }
     337                 :         if( true )
     338                 :         {
     339           19790 :             if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
     340             181 :                 return w.suspend(writer::state::obj2, it, pt);
     341                 :         }
     342                 :         else
     343                 :         {
     344             308 : do_obj2:
     345             308 :             if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
     346             127 :                 return w.suspend(writer::state::obj2, it, pt);
     347                 :         }
     348             181 : do_obj3:
     349           19844 :         if(BOOST_JSON_LIKELY(ss))
     350           19790 :             ss.append(':');
     351                 :         else
     352              54 :             return w.suspend(writer::state::obj3, it, pt);
     353           28514 : do_obj4:
     354                 :         {
     355                 :             using std::get;
     356           28514 :             w.p_ = std::addressof( get<1>(*it) );
     357                 :         }
     358           28514 :         if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
     359            8724 :             return w.suspend(writer::state::obj4, it, pt);
     360           19790 :         ++it;
     361           19790 :         if(BOOST_JSON_UNLIKELY(it == end))
     362           17634 :             break;
     363            2156 : do_obj5:
     364            2174 :         if(BOOST_JSON_LIKELY(ss))
     365            2156 :             ss.append(',');
     366                 :         else
     367              18 :             return w.suspend(writer::state::obj5, it, pt);
     368                 :     }
     369           18245 : do_obj6:
     370           18245 :     if(BOOST_JSON_LIKELY( ss ))
     371                 :     {
     372           18197 :         ss.append('}');
     373           18197 :         return true;
     374                 :     }
     375              48 :     return w.suspend(writer::state::obj6, it, pt);
     376           27361 : }
     377                 : 
     378                 : template< class T, bool StackEmpty >
     379                 : struct serialize_tuple_elem_helper
     380                 : {
     381                 :     writer& w;
     382                 :     stream& ss;
     383                 :     T const* pt;
     384                 : 
     385                 :     template< std::size_t I >
     386                 :     bool
     387             258 :     operator()( std::integral_constant<std::size_t, I> ) const
     388                 :     {
     389                 :         using std::get;
     390             258 :         w.p_ = std::addressof( get<I>(*pt) );
     391                 : 
     392                 :         using Elem = tuple_element_t<I, T>;
     393             258 :         return write_impl<Elem, StackEmpty>(w, ss);
     394                 :     }
     395                 : };
     396                 : 
     397                 : template<class T, bool StackEmpty>
     398                 : BOOST_FORCEINLINE
     399                 : bool
     400                 : write_impl(tuple_conversion_tag, writer& w, stream& ss0)
     401                 : {
     402                 :     T const* pt;
     403             174 :     local_stream ss(ss0);
     404                 :     std::size_t cur;
     405              64 :     constexpr std::size_t N = std::tuple_size<T>::value;
     406                 : #if defined(_MSC_VER)
     407                 : # pragma warning( push )
     408                 : # pragma warning( disable : 4127 )
     409                 : #endif
     410             110 :     if(StackEmpty || w.st_.empty())
     411                 :     {
     412                 : #if defined(_MSC_VER)
     413                 : # pragma warning( pop )
     414                 : #endif
     415              76 :         BOOST_ASSERT( w.p_ );
     416              76 :         pt = reinterpret_cast<T const*>(w.p_);
     417              76 :         cur = 0;
     418                 :     }
     419                 :     else
     420                 :     {
     421                 :         writer::state st;
     422              98 :         w.st_.pop(st);
     423              98 :         w.st_.pop(cur);
     424              98 :         w.st_.pop(pt);
     425              98 :         switch(st)
     426                 :         {
     427               2 :         default:
     428               2 :         case writer::state::arr1: goto do_arr1;
     429              82 :         case writer::state::arr2: goto do_arr2;
     430               8 :         case writer::state::arr3: goto do_arr3;
     431               6 :         case writer::state::arr4: goto do_arr4;
     432                 :             break;
     433                 :         }
     434                 :     }
     435              78 : do_arr1:
     436              78 :     if(BOOST_JSON_LIKELY(ss))
     437              76 :         ss.append('[');
     438                 :     else
     439               2 :         return w.suspend(writer::state::arr1, cur, pt);
     440             100 :     for(;;)
     441                 :     {
     442             258 : do_arr2:
     443                 :         {
     444             258 :             bool const stop = !mp11::mp_with_index<N>(
     445                 :                 cur,
     446                 :                 serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt});
     447             258 :             if(BOOST_JSON_UNLIKELY( stop ))
     448              82 :                 return w.suspend(writer::state::arr2, cur, pt);
     449                 :         }
     450             176 :         if(BOOST_JSON_UNLIKELY( ++cur == N ))
     451              76 :             break;
     452             100 : do_arr3:
     453             108 :         if(BOOST_JSON_LIKELY(ss))
     454             100 :             ss.append(',');
     455                 :         else
     456               8 :             return w.suspend(writer::state::arr3, cur, pt);
     457                 :     }
     458              82 : do_arr4:
     459              82 :     if(BOOST_JSON_LIKELY(ss))
     460              76 :         ss.append(']');
     461                 :     else
     462               6 :         return w.suspend(writer::state::arr4, cur, pt);
     463              76 :     return true;
     464             174 : }
     465                 : 
     466                 : template< class T, bool StackEmpty >
     467                 : struct serialize_struct_elem_helper
     468                 : {
     469                 :     static_assert(
     470                 :         uniquely_named_members<T>::value,
     471                 :         "The type has several described members with the same name.");
     472                 : 
     473                 :     writer& w;
     474                 :     local_stream& ss;
     475                 :     T const* pt;
     476                 :     writer::state st;
     477                 : 
     478                 :     template< std::size_t I >
     479                 :     writer::state
     480                 :     operator()( std::integral_constant<std::size_t, I> ) const
     481                 :     {
     482                 :         using Ds = described_members<T>;
     483                 :         using D = mp11::mp_at_c<Ds, I>;
     484                 :         using M = described_member_t<T, D>;
     485                 : 
     486                 :         switch(st)
     487                 :         {
     488                 :         case writer::state::obj2: goto do_obj2;
     489                 :         case writer::state::obj3: goto do_obj3;
     490                 :         case writer::state::obj4: goto do_obj4;
     491                 :         default: break;
     492                 :         }
     493                 : 
     494                 :         {
     495                 :             string_view const sv = D::name;
     496                 :             w.cs0_ = { sv.data(), sv.size() };
     497                 :             w.buf_[2] = false;
     498                 :         }
     499                 :         if( true )
     500                 :         {
     501                 :             if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
     502                 :                 return writer::state::obj2;
     503                 :         }
     504                 :         else
     505                 :         {
     506                 : do_obj2:
     507                 :             if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
     508                 :                 return writer::state::obj2;
     509                 :         }
     510                 : do_obj3:
     511                 :         if(BOOST_JSON_LIKELY(ss))
     512                 :             ss.append(':');
     513                 :         else
     514                 :             return writer::state::obj3;
     515                 : do_obj4:
     516                 :         w.p_ = std::addressof( pt->* D::pointer );
     517                 :         if(BOOST_JSON_UNLIKELY((
     518                 :                 !write_impl<M, StackEmpty>(w, ss) )))
     519                 :             return writer::state::obj4;
     520                 : 
     521                 :         return writer::state{};
     522                 :     }
     523                 : };
     524                 : 
     525                 : template<class T, bool StackEmpty>
     526                 : BOOST_FORCEINLINE
     527                 : bool
     528                 : write_impl(described_class_conversion_tag, writer& w, stream& ss0)
     529                 : {
     530                 :     using Ds = described_members<T>;
     531                 : 
     532                 :     T const* pt;
     533                 :     local_stream ss(ss0);
     534                 :     std::size_t cur;
     535                 :     constexpr std::size_t N = mp11::mp_size<Ds>::value;
     536                 :     writer::state st;
     537                 : #if defined(_MSC_VER)
     538                 : # pragma warning( push )
     539                 : # pragma warning( disable : 4127 )
     540                 : #endif
     541                 :     if(StackEmpty || w.st_.empty())
     542                 : #if defined(_MSC_VER)
     543                 : # pragma warning( pop )
     544                 : #endif
     545                 :     {
     546                 :         BOOST_ASSERT( w.p_ );
     547                 :         pt = reinterpret_cast<T const*>(w.p_);
     548                 :         cur = 0;
     549                 :     }
     550                 :     else
     551                 :     {
     552                 :         w.st_.pop(st);
     553                 :         w.st_.pop(cur);
     554                 :         w.st_.pop(pt);
     555                 :         switch(st)
     556                 :         {
     557                 :         default:
     558                 :         case writer::state::obj1: goto do_obj1;
     559                 :         case writer::state::obj2: // fall through
     560                 :         case writer::state::obj3: // fall through
     561                 :         case writer::state::obj4: goto do_obj2;
     562                 :         case writer::state::obj5: goto do_obj5;
     563                 :         case writer::state::obj6: goto do_obj6;
     564                 :             break;
     565                 :         }
     566                 :     }
     567                 : do_obj1:
     568                 :     if(BOOST_JSON_LIKELY( ss ))
     569                 :         ss.append('{');
     570                 :     else
     571                 :         return w.suspend(writer::state::obj1, cur, pt);
     572                 :     if(BOOST_JSON_UNLIKELY( cur == N ))
     573                 :         goto do_obj6;
     574                 :     for(;;)
     575                 :     {
     576                 :         st = {};
     577                 : do_obj2:
     578                 :         st = mp11::mp_with_index<N>(
     579                 :             cur,
     580                 :             serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st});
     581                 :         if(BOOST_JSON_UNLIKELY( st != writer::state{} ))
     582                 :             return w.suspend(st, cur, pt);
     583                 :         ++cur;
     584                 :         if(BOOST_JSON_UNLIKELY(cur == N))
     585                 :             break;
     586                 : do_obj5:
     587                 :         if(BOOST_JSON_LIKELY(ss))
     588                 :             ss.append(',');
     589                 :         else
     590                 :             return w.suspend(writer::state::obj5, cur, pt);
     591                 :     }
     592                 : do_obj6:
     593                 :     if(BOOST_JSON_LIKELY( ss ))
     594                 :     {
     595                 :         ss.append('}');
     596                 :         return true;
     597                 :     }
     598                 :     return w.suspend(writer::state::obj6, cur, pt);
     599                 : }
     600                 : 
     601                 : template<class T, bool StackEmpty>
     602                 : BOOST_FORCEINLINE
     603                 : bool
     604                 : write_impl(described_enum_conversion_tag, writer& w, stream& ss)
     605                 : {
     606                 : #ifdef BOOST_DESCRIBE_CXX14
     607                 :     using Integer = typename std::underlying_type<T>::type;
     608                 : 
     609                 : #if defined(_MSC_VER)
     610                 : # pragma warning( push )
     611                 : # pragma warning( disable : 4127 )
     612                 : #endif
     613                 :     if(StackEmpty || w.st_.empty())
     614                 : #if defined(_MSC_VER)
     615                 : # pragma warning( pop )
     616                 : #endif
     617                 :     {
     618                 :         BOOST_ASSERT( w.p_ );
     619                 :         T const* pt = reinterpret_cast<T const*>(w.p_);
     620                 :         char const* const name = describe::enum_to_string(*pt, nullptr);
     621                 :         if( name )
     622                 :         {
     623                 :             string_view const sv = name;
     624                 :             w.cs0_ = { sv.data(), sv.size() };
     625                 :             w.buf_[2] = false;
     626                 :             return write_string(w, ss);
     627                 :         }
     628                 :         else
     629                 :         {
     630                 :             Integer n = static_cast<Integer>(*pt);
     631                 :             w.p_ = &n;
     632                 :             return write_impl<Integer, true>(w, ss);
     633                 :         }
     634                 :     }
     635                 :     else
     636                 :     {
     637                 :         writer::state st;
     638                 :         w.st_.peek(st);
     639                 :         if( st == writer::state::lit )
     640                 :             return write_impl<Integer, false>(w, ss);
     641                 :         else
     642                 :             return resume_string(w, ss);
     643                 :     }
     644                 : #else // BOOST_DESCRIBE_CXX14
     645                 :     (void)w;
     646                 :     (void)ss;
     647                 :     static_assert(
     648                 :         !std::is_same<T, T>::value,
     649                 :         "described enums require C++14 support");
     650                 :     return false;
     651                 : #endif // BOOST_DESCRIBE_CXX14
     652                 : }
     653                 : 
     654                 : template< class T, bool StackEmpty >
     655                 : struct serialize_variant_elem_helper
     656                 : {
     657                 :     writer& w;
     658                 :     stream& ss;
     659                 : 
     660                 :     template<class Elem>
     661                 :     bool
     662                 :     operator()(Elem const& x) const
     663                 :     {
     664                 :         w.p_ = std::addressof(x);
     665                 :         return write_impl<Elem, true>(w, ss);
     666                 :     }
     667                 : };
     668                 : 
     669                 : template< class T >
     670                 : struct serialize_variant_elem_helper<T, false>
     671                 : {
     672                 :     writer& w;
     673                 :     stream& ss;
     674                 : 
     675                 :     template< std::size_t I >
     676                 :     bool
     677                 :     operator()( std::integral_constant<std::size_t, I> ) const
     678                 :     {
     679                 :         using std::get;
     680                 :         using Elem = remove_cvref<decltype(get<I>(
     681                 :             std::declval<T const&>() ))>;
     682                 :         return write_impl<Elem, false>(w, ss);
     683                 :     }
     684                 : };
     685                 : 
     686                 : template<class T, bool StackEmpty>
     687                 : BOOST_FORCEINLINE
     688                 : bool
     689                 : write_impl(variant_conversion_tag, writer& w, stream& ss)
     690                 : {
     691                 :     T const* pt;
     692                 : 
     693                 :     using Index = remove_cvref<decltype( pt->index() )>;
     694                 : 
     695                 : #if defined(_MSC_VER)
     696                 : # pragma warning( push )
     697                 : # pragma warning( disable : 4127 )
     698                 : #endif
     699                 :     if(StackEmpty || w.st_.empty())
     700                 : #if defined(_MSC_VER)
     701                 : # pragma warning( pop )
     702                 : #endif
     703                 :     {
     704                 :         BOOST_ASSERT( w.p_ );
     705                 :         pt = reinterpret_cast<T const*>(w.p_);
     706                 :         if(BOOST_JSON_LIKELY((
     707                 :                 visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt))))
     708                 :             return true;
     709                 : 
     710                 :         Index const ix = pt->index();
     711                 :         w.st_.push(ix);
     712                 :         return false;
     713                 :     }
     714                 :     else
     715                 :     {
     716                 :         Index ix;
     717                 :         w.st_.pop(ix);
     718                 : 
     719                 :         constexpr std::size_t N = mp11::mp_size<T>::value;
     720                 :         if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>(
     721                 :                 ix,
     722                 :                 serialize_variant_elem_helper<T, false>{w, ss}))))
     723                 :             return true;
     724                 : 
     725                 :         w.st_.push(ix);
     726                 :         return false;
     727                 :     }
     728                 : }
     729                 : 
     730                 : template<class T, bool StackEmpty>
     731                 : BOOST_FORCEINLINE
     732                 : bool
     733                 : write_impl(optional_conversion_tag, writer& w, stream& ss)
     734                 : {
     735                 :     using Elem = value_result_type<T>;
     736                 : 
     737                 :     bool done;
     738                 :     bool has_value;
     739                 : 
     740                 : #if defined(_MSC_VER)
     741                 : # pragma warning( push )
     742                 : # pragma warning( disable : 4127 )
     743                 : #endif
     744                 :     if(StackEmpty || w.st_.empty())
     745                 : #if defined(_MSC_VER)
     746                 : # pragma warning( pop )
     747                 : #endif
     748                 :     {
     749                 :         BOOST_ASSERT( w.p_ );
     750                 :         T const* pt = reinterpret_cast<T const*>(w.p_);
     751                 :         has_value = static_cast<bool>(*pt);
     752                 :         if( has_value )
     753                 :         {
     754                 :             w.p_ = std::addressof( *(*pt) );
     755                 :             done = write_impl<Elem, true>(w, ss);
     756                 :         }
     757                 :         else
     758                 :         {
     759                 :             w.p_ = nullptr;
     760                 :             done = write_impl<std::nullptr_t, true>(w, ss);;
     761                 :         }
     762                 :     }
     763                 :     else
     764                 :     {
     765                 :         w.st_.pop(has_value);
     766                 : 
     767                 :         if( has_value )
     768                 :             done = write_impl<Elem, false>(w, ss);
     769                 :         else
     770                 :             done = write_impl<std::nullptr_t, false>(w, ss);
     771                 :     }
     772                 : 
     773                 :     if(BOOST_JSON_UNLIKELY( !done ))
     774                 :         w.st_.push(has_value);
     775                 : 
     776                 :     return done;
     777                 : }
     778                 : 
     779                 : template<class T, bool StackEmpty>
     780                 : BOOST_FORCEINLINE
     781                 : bool
     782                 : write_impl(path_conversion_tag, writer& w, stream& ss)
     783                 : {
     784                 :     w.buf_[2] = false;
     785                 : #if defined(_MSC_VER)
     786                 : # pragma warning( push )
     787                 : # pragma warning( disable : 4127 )
     788                 : #endif
     789                 :     if(StackEmpty || w.st_.empty())
     790                 : #if defined(_MSC_VER)
     791                 : # pragma warning( pop )
     792                 : #endif
     793                 :     {
     794                 :         BOOST_ASSERT( w.p_ );
     795                 :         T const* pt = reinterpret_cast<T const*>(w.p_);
     796                 : 
     797                 :         std::string const s = pt->generic_string();
     798                 :         w.cs0_ = { s.data(), s.size() };
     799                 :         if(BOOST_JSON_LIKELY( write_string(w, ss) ))
     800                 :             return true;
     801                 : 
     802                 :         std::size_t const used = w.cs0_.used( s.data() );
     803                 :         w.st_.push( used );
     804                 :         w.st_.push( std::move(s) );
     805                 :         return false;
     806                 :     }
     807                 :     else
     808                 :     {
     809                 :         std::string s;
     810                 :         std::size_t used;
     811                 :         w.st_.pop( s );
     812                 :         w.st_.pop( used );
     813                 : 
     814                 :         w.cs0_ = { s.data(), s.size() };
     815                 :         w.cs0_.skip(used);
     816                 : 
     817                 :         if(BOOST_JSON_LIKELY( resume_string(w, ss) ))
     818                 :             return true;
     819                 : 
     820                 :         used = w.cs0_.used( s.data() );
     821                 :         w.st_.push( used );
     822                 :         w.st_.push( std::move(s) );
     823                 :         return false;
     824                 :     }
     825                 : }
     826                 : 
     827                 : template<class T, bool StackEmpty>
     828                 : bool
     829           35744 : write_impl(writer& w, stream& ss)
     830                 : {
     831                 :     using cat = detail::generic_conversion_category<T>;
     832           35743 :     return write_impl<T, StackEmpty>( cat(), w, ss );
     833                 : }
     834                 : 
     835                 : } // namespace detail
     836                 : 
     837                 : template<class T>
     838                 : void
     839             219 : serializer::reset(T const* p) noexcept
     840                 : {
     841                 :     BOOST_CORE_STATIC_ASSERT( !std::is_pointer<T>::value );
     842                 :     BOOST_CORE_STATIC_ASSERT( std::is_object<T>::value );
     843                 : 
     844             219 :     p_ = p;
     845             219 :     fn0_ = &detail::write_impl<T, true>;
     846             219 :     fn1_ = &detail::write_impl<T, false>;
     847             219 :     st_.clear();
     848             219 :     done_ = false;
     849             219 : }
     850                 : 
     851                 : } // namespace json
     852                 : } // namespace boost
     853                 : 
     854                 : #endif // BOOST_JSON_IMPL_SERIALIZER_HPP
        

Generated by: LCOV version 2.3