File indexing completed on 2026-08-19 08:49:17
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/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)
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
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
0215 do_str1:
0216 if(BOOST_JSON_LIKELY(ss))
0217 ss.append('\x22');
0218 else
0219 return w.suspend(writer::state::str1);
0220
0221
0222
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
0255
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 }
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 }
0563 }
0564
0565 #ifdef _MSC_VER
0566 #pragma warning(pop)
0567 #endif
0568
0569 #endif