LCOV - code coverage report
Current view: top level - json/impl - serializer.ipp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 261 261
Test Date: 2026-03-05 09:04:27 Functions: 100.0 % 36 36

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
       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_IPP
      11                 : #define BOOST_JSON_IMPL_SERIALIZER_IPP
      12                 : 
      13                 : #include <boost/json/serializer.hpp>
      14                 : #include <boost/json/detail/format.hpp>
      15                 : #include <boost/json/detail/sse2.hpp>
      16                 : 
      17                 : #ifdef _MSC_VER
      18                 : #pragma warning(push)
      19                 : #pragma warning(disable: 4127) // conditional expression is constant
      20                 : #endif
      21                 : 
      22                 : namespace boost {
      23                 : namespace json {
      24                 : namespace detail {
      25                 : 
      26                 : struct int64_formatter
      27                 : {
      28                 :     std::int64_t i;
      29                 : 
      30                 :     std::size_t
      31 HIT        3189 :     operator()(char* dst) const noexcept
      32                 :     {
      33            3189 :         return format_int64(dst, i);
      34                 :     }
      35                 : };
      36                 : 
      37                 : struct uint64_formatter
      38                 : {
      39                 :     std::uint64_t u;
      40                 : 
      41                 :     std::size_t
      42             425 :     operator()(char* dst) const noexcept
      43                 :     {
      44             425 :         return format_uint64(dst, u);
      45                 :     }
      46                 : };
      47                 : 
      48                 : struct double_formatter
      49                 : {
      50                 :     double d;
      51                 :     bool allow_infinity_and_nan;
      52                 : 
      53                 :     std::size_t
      54             477 :     operator()(char* dst) const noexcept
      55                 :     {
      56             477 :         return format_double(dst, d, allow_infinity_and_nan);
      57                 :     }
      58                 : };
      59                 : 
      60           21250 : writer::
      61                 : writer(
      62                 :     storage_ptr sp,
      63                 :     unsigned char* buf,
      64                 :     std::size_t buf_size,
      65           21250 :     serialize_options const& opts) noexcept
      66           21250 :     : st_(
      67           21250 :         std::move(sp),
      68                 :         buf,
      69                 :         buf_size)
      70           21250 :     , opts_(opts)
      71                 : {
      72                 :     // ensure room for \uXXXX escape plus one
      73                 :     BOOST_STATIC_ASSERT(sizeof(buf_) >= 7);
      74           21250 : }
      75                 : 
      76                 : bool
      77                 : BOOST_FORCEINLINE
      78                 : write_buffer(writer& w, stream& ss0)
      79                 : {
      80            1444 :     local_stream ss(ss0);
      81            2578 :     auto const n = ss.remain();
      82            2578 :     if( n < w.cs0_.remain() )
      83                 :     {
      84            1334 :         ss.append(w.cs0_.data(), n);
      85            1334 :         w.cs0_.skip(n);
      86            1334 :         return w.suspend(writer::state::lit);
      87                 :     }
      88            1244 :     ss.append( w.cs0_.data(), w.cs0_.remain() );
      89            1244 :     return true;
      90            2578 : }
      91                 : 
      92                 : template< class F >
      93                 : bool
      94            4091 : write_buffer(writer& w, stream& ss0, F f)
      95                 : {
      96            4091 :     BOOST_ASSERT( w.st_.empty() );
      97                 : 
      98            4091 :     local_stream ss(ss0);
      99            4091 :     if(BOOST_JSON_LIKELY( ss.remain() >= detail::max_number_chars ))
     100                 :     {
     101            2957 :         ss.advance( f(ss.data()) );
     102            2957 :         return true;
     103                 :     }
     104                 : 
     105            1134 :     w.cs0_ = { w.buf_, f(w.buf_) };
     106            1134 :     return write_buffer(w, ss);
     107            4091 : }
     108                 : 
     109                 : template<literals Lit>
     110                 : bool
     111            4725 : write_literal(writer& w, stream& ss)
     112                 : {
     113            4725 :     constexpr std::size_t index = literal_index(Lit);
     114            4725 :     constexpr char const* literal = literal_strings[index];
     115            4725 :     constexpr std::size_t sz = literal_sizes[index];
     116                 : 
     117            4725 :     std::size_t const n = ss.remain();
     118            4725 :     if(BOOST_JSON_LIKELY( n >= sz ))
     119                 :     {
     120            4613 :         ss.append( literal, sz );
     121            4613 :         return true;
     122                 :     }
     123                 : 
     124             112 :     ss.append(literal, n);
     125                 : 
     126             112 :     w.cs0_ = {literal + n, sz - n};
     127             112 :     return w.suspend(writer::state::lit);
     128                 : }
     129                 : 
     130                 : bool
     131             197 : write_true(writer& w, stream& ss)
     132                 : {
     133             197 :     return write_literal<literals::true_>(w, ss);
     134                 : }
     135                 : 
     136                 : bool
     137             176 : write_false(writer& w, stream& ss)
     138                 : {
     139             176 :     return write_literal<literals::false_>(w, ss);
     140                 : }
     141                 : 
     142                 : bool
     143            4352 : write_null(writer& w, stream& ss)
     144                 : {
     145            4352 :     return write_literal<literals::null>(w, ss);
     146                 : }
     147                 : 
     148                 : bool
     149            3189 : write_int64(writer& w, stream& ss0, std::int64_t i)
     150                 : {
     151            3189 :     return write_buffer( w, ss0, int64_formatter{i} );
     152                 : }
     153                 : 
     154                 : bool
     155             425 : write_uint64(writer& w, stream& ss0, std::uint64_t u)
     156                 : {
     157             425 :     return write_buffer( w, ss0, uint64_formatter{u} );
     158                 : }
     159                 : 
     160                 : bool
     161             477 : write_double(writer& w, stream& ss0, double d)
     162                 : {
     163             954 :     return write_buffer(
     164             477 :         w, ss0, double_formatter{d, w.opts_.allow_infinity_and_nan} );
     165                 : }
     166                 : 
     167                 : bool
     168            1444 : resume_buffer(writer& w, stream& ss0)
     169                 : {
     170            1444 :     BOOST_ASSERT( !w.st_.empty() );
     171                 :     writer::state st;
     172            1444 :     w.st_.pop(st);
     173            1444 :     BOOST_ASSERT(st == writer::state::lit);
     174                 : 
     175            2888 :     return write_buffer(w, ss0);
     176                 : }
     177                 : 
     178                 : template<bool StackEmpty>
     179                 : bool
     180           44303 : do_write_string(writer& w, stream& ss0)
     181                 : {
     182           44303 :     local_stream ss(ss0);
     183           44303 :     local_const_stream cs(w.cs0_);
     184            9812 :     if(! StackEmpty && ! w.st_.empty())
     185                 :     {
     186                 :         writer::state st;
     187            9812 :         w.st_.pop(st);
     188            9812 :         switch(st)
     189                 :         {
     190             170 :         default:
     191             170 :         case writer::state::str1: goto do_str1;
     192             268 :         case writer::state::str2: goto do_str2;
     193            9082 :         case writer::state::str3: goto do_str3;
     194              52 :         case writer::state::esc1: goto do_esc1;
     195              48 :         case writer::state::utf1: goto do_utf1;
     196              48 :         case writer::state::utf2: goto do_utf2;
     197              48 :         case writer::state::utf3: goto do_utf3;
     198              48 :         case writer::state::utf4: goto do_utf4;
     199              48 :         case writer::state::utf5: goto do_utf5;
     200                 :         }
     201                 :     }
     202                 :     static constexpr char hex[] = "0123456789abcdef";
     203                 :     static constexpr char esc[] =
     204                 :         "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
     205                 :         "\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
     206                 :         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0"
     207                 :         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
     208                 :         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
     209                 :         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
     210                 :         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
     211                 :         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
     212                 : 
     213                 :     // opening quote
     214           34491 : do_str1:
     215           34661 :     if(BOOST_JSON_LIKELY(ss))
     216           34491 :         ss.append('\x22'); // '"'
     217                 :     else
     218             170 :         return w.suspend(writer::state::str1);
     219                 : 
     220                 :     // fast loop,
     221                 :     // copy unescaped
     222           34759 : do_str2:
     223           34759 :     if(BOOST_JSON_LIKELY(ss))
     224                 :     {
     225           34503 :         std::size_t n = cs.remain();
     226           34503 :         if(BOOST_JSON_LIKELY(n > 0))
     227                 :         {
     228           34459 :             if(ss.remain() > n)
     229           25784 :                 n = detail::count_unescaped(
     230                 :                     cs.data(), n);
     231                 :             else
     232            8675 :                 n = detail::count_unescaped(
     233                 :                     cs.data(), ss.remain());
     234           34459 :             if(n > 0)
     235                 :             {
     236           25225 :                 ss.append(cs.data(), n);
     237           25225 :                 cs.skip(n);
     238           25225 :                 if(! ss)
     239              12 :                     return w.suspend(writer::state::str2);
     240                 :             }
     241                 :         }
     242                 :         else
     243                 :         {
     244              44 :             ss.append('\x22'); // '"'
     245              44 :             return true;
     246                 :         }
     247                 :     }
     248                 :     else
     249                 :     {
     250             256 :         return w.suspend(writer::state::str2);
     251                 :     }
     252                 : 
     253                 :     // slow loop,
     254                 :     // handle escapes
     255           43725 : do_str3:
     256        31461094 :     while(BOOST_JSON_LIKELY(ss))
     257                 :     {
     258        31452012 :         if(BOOST_JSON_LIKELY(cs))
     259                 :         {
     260        31417565 :             auto const ch = *cs;
     261        31417565 :             auto const c = esc[static_cast<
     262                 :                 unsigned char>(ch)];
     263        31417565 :             ++cs;
     264        31417565 :             if(! c)
     265                 :             {
     266        31416837 :                 ss.append(ch);
     267                 :             }
     268             728 :             else if(c != 'u')
     269                 :             {
     270             376 :                 ss.append('\\');
     271             376 :                 if(BOOST_JSON_LIKELY(ss))
     272                 :                 {
     273             324 :                     ss.append(c);
     274                 :                 }
     275                 :                 else
     276                 :                 {
     277              52 :                     w.buf_[0] = c;
     278              52 :                     return w.suspend(
     279              52 :                         writer::state::esc1);
     280                 :                 }
     281                 :             }
     282                 :             else
     283                 :             {
     284             352 :                 if(BOOST_JSON_LIKELY(
     285                 :                     ss.remain() >= 6))
     286                 :                 {
     287             208 :                     ss.append("\\u00", 4);
     288             208 :                     ss.append(hex[static_cast<
     289             208 :                         unsigned char>(ch) >> 4]);
     290             208 :                     ss.append(hex[static_cast<
     291             208 :                         unsigned char>(ch) & 15]);
     292                 :                 }
     293                 :                 else
     294                 :                 {
     295             144 :                     ss.append('\\');
     296             144 :                     w.buf_[0] = hex[static_cast<
     297             144 :                         unsigned char>(ch) >> 4];
     298             144 :                     w.buf_[1] = hex[static_cast<
     299             144 :                         unsigned char>(ch) & 15];
     300             144 :                     goto do_utf1;
     301                 :                 }
     302                 :             }
     303                 :         }
     304                 :         else
     305                 :         {
     306           34447 :             ss.append('\x22'); // '"'
     307           34447 :             return true;
     308                 :         }
     309                 :     }
     310            9082 :     return w.suspend(writer::state::str3);
     311                 : 
     312              52 : do_esc1:
     313              52 :     BOOST_ASSERT(ss);
     314              52 :     ss.append(w.buf_[0]);
     315              52 :     goto do_str3;
     316                 : 
     317             192 : do_utf1:
     318             192 :     if(BOOST_JSON_LIKELY(ss))
     319             144 :         ss.append('u');
     320                 :     else
     321              48 :         return w.suspend(writer::state::utf1);
     322             192 : do_utf2:
     323             192 :     if(BOOST_JSON_LIKELY(ss))
     324             144 :         ss.append('0');
     325                 :     else
     326              48 :         return w.suspend(writer::state::utf2);
     327             192 : do_utf3:
     328             192 :     if(BOOST_JSON_LIKELY(ss))
     329             144 :         ss.append('0');
     330                 :     else
     331              48 :         return w.suspend(writer::state::utf3);
     332             192 : do_utf4:
     333             192 :     if(BOOST_JSON_LIKELY(ss))
     334             144 :         ss.append(w.buf_[0]);
     335                 :     else
     336              48 :         return w.suspend(writer::state::utf4);
     337             192 : do_utf5:
     338             192 :     if(BOOST_JSON_LIKELY(ss))
     339             144 :         ss.append(w.buf_[1]);
     340                 :     else
     341              48 :         return w.suspend(writer::state::utf5);
     342             144 :     goto do_str3;
     343           44303 : }
     344                 : 
     345                 : bool
     346           19833 : write_string(writer& w, stream& ss0)
     347                 : {
     348           19833 :     return do_write_string<true>(w, ss0);
     349                 : }
     350                 : 
     351                 : bool
     352             408 : resume_string(writer& w, stream& ss0)
     353                 : {
     354             408 :     return do_write_string<false>(w, ss0);
     355                 : }
     356                 : 
     357                 : template<bool StackEmpty>
     358                 : bool
     359                 : write_value(writer& w, stream& ss);
     360                 : 
     361                 : template< class T, bool StackEmpty >
     362                 : BOOST_FORCEINLINE
     363                 : bool
     364                 : write_impl(no_conversion_tag, writer& w, stream& ss)
     365                 : {
     366           34548 :     return write_value<StackEmpty>(w, ss);
     367                 : }
     368                 : 
     369                 : template<bool StackEmpty>
     370                 : bool
     371            6043 : write_array(writer& w, stream& ss)
     372                 : {
     373            6042 :     return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss);
     374                 : }
     375                 : 
     376                 : template<bool StackEmpty>
     377                 : bool
     378           27196 : write_object(writer& w, stream& ss)
     379                 : {
     380           27196 :     return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss);
     381                 : }
     382                 : 
     383                 : template<bool StackEmpty>
     384                 : bool
     385           66944 : write_value(writer& w, stream& ss)
     386                 : {
     387           22905 :     if(StackEmpty || w.st_.empty())
     388                 :     {
     389           44520 :         BOOST_ASSERT( w.p_ );
     390           44520 :         auto const pv = reinterpret_cast<value const*>(w.p_);
     391           44520 :         switch(pv->kind())
     392                 :         {
     393           18085 :         default:
     394                 :         case kind::object:
     395           18085 :             w.p_ = &pv->get_object();
     396           18085 :             return write_object<true>(w, ss);
     397                 : 
     398            3402 :         case kind::array:
     399            3402 :             w.p_ = &pv->get_array();
     400            3402 :             return write_array<true>(w, ss);
     401                 : 
     402           14655 :         case kind::string:
     403                 :         {
     404           14655 :             auto const& js = pv->get_string();
     405           14655 :             w.cs0_ = { js.data(), js.size() };
     406           14655 :             return do_write_string<true>(w, ss);
     407                 :         }
     408                 : 
     409            3183 :         case kind::int64:
     410            3183 :             return write_int64( w, ss, pv->get_int64() );
     411              91 :         case kind::uint64:
     412              91 :             return write_uint64( w, ss, pv->get_uint64() );
     413             467 :         case kind::double_:
     414             467 :             return write_double( w, ss, pv->get_double() );
     415                 : 
     416             306 :         case kind::bool_:
     417             306 :             if( pv->get_bool() )
     418             139 :                 return write_true(w, ss);
     419                 :             else
     420             167 :                 return write_false(w, ss);
     421                 : 
     422            4331 :         case kind::null:
     423            4331 :             return write_null(w, ss);
     424                 :         }
     425                 :     }
     426                 :     else
     427                 :     {
     428                 :         writer::state st;
     429           22424 :         w.st_.peek(st);
     430           22424 :         switch(st)
     431                 :         {
     432            1324 :         default:
     433                 :         case writer::state::lit:
     434            1324 :             return resume_buffer(w, ss);
     435                 : 
     436            9404 :         case writer::state::str1: case writer::state::str2:
     437                 :         case writer::state::str3: case writer::state::esc1:
     438                 :         case writer::state::utf1: case writer::state::utf2:
     439                 :         case writer::state::utf3: case writer::state::utf4:
     440                 :         case writer::state::utf5:
     441            9404 :             return do_write_string<false>(w, ss);
     442                 : 
     443            2636 :         case writer::state::arr1: case writer::state::arr2:
     444                 :         case writer::state::arr3: case writer::state::arr4:
     445            2636 :             return write_array<StackEmpty>(w, ss);
     446                 : 
     447            9060 :         case writer::state::obj1: case writer::state::obj2:
     448                 :         case writer::state::obj3: case writer::state::obj4:
     449                 :         case writer::state::obj5: case writer::state::obj6:
     450            9060 :             return write_object<StackEmpty>(w, ss);
     451                 :         }
     452                 :     }
     453                 : }
     454                 : 
     455                 : } // namespace detail
     456                 : 
     457            2348 : serializer::
     458            2348 : serializer(serialize_options const& opts) noexcept
     459            2348 :     : serializer({}, nullptr, 0, opts)
     460            2348 : {}
     461                 : 
     462           21250 : serializer::
     463                 : serializer(
     464                 :     storage_ptr sp,
     465                 :     unsigned char* buf,
     466                 :     std::size_t buf_size,
     467           21250 :     serialize_options const& opts) noexcept
     468           21250 :     : detail::writer(std::move(sp), buf, buf_size, opts)
     469           21250 : {}
     470                 : 
     471                 : void
     472           20966 : serializer::
     473                 : reset(value const* p) noexcept
     474                 : {
     475           20966 :     p_ = p;
     476           20966 :     fn0_ = &detail::write_value<true>;
     477           20966 :     fn1_ = &detail::write_value<false>;
     478           20966 :     st_.clear();
     479           20966 :     done_ = false;
     480           20966 : }
     481                 : 
     482                 : void
     483               5 : serializer::
     484                 : reset(array const* p) noexcept
     485                 : {
     486               5 :     p_ = p;
     487               5 :     fn0_ = &detail::write_array<true>;
     488               5 :     fn1_ = &detail::write_array<false>;
     489               5 :     st_.clear();
     490               5 :     done_ = false;
     491               5 : }
     492                 : 
     493                 : void
     494              51 : serializer::
     495                 : reset(object const* p) noexcept
     496                 : {
     497              51 :     p_ = p;
     498              51 :     fn0_ = &detail::write_object<true>;
     499              51 :     fn1_ = &detail::write_object<false>;
     500              51 :     st_.clear();
     501              51 :     done_ = false;
     502              51 : }
     503                 : 
     504                 : void
     505               2 : serializer::
     506                 : reset(string const* p) noexcept
     507                 : {
     508               2 :     cs0_ = { p->data(), p->size() };
     509               2 :     fn0_ = &detail::do_write_string<true>;
     510               2 :     fn1_ = &detail::do_write_string<false>;
     511               2 :     st_.clear();
     512               2 :     done_ = false;
     513               2 : }
     514                 : 
     515                 : void
     516               1 : serializer::
     517                 : reset(string_view sv) noexcept
     518                 : {
     519               1 :     cs0_ = { sv.data(), sv.size() };
     520               1 :     fn0_ = &detail::do_write_string<true>;
     521               1 :     fn1_ = &detail::do_write_string<false>;
     522               1 :     st_.clear();
     523               1 :     done_ = false;
     524               1 : }
     525                 : 
     526                 : void
     527               6 : serializer::reset(std::nullptr_t) noexcept
     528                 : {
     529               6 :     p_ = nullptr;
     530               6 :     fn0_ = &detail::write_impl<std::nullptr_t, true>;
     531               6 :     fn1_ = &detail::write_impl<std::nullptr_t, false>;
     532               6 :     st_.clear();
     533               6 :     done_ = false;
     534               6 : }
     535                 : 
     536                 : string_view
     537           32988 : serializer::
     538                 : read(char* dest, std::size_t size)
     539                 : {
     540           32988 :     if( !fn0_ )
     541               6 :         reset(nullptr);
     542                 : 
     543           32988 :     if(BOOST_JSON_UNLIKELY(size == 0))
     544               1 :         return {dest, 0};
     545                 : 
     546           32987 :     detail::stream ss(dest, size);
     547           32987 :     if(st_.empty())
     548           21249 :         fn0_(*this, ss);
     549                 :     else
     550           11738 :         fn1_(*this, ss);
     551           32985 :     if(st_.empty())
     552                 :     {
     553           21247 :         done_ = true;
     554           21247 :         fn0_ = nullptr;
     555           21247 :         p_ = nullptr;
     556                 :     }
     557           32985 :     return string_view(
     558           32985 :         dest, ss.used(dest));
     559                 : }
     560                 : 
     561                 : } // namespace json
     562                 : } // namespace boost
     563                 : 
     564                 : #ifdef _MSC_VER
     565                 : #pragma warning(pop)
     566                 : #endif
     567                 : 
     568                 : #endif
        

Generated by: LCOV version 2.3