Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:47:35

0001 //
0002 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/json
0008 //
0009 
0010 #ifndef BOOST_JSON_IMPL_SERIALIZER_IPP
0011 #define BOOST_JSON_IMPL_SERIALIZER_IPP
0012 
0013 #include <boost/json/serializer.hpp>
0014 #include <boost/json/detail/format.hpp>
0015 #include <boost/json/detail/sse2.hpp>
0016 
0017 #ifdef _MSC_VER
0018 #pragma warning(push)
0019 #pragma warning(disable: 4127) // conditional expression is constant
0020 #endif
0021 
0022 namespace boost {
0023 namespace json {
0024 namespace detail {
0025 
0026 struct int64_formatter
0027 {
0028     std::int64_t i;
0029 
0030     std::size_t
0031     operator()(char* dst) const noexcept
0032     {
0033         return format_int64(dst, i);
0034     }
0035 };
0036 
0037 struct uint64_formatter
0038 {
0039     std::uint64_t u;
0040 
0041     std::size_t
0042     operator()(char* dst) const noexcept
0043     {
0044         return format_uint64(dst, u);
0045     }
0046 };
0047 
0048 struct double_formatter
0049 {
0050     double d;
0051     bool allow_infinity_and_nan;
0052 
0053     std::size_t
0054     operator()(char* dst) const noexcept
0055     {
0056         return format_double(dst, d, allow_infinity_and_nan);
0057     }
0058 };
0059 
0060 writer::
0061 writer(
0062     storage_ptr sp,
0063     unsigned char* buf,
0064     std::size_t buf_size,
0065     serialize_options const& opts) noexcept
0066     : st_(
0067         std::move(sp),
0068         buf,
0069         buf_size)
0070     , opts_(opts)
0071 {
0072     // ensure room for \uXXXX escape plus one
0073     BOOST_STATIC_ASSERT(sizeof(buf_) >= 7);
0074 }
0075 
0076 bool
0077 BOOST_FORCEINLINE
0078 write_buffer(writer& w, stream& ss0)
0079 {
0080     local_stream ss(ss0);
0081     auto const n = ss.remain();
0082     if( n < w.cs0_.remain() )
0083     {
0084         ss.append(w.cs0_.data(), n);
0085         w.cs0_.skip(n);
0086         return w.suspend(writer::state::lit);
0087     }
0088     ss.append( w.cs0_.data(), w.cs0_.remain() );
0089     return true;
0090 }
0091 
0092 template< class F >
0093 bool
0094 write_buffer(writer& w, stream& ss0, F f)
0095 {
0096     BOOST_ASSERT( w.st_.empty() );
0097 
0098     local_stream ss(ss0);
0099     if(BOOST_JSON_LIKELY( ss.remain() >= detail::max_number_chars ))
0100     {
0101         ss.advance( f(ss.data()) );
0102         return true;
0103     }
0104 
0105     w.cs0_ = { w.buf_, f(w.buf_) };
0106     return write_buffer(w, ss);
0107 }
0108 
0109 template<literals Lit>
0110 bool
0111 write_literal(writer& w, stream& ss)
0112 {
0113     constexpr std::size_t index = literal_index(Lit);
0114     constexpr char const* literal = literal_strings[index];
0115     constexpr std::size_t sz = literal_sizes[index];
0116 
0117     std::size_t const n = ss.remain();
0118     if(BOOST_JSON_LIKELY( n >= sz ))
0119     {
0120         ss.append( literal, sz );
0121         return true;
0122     }
0123 
0124     ss.append(literal, n);
0125 
0126     w.cs0_ = {literal + n, sz - n};
0127     return w.suspend(writer::state::lit);
0128 }
0129 
0130 bool
0131 write_true(writer& w, stream& ss)
0132 {
0133     return write_literal<literals::true_>(w, ss);
0134 }
0135 
0136 bool
0137 write_false(writer& w, stream& ss)
0138 {
0139     return write_literal<literals::false_>(w, ss);
0140 }
0141 
0142 bool
0143 write_null(writer& w, stream& ss)
0144 {
0145     return write_literal<literals::null>(w, ss);
0146 }
0147 
0148 bool
0149 write_int64(writer& w, stream& ss0, std::int64_t i)
0150 {
0151     return write_buffer( w, ss0, int64_formatter{i} );
0152 }
0153 
0154 bool
0155 write_uint64(writer& w, stream& ss0, std::uint64_t u)
0156 {
0157     return write_buffer( w, ss0, uint64_formatter{u} );
0158 }
0159 
0160 bool
0161 write_double(writer& w, stream& ss0, double d)
0162 {
0163     return write_buffer(
0164         w, ss0, double_formatter{d, w.opts_.allow_infinity_and_nan} );
0165 }
0166 
0167 bool
0168 resume_buffer(writer& w, stream& ss0)
0169 {
0170     BOOST_ASSERT( !w.st_.empty() );
0171     writer::state st;
0172     w.st_.pop(st);
0173     BOOST_ASSERT(st == writer::state::lit);
0174 
0175     return write_buffer(w, ss0);
0176 }
0177 
0178 template<bool StackEmpty>
0179 bool
0180 do_write_string(writer& w, stream& ss0)
0181 {
0182     local_stream ss(ss0);
0183     local_const_stream cs(w.cs0_);
0184     if(! StackEmpty && ! w.st_.empty())
0185     {
0186         writer::state st;
0187         w.st_.pop(st);
0188         switch(st)
0189         {
0190         default:
0191         case writer::state::str1: goto do_str1;
0192         case writer::state::str2: goto do_str2;
0193         case writer::state::str3: goto do_str3;
0194         case writer::state::esc1: goto do_esc1;
0195         case writer::state::utf1: goto do_utf1;
0196         case writer::state::utf2: goto do_utf2;
0197         case writer::state::utf3: goto do_utf3;
0198         case writer::state::utf4: goto do_utf4;
0199         case writer::state::utf5: goto do_utf5;
0200         }
0201     }
0202     static constexpr char hex[] = "0123456789abcdef";
0203     static constexpr char esc[] =
0204         "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
0205         "\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"
0206         "\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"
0207         "\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"
0208         "\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"
0209         "\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"
0210         "\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"
0211         "\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";
0212 
0213     // opening quote
0214 do_str1:
0215     if(BOOST_JSON_LIKELY(ss))
0216         ss.append('\x22'); // '"'
0217     else
0218         return w.suspend(writer::state::str1);
0219 
0220     // fast loop,
0221     // copy unescaped
0222 do_str2:
0223     if(BOOST_JSON_LIKELY(ss))
0224     {
0225         std::size_t n = cs.remain();
0226         if(BOOST_JSON_LIKELY(n > 0))
0227         {
0228             if(ss.remain() > n)
0229                 n = detail::count_unescaped(
0230                     cs.data(), n);
0231             else
0232                 n = detail::count_unescaped(
0233                     cs.data(), ss.remain());
0234             if(n > 0)
0235             {
0236                 ss.append(cs.data(), n);
0237                 cs.skip(n);
0238                 if(! ss)
0239                     return w.suspend(writer::state::str2);
0240             }
0241         }
0242         else
0243         {
0244             ss.append('\x22'); // '"'
0245             return true;
0246         }
0247     }
0248     else
0249     {
0250         return w.suspend(writer::state::str2);
0251     }
0252 
0253     // slow loop,
0254     // handle escapes
0255 do_str3:
0256     while(BOOST_JSON_LIKELY(ss))
0257     {
0258         if(BOOST_JSON_LIKELY(cs))
0259         {
0260             auto const ch = *cs;
0261             auto const c = esc[static_cast<
0262                 unsigned char>(ch)];
0263             ++cs;
0264             if(! c)
0265             {
0266                 ss.append(ch);
0267             }
0268             else if(c != 'u')
0269             {
0270                 ss.append('\\');
0271                 if(BOOST_JSON_LIKELY(ss))
0272                 {
0273                     ss.append(c);
0274                 }
0275                 else
0276                 {
0277                     w.buf_[0] = c;
0278                     return w.suspend(
0279                         writer::state::esc1);
0280                 }
0281             }
0282             else
0283             {
0284                 if(BOOST_JSON_LIKELY(
0285                     ss.remain() >= 6))
0286                 {
0287                     ss.append("\\u00", 4);
0288                     ss.append(hex[static_cast<
0289                         unsigned char>(ch) >> 4]);
0290                     ss.append(hex[static_cast<
0291                         unsigned char>(ch) & 15]);
0292                 }
0293                 else
0294                 {
0295                     ss.append('\\');
0296                     w.buf_[0] = hex[static_cast<
0297                         unsigned char>(ch) >> 4];
0298                     w.buf_[1] = hex[static_cast<
0299                         unsigned char>(ch) & 15];
0300                     goto do_utf1;
0301                 }
0302             }
0303         }
0304         else
0305         {
0306             ss.append('\x22'); // '"'
0307             return true;
0308         }
0309     }
0310     return w.suspend(writer::state::str3);
0311 
0312 do_esc1:
0313     BOOST_ASSERT(ss);
0314     ss.append(w.buf_[0]);
0315     goto do_str3;
0316 
0317 do_utf1:
0318     if(BOOST_JSON_LIKELY(ss))
0319         ss.append('u');
0320     else
0321         return w.suspend(writer::state::utf1);
0322 do_utf2:
0323     if(BOOST_JSON_LIKELY(ss))
0324         ss.append('0');
0325     else
0326         return w.suspend(writer::state::utf2);
0327 do_utf3:
0328     if(BOOST_JSON_LIKELY(ss))
0329         ss.append('0');
0330     else
0331         return w.suspend(writer::state::utf3);
0332 do_utf4:
0333     if(BOOST_JSON_LIKELY(ss))
0334         ss.append(w.buf_[0]);
0335     else
0336         return w.suspend(writer::state::utf4);
0337 do_utf5:
0338     if(BOOST_JSON_LIKELY(ss))
0339         ss.append(w.buf_[1]);
0340     else
0341         return w.suspend(writer::state::utf5);
0342     goto do_str3;
0343 }
0344 
0345 bool
0346 write_string(writer& w, stream& ss0)
0347 {
0348     return do_write_string<true>(w, ss0);
0349 }
0350 
0351 bool
0352 resume_string(writer& w, stream& ss0)
0353 {
0354     return do_write_string<false>(w, ss0);
0355 }
0356 
0357 template<bool StackEmpty>
0358 bool
0359 write_value(writer& w, stream& ss);
0360 
0361 template< class T, bool StackEmpty >
0362 BOOST_FORCEINLINE
0363 bool
0364 write_impl(no_conversion_tag, writer& w, stream& ss)
0365 {
0366     return write_value<StackEmpty>(w, ss);
0367 }
0368 
0369 template<bool StackEmpty>
0370 bool
0371 write_array(writer& w, stream& ss)
0372 {
0373     return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss);
0374 }
0375 
0376 template<bool StackEmpty>
0377 bool
0378 write_object(writer& w, stream& ss)
0379 {
0380     return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss);
0381 }
0382 
0383 template<bool StackEmpty>
0384 bool
0385 write_value(writer& w, stream& ss)
0386 {
0387     if(StackEmpty || w.st_.empty())
0388     {
0389         BOOST_ASSERT( w.p_ );
0390         auto const pv = reinterpret_cast<value const*>(w.p_);
0391         switch(pv->kind())
0392         {
0393         default:
0394         case kind::object:
0395             w.p_ = &pv->get_object();
0396             return write_object<true>(w, ss);
0397 
0398         case kind::array:
0399             w.p_ = &pv->get_array();
0400             return write_array<true>(w, ss);
0401 
0402         case kind::string:
0403         {
0404             auto const& js = pv->get_string();
0405             w.cs0_ = { js.data(), js.size() };
0406             return do_write_string<true>(w, ss);
0407         }
0408 
0409         case kind::int64:
0410             return write_int64( w, ss, pv->get_int64() );
0411         case kind::uint64:
0412             return write_uint64( w, ss, pv->get_uint64() );
0413         case kind::double_:
0414             return write_double( w, ss, pv->get_double() );
0415 
0416         case kind::bool_:
0417             if( pv->get_bool() )
0418                 return write_true(w, ss);
0419             else
0420                 return write_false(w, ss);
0421 
0422         case kind::null:
0423             return write_null(w, ss);
0424         }
0425     }
0426     else
0427     {
0428         writer::state st;
0429         w.st_.peek(st);
0430         switch(st)
0431         {
0432         default:
0433         case writer::state::lit:
0434             return resume_buffer(w, ss);
0435 
0436         case writer::state::str1: case writer::state::str2:
0437         case writer::state::str3: case writer::state::esc1:
0438         case writer::state::utf1: case writer::state::utf2:
0439         case writer::state::utf3: case writer::state::utf4:
0440         case writer::state::utf5:
0441             return do_write_string<false>(w, ss);
0442 
0443         case writer::state::arr1: case writer::state::arr2:
0444         case writer::state::arr3: case writer::state::arr4:
0445             return write_array<StackEmpty>(w, ss);
0446 
0447         case writer::state::obj1: case writer::state::obj2:
0448         case writer::state::obj3: case writer::state::obj4:
0449         case writer::state::obj5: case writer::state::obj6:
0450             return write_object<StackEmpty>(w, ss);
0451         }
0452     }
0453 }
0454 
0455 } // namespace detail
0456 
0457 serializer::
0458 serializer(serialize_options const& opts) noexcept
0459     : serializer({}, nullptr, 0, opts)
0460 {}
0461 
0462 serializer::
0463 serializer(
0464     storage_ptr sp,
0465     unsigned char* buf,
0466     std::size_t buf_size,
0467     serialize_options const& opts) noexcept
0468     : detail::writer(std::move(sp), buf, buf_size, opts)
0469 {}
0470 
0471 void
0472 serializer::
0473 reset(value const* p) noexcept
0474 {
0475     p_ = p;
0476     fn0_ = &detail::write_value<true>;
0477     fn1_ = &detail::write_value<false>;
0478     st_.clear();
0479     done_ = false;
0480 }
0481 
0482 void
0483 serializer::
0484 reset(array const* p) noexcept
0485 {
0486     p_ = p;
0487     fn0_ = &detail::write_array<true>;
0488     fn1_ = &detail::write_array<false>;
0489     st_.clear();
0490     done_ = false;
0491 }
0492 
0493 void
0494 serializer::
0495 reset(object const* p) noexcept
0496 {
0497     p_ = p;
0498     fn0_ = &detail::write_object<true>;
0499     fn1_ = &detail::write_object<false>;
0500     st_.clear();
0501     done_ = false;
0502 }
0503 
0504 void
0505 serializer::
0506 reset(string const* p) noexcept
0507 {
0508     cs0_ = { p->data(), p->size() };
0509     fn0_ = &detail::do_write_string<true>;
0510     fn1_ = &detail::do_write_string<false>;
0511     st_.clear();
0512     done_ = false;
0513 }
0514 
0515 void
0516 serializer::
0517 reset(string_view sv) noexcept
0518 {
0519     cs0_ = { sv.data(), sv.size() };
0520     fn0_ = &detail::do_write_string<true>;
0521     fn1_ = &detail::do_write_string<false>;
0522     st_.clear();
0523     done_ = false;
0524 }
0525 
0526 void
0527 serializer::reset(std::nullptr_t) noexcept
0528 {
0529     p_ = nullptr;
0530     fn0_ = &detail::write_impl<std::nullptr_t, true>;
0531     fn1_ = &detail::write_impl<std::nullptr_t, false>;
0532     st_.clear();
0533     done_ = false;
0534 }
0535 
0536 string_view
0537 serializer::
0538 read(char* dest, std::size_t size)
0539 {
0540     if( !fn0_ )
0541         reset(nullptr);
0542 
0543     if(BOOST_JSON_UNLIKELY(size == 0))
0544         return {dest, 0};
0545 
0546     detail::stream ss(dest, size);
0547     if(st_.empty())
0548         fn0_(*this, ss);
0549     else
0550         fn1_(*this, ss);
0551     if(st_.empty())
0552     {
0553         done_ = true;
0554         fn0_ = nullptr;
0555         p_ = nullptr;
0556     }
0557     return string_view(
0558         dest, ss.used(dest));
0559 }
0560 
0561 } // namespace json
0562 } // namespace boost
0563 
0564 #ifdef _MSC_VER
0565 #pragma warning(pop)
0566 #endif
0567 
0568 #endif