LCOV - code coverage report
Current view: top level - json/impl - serializer.ipp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 261 261
Test Date: 2025-12-23 17:20:51 Functions: 100.0 % 36 36

            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         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.1