File indexing completed on 2025-09-18 08:47:35
0001
0002
0003
0004
0005
0006
0007
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)
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
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
0214 do_str1:
0215 if(BOOST_JSON_LIKELY(ss))
0216 ss.append('\x22');
0217 else
0218 return w.suspend(writer::state::str1);
0219
0220
0221
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
0254
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 }
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 }
0562 }
0563
0564 #ifdef _MSC_VER
0565 #pragma warning(pop)
0566 #endif
0567
0568 #endif