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: 2026-01-02 17:31:39 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/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         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        21245 : writer::
      62              : writer(
      63              :     storage_ptr sp,
      64              :     unsigned char* buf,
      65              :     std::size_t buf_size,
      66        21245 :     serialize_options const& opts) noexcept
      67        21245 :     : st_(
      68        21245 :         std::move(sp),
      69              :         buf,
      70              :         buf_size)
      71        21245 :     , opts_(opts)
      72              : {
      73              :     // ensure room for \uXXXX escape plus one
      74              :     BOOST_CORE_STATIC_ASSERT( sizeof(buf_) >= 7 );
      75        21245 : }
      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        44285 : do_write_string(writer& w, stream& ss0)
     182              : {
     183        44285 :     local_stream ss(ss0);
     184        44285 :     local_const_stream cs(w.cs0_);
     185         9812 :     if(! StackEmpty && ! w.st_.empty())
     186              :     {
     187              :         writer::state st;
     188         9812 :         w.st_.pop(st);
     189         9812 :         switch(st)
     190              :         {
     191          170 :         default:
     192          170 :         case writer::state::str1: goto do_str1;
     193          268 :         case writer::state::str2: goto do_str2;
     194         9082 :         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        34473 : do_str1:
     216        34643 :     if(BOOST_JSON_LIKELY(ss))
     217        34473 :         ss.append('\x22'); // '"'
     218              :     else
     219          170 :         return w.suspend(writer::state::str1);
     220              : 
     221              :     // fast loop,
     222              :     // copy unescaped
     223        34741 : do_str2:
     224        34741 :     if(BOOST_JSON_LIKELY(ss))
     225              :     {
     226        34485 :         std::size_t n = cs.remain();
     227        34485 :         if(BOOST_JSON_LIKELY(n > 0))
     228              :         {
     229        34441 :             if(ss.remain() > n)
     230        25766 :                 n = detail::count_unescaped(
     231              :                     cs.data(), n);
     232              :             else
     233         8675 :                 n = detail::count_unescaped(
     234              :                     cs.data(), ss.remain());
     235        34441 :             if(n > 0)
     236              :             {
     237        25225 :                 ss.append(cs.data(), n);
     238        25225 :                 cs.skip(n);
     239        25225 :                 if(! ss)
     240           12 :                     return w.suspend(writer::state::str2);
     241              :             }
     242              :         }
     243              :         else
     244              :         {
     245           44 :             ss.append('\x22'); // '"'
     246           44 :             return true;
     247              :         }
     248              :     }
     249              :     else
     250              :     {
     251          256 :         return w.suspend(writer::state::str2);
     252              :     }
     253              : 
     254              :     // slow loop,
     255              :     // handle escapes
     256        43707 : do_str3:
     257     31461016 :     while(BOOST_JSON_LIKELY(ss))
     258              :     {
     259     31451934 :         if(BOOST_JSON_LIKELY(cs))
     260              :         {
     261     31417505 :             auto const ch = *cs;
     262     31417505 :             auto const c = esc[static_cast<
     263              :                 unsigned char>(ch)];
     264     31417505 :             ++cs;
     265     31417505 :             if(! c)
     266              :             {
     267     31416777 :                 ss.append(ch);
     268              :             }
     269          728 :             else if(c != 'u')
     270              :             {
     271          376 :                 ss.append('\\');
     272          376 :                 if(BOOST_JSON_LIKELY(ss))
     273              :                 {
     274          324 :                     ss.append(c);
     275              :                 }
     276              :                 else
     277              :                 {
     278           52 :                     w.buf_[0] = c;
     279           52 :                     return w.suspend(
     280           52 :                         writer::state::esc1);
     281              :                 }
     282              :             }
     283              :             else
     284              :             {
     285          352 :                 if(BOOST_JSON_LIKELY(
     286              :                     ss.remain() >= 6))
     287              :                 {
     288          208 :                     ss.append("\\u00", 4);
     289          208 :                     ss.append(hex[static_cast<
     290          208 :                         unsigned char>(ch) >> 4]);
     291          208 :                     ss.append(hex[static_cast<
     292          208 :                         unsigned char>(ch) & 15]);
     293              :                 }
     294              :                 else
     295              :                 {
     296          144 :                     ss.append('\\');
     297          144 :                     w.buf_[0] = hex[static_cast<
     298          144 :                         unsigned char>(ch) >> 4];
     299          144 :                     w.buf_[1] = hex[static_cast<
     300          144 :                         unsigned char>(ch) & 15];
     301          144 :                     goto do_utf1;
     302              :                 }
     303              :             }
     304              :         }
     305              :         else
     306              :         {
     307        34429 :             ss.append('\x22'); // '"'
     308        34429 :             return true;
     309              :         }
     310              :     }
     311         9082 :     return w.suspend(writer::state::str3);
     312              : 
     313           52 : do_esc1:
     314           52 :     BOOST_ASSERT(ss);
     315           52 :     ss.append(w.buf_[0]);
     316           52 :     goto do_str3;
     317              : 
     318          192 : do_utf1:
     319          192 :     if(BOOST_JSON_LIKELY(ss))
     320          144 :         ss.append('u');
     321              :     else
     322           48 :         return w.suspend(writer::state::utf1);
     323          192 : do_utf2:
     324          192 :     if(BOOST_JSON_LIKELY(ss))
     325          144 :         ss.append('0');
     326              :     else
     327           48 :         return w.suspend(writer::state::utf2);
     328          192 : do_utf3:
     329          192 :     if(BOOST_JSON_LIKELY(ss))
     330          144 :         ss.append('0');
     331              :     else
     332           48 :         return w.suspend(writer::state::utf3);
     333          192 : do_utf4:
     334          192 :     if(BOOST_JSON_LIKELY(ss))
     335          144 :         ss.append(w.buf_[0]);
     336              :     else
     337           48 :         return w.suspend(writer::state::utf4);
     338          192 : do_utf5:
     339          192 :     if(BOOST_JSON_LIKELY(ss))
     340          144 :         ss.append(w.buf_[1]);
     341              :     else
     342           48 :         return w.suspend(writer::state::utf5);
     343          144 :     goto do_str3;
     344        44285 : }
     345              : 
     346              : bool
     347        19827 : write_string(writer& w, stream& ss0)
     348              : {
     349        19827 :     return do_write_string<true>(w, ss0);
     350              : }
     351              : 
     352              : bool
     353          408 : resume_string(writer& w, stream& ss0)
     354              : {
     355          408 :     return do_write_string<false>(w, ss0);
     356              : }
     357              : 
     358              : template<bool StackEmpty>
     359              : bool
     360              : write_value(writer& w, stream& ss);
     361              : 
     362              : template< class T, bool StackEmpty >
     363              : BOOST_FORCEINLINE
     364              : bool
     365              : write_impl(no_conversion_tag, writer& w, stream& ss)
     366              : {
     367        34536 :     return write_value<StackEmpty>(w, ss);
     368              : }
     369              : 
     370              : template<bool StackEmpty>
     371              : bool
     372         6041 : write_array(writer& w, stream& ss)
     373              : {
     374         6040 :     return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss);
     375              : }
     376              : 
     377              : template<bool StackEmpty>
     378              : bool
     379        27194 : write_object(writer& w, stream& ss)
     380              : {
     381        27194 :     return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss);
     382              : }
     383              : 
     384              : template<bool StackEmpty>
     385              : bool
     386        66927 : write_value(writer& w, stream& ss)
     387              : {
     388        22905 :     if(StackEmpty || w.st_.empty())
     389              :     {
     390        44503 :         BOOST_ASSERT( w.p_ );
     391        44503 :         auto const pv = reinterpret_cast<value const*>(w.p_);
     392        44503 :         switch(pv->kind())
     393              :         {
     394        18083 :         default:
     395              :         case kind::object:
     396        18083 :             w.p_ = &pv->get_object();
     397        18083 :             return write_object<true>(w, ss);
     398              : 
     399         3400 :         case kind::array:
     400         3400 :             w.p_ = &pv->get_array();
     401         3400 :             return write_array<true>(w, ss);
     402              : 
     403        14643 :         case kind::string:
     404              :         {
     405        14643 :             auto const& js = pv->get_string();
     406        14643 :             w.cs0_ = { js.data(), js.size() };
     407        14643 :             return do_write_string<true>(w, ss);
     408              :         }
     409              : 
     410         3182 :         case kind::int64:
     411         3182 :             return write_int64( w, ss, pv->get_int64() );
     412           91 :         case kind::uint64:
     413           91 :             return write_uint64( w, ss, pv->get_uint64() );
     414          467 :         case kind::double_:
     415          467 :             return write_double( w, ss, pv->get_double() );
     416              : 
     417          306 :         case kind::bool_:
     418          306 :             if( pv->get_bool() )
     419          139 :                 return write_true(w, ss);
     420              :             else
     421          167 :                 return write_false(w, ss);
     422              : 
     423         4331 :         case kind::null:
     424         4331 :             return write_null(w, ss);
     425              :         }
     426              :     }
     427              :     else
     428              :     {
     429              :         writer::state st;
     430        22424 :         w.st_.peek(st);
     431        22424 :         switch(st)
     432              :         {
     433         1324 :         default:
     434              :         case writer::state::lit:
     435         1324 :             return resume_buffer(w, ss);
     436              : 
     437         9404 :         case writer::state::str1: case writer::state::str2:
     438              :         case writer::state::str3: case writer::state::esc1:
     439              :         case writer::state::utf1: case writer::state::utf2:
     440              :         case writer::state::utf3: case writer::state::utf4:
     441              :         case writer::state::utf5:
     442         9404 :             return do_write_string<false>(w, ss);
     443              : 
     444         2636 :         case writer::state::arr1: case writer::state::arr2:
     445              :         case writer::state::arr3: case writer::state::arr4:
     446         2636 :             return write_array<StackEmpty>(w, ss);
     447              : 
     448         9060 :         case writer::state::obj1: case writer::state::obj2:
     449              :         case writer::state::obj3: case writer::state::obj4:
     450              :         case writer::state::obj5: case writer::state::obj6:
     451         9060 :             return write_object<StackEmpty>(w, ss);
     452              :         }
     453              :     }
     454              : }
     455              : 
     456              : } // namespace detail
     457              : 
     458         2348 : serializer::
     459         2348 : serializer(serialize_options const& opts) noexcept
     460         2348 :     : serializer({}, nullptr, 0, opts)
     461         2348 : {}
     462              : 
     463        21245 : serializer::
     464              : serializer(
     465              :     storage_ptr sp,
     466              :     unsigned char* buf,
     467              :     std::size_t buf_size,
     468        21245 :     serialize_options const& opts) noexcept
     469        21245 :     : detail::writer(std::move(sp), buf, buf_size, opts)
     470        21245 : {}
     471              : 
     472              : void
     473        20961 : serializer::
     474              : reset(value const* p) noexcept
     475              : {
     476        20961 :     p_ = p;
     477        20961 :     fn0_ = &detail::write_value<true>;
     478        20961 :     fn1_ = &detail::write_value<false>;
     479        20961 :     st_.clear();
     480        20961 :     done_ = false;
     481        20961 : }
     482              : 
     483              : void
     484            5 : serializer::
     485              : reset(array const* p) noexcept
     486              : {
     487            5 :     p_ = p;
     488            5 :     fn0_ = &detail::write_array<true>;
     489            5 :     fn1_ = &detail::write_array<false>;
     490            5 :     st_.clear();
     491            5 :     done_ = false;
     492            5 : }
     493              : 
     494              : void
     495           51 : serializer::
     496              : reset(object const* p) noexcept
     497              : {
     498           51 :     p_ = p;
     499           51 :     fn0_ = &detail::write_object<true>;
     500           51 :     fn1_ = &detail::write_object<false>;
     501           51 :     st_.clear();
     502           51 :     done_ = false;
     503           51 : }
     504              : 
     505              : void
     506            2 : serializer::
     507              : reset(string const* p) noexcept
     508              : {
     509            2 :     cs0_ = { p->data(), p->size() };
     510            2 :     fn0_ = &detail::do_write_string<true>;
     511            2 :     fn1_ = &detail::do_write_string<false>;
     512            2 :     st_.clear();
     513            2 :     done_ = false;
     514            2 : }
     515              : 
     516              : void
     517            1 : serializer::
     518              : reset(string_view sv) noexcept
     519              : {
     520            1 :     cs0_ = { sv.data(), sv.size() };
     521            1 :     fn0_ = &detail::do_write_string<true>;
     522            1 :     fn1_ = &detail::do_write_string<false>;
     523            1 :     st_.clear();
     524            1 :     done_ = false;
     525            1 : }
     526              : 
     527              : void
     528            6 : serializer::reset(std::nullptr_t) noexcept
     529              : {
     530            6 :     p_ = nullptr;
     531            6 :     fn0_ = &detail::write_impl<std::nullptr_t, true>;
     532            6 :     fn1_ = &detail::write_impl<std::nullptr_t, false>;
     533            6 :     st_.clear();
     534            6 :     done_ = false;
     535            6 : }
     536              : 
     537              : string_view
     538        32983 : serializer::
     539              : read(char* dest, std::size_t size)
     540              : {
     541        32983 :     if( !fn0_ )
     542            6 :         reset(nullptr);
     543              : 
     544        32983 :     if(BOOST_JSON_UNLIKELY(size == 0))
     545            1 :         return {dest, 0};
     546              : 
     547        32982 :     detail::stream ss(dest, size);
     548        32982 :     if(st_.empty())
     549        21244 :         fn0_(*this, ss);
     550              :     else
     551        11738 :         fn1_(*this, ss);
     552        32980 :     if(st_.empty())
     553              :     {
     554        21242 :         done_ = true;
     555        21242 :         fn0_ = nullptr;
     556        21242 :         p_ = nullptr;
     557              :     }
     558        32980 :     return string_view(
     559        32980 :         dest, ss.used(dest));
     560              : }
     561              : 
     562              : } // namespace json
     563              : } // namespace boost
     564              : 
     565              : #ifdef _MSC_VER
     566              : #pragma warning(pop)
     567              : #endif
     568              : 
     569              : #endif
        

Generated by: LCOV version 2.1