Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-19 08:49:17

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