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

Generated by: LCOV version 2.3