File indexing completed on 2025-07-11 08:14:24
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 #include <ostream>
0017
0018 #ifdef _MSC_VER
0019 #pragma warning(push)
0020 #pragma warning(disable: 4127)
0021 #endif
0022
0023 namespace boost {
0024 namespace json {
0025
0026 enum class serializer::state : char
0027 {
0028 nul1, nul2, nul3, nul4,
0029 tru1, tru2, tru3, tru4,
0030 fal1, fal2, fal3, fal4, fal5,
0031 str1, str2, str3, esc1, utf1,
0032 utf2, utf3, utf4, utf5,
0033 num,
0034 arr1, arr2, arr3, arr4,
0035 obj1, obj2, obj3, obj4, obj5, obj6
0036 };
0037
0038
0039
0040 serializer::
0041 serializer(
0042 storage_ptr sp,
0043 unsigned char* buf,
0044 std::size_t buf_size,
0045 serialize_options const& opts) noexcept
0046 : st_(
0047 std::move(sp),
0048 buf,
0049 buf_size)
0050 , opts_(opts)
0051 {
0052 }
0053
0054 bool
0055 serializer::
0056 suspend(state st)
0057 {
0058 st_.push(st);
0059 return false;
0060 }
0061
0062 bool
0063 serializer::
0064 suspend(
0065 state st,
0066 array::const_iterator it,
0067 array const* pa)
0068 {
0069 st_.push(pa);
0070 st_.push(it);
0071 st_.push(st);
0072 return false;
0073 }
0074
0075 bool
0076 serializer::
0077 suspend(
0078 state st,
0079 object::const_iterator it,
0080 object const* po)
0081 {
0082 st_.push(po);
0083 st_.push(it);
0084 st_.push(st);
0085 return false;
0086 }
0087
0088 template<bool StackEmpty>
0089 bool
0090 serializer::
0091 write_null(stream& ss0)
0092 {
0093 local_stream ss(ss0);
0094 if(! StackEmpty && ! st_.empty())
0095 {
0096 state st;
0097 st_.pop(st);
0098 switch(st)
0099 {
0100 default:
0101 case state::nul1: goto do_nul1;
0102 case state::nul2: goto do_nul2;
0103 case state::nul3: goto do_nul3;
0104 case state::nul4: goto do_nul4;
0105 }
0106 }
0107 do_nul1:
0108 if(BOOST_JSON_LIKELY(ss))
0109 ss.append('n');
0110 else
0111 return suspend(state::nul1);
0112 do_nul2:
0113 if(BOOST_JSON_LIKELY(ss))
0114 ss.append('u');
0115 else
0116 return suspend(state::nul2);
0117 do_nul3:
0118 if(BOOST_JSON_LIKELY(ss))
0119 ss.append('l');
0120 else
0121 return suspend(state::nul3);
0122 do_nul4:
0123 if(BOOST_JSON_LIKELY(ss))
0124 ss.append('l');
0125 else
0126 return suspend(state::nul4);
0127 return true;
0128 }
0129
0130 template<bool StackEmpty>
0131 bool
0132 serializer::
0133 write_true(stream& ss0)
0134 {
0135 local_stream ss(ss0);
0136 if(! StackEmpty && ! st_.empty())
0137 {
0138 state st;
0139 st_.pop(st);
0140 switch(st)
0141 {
0142 default:
0143 case state::tru1: goto do_tru1;
0144 case state::tru2: goto do_tru2;
0145 case state::tru3: goto do_tru3;
0146 case state::tru4: goto do_tru4;
0147 }
0148 }
0149 do_tru1:
0150 if(BOOST_JSON_LIKELY(ss))
0151 ss.append('t');
0152 else
0153 return suspend(state::tru1);
0154 do_tru2:
0155 if(BOOST_JSON_LIKELY(ss))
0156 ss.append('r');
0157 else
0158 return suspend(state::tru2);
0159 do_tru3:
0160 if(BOOST_JSON_LIKELY(ss))
0161 ss.append('u');
0162 else
0163 return suspend(state::tru3);
0164 do_tru4:
0165 if(BOOST_JSON_LIKELY(ss))
0166 ss.append('e');
0167 else
0168 return suspend(state::tru4);
0169 return true;
0170 }
0171
0172 template<bool StackEmpty>
0173 bool
0174 serializer::
0175 write_false(stream& ss0)
0176 {
0177 local_stream ss(ss0);
0178 if(! StackEmpty && ! st_.empty())
0179 {
0180 state st;
0181 st_.pop(st);
0182 switch(st)
0183 {
0184 default:
0185 case state::fal1: goto do_fal1;
0186 case state::fal2: goto do_fal2;
0187 case state::fal3: goto do_fal3;
0188 case state::fal4: goto do_fal4;
0189 case state::fal5: goto do_fal5;
0190 }
0191 }
0192 do_fal1:
0193 if(BOOST_JSON_LIKELY(ss))
0194 ss.append('f');
0195 else
0196 return suspend(state::fal1);
0197 do_fal2:
0198 if(BOOST_JSON_LIKELY(ss))
0199 ss.append('a');
0200 else
0201 return suspend(state::fal2);
0202 do_fal3:
0203 if(BOOST_JSON_LIKELY(ss))
0204 ss.append('l');
0205 else
0206 return suspend(state::fal3);
0207 do_fal4:
0208 if(BOOST_JSON_LIKELY(ss))
0209 ss.append('s');
0210 else
0211 return suspend(state::fal4);
0212 do_fal5:
0213 if(BOOST_JSON_LIKELY(ss))
0214 ss.append('e');
0215 else
0216 return suspend(state::fal5);
0217 return true;
0218 }
0219
0220 template<bool StackEmpty>
0221 bool
0222 serializer::
0223 write_string(stream& ss0)
0224 {
0225 local_stream ss(ss0);
0226 local_const_stream cs(cs0_);
0227 if(! StackEmpty && ! st_.empty())
0228 {
0229 state st;
0230 st_.pop(st);
0231 switch(st)
0232 {
0233 default:
0234 case state::str1: goto do_str1;
0235 case state::str2: goto do_str2;
0236 case state::str3: goto do_str3;
0237 case state::esc1: goto do_esc1;
0238 case state::utf1: goto do_utf1;
0239 case state::utf2: goto do_utf2;
0240 case state::utf3: goto do_utf3;
0241 case state::utf4: goto do_utf4;
0242 case state::utf5: goto do_utf5;
0243 }
0244 }
0245 static constexpr char hex[] = "0123456789abcdef";
0246 static constexpr char esc[] =
0247 "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
0248 "\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
0249 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0"
0250 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
0251 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
0252 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
0253 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
0254 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
0255
0256
0257 do_str1:
0258 if(BOOST_JSON_LIKELY(ss))
0259 ss.append('\x22');
0260 else
0261 return suspend(state::str1);
0262
0263
0264
0265 do_str2:
0266 if(BOOST_JSON_LIKELY(ss))
0267 {
0268 std::size_t n = cs.remain();
0269 if(BOOST_JSON_LIKELY(n > 0))
0270 {
0271 if(ss.remain() > n)
0272 n = detail::count_unescaped(
0273 cs.data(), n);
0274 else
0275 n = detail::count_unescaped(
0276 cs.data(), ss.remain());
0277 if(n > 0)
0278 {
0279 ss.append(cs.data(), n);
0280 cs.skip(n);
0281 if(! ss)
0282 return suspend(state::str2);
0283 }
0284 }
0285 else
0286 {
0287 ss.append('\x22');
0288 return true;
0289 }
0290 }
0291 else
0292 {
0293 return suspend(state::str2);
0294 }
0295
0296
0297
0298 do_str3:
0299 while(BOOST_JSON_LIKELY(ss))
0300 {
0301 if(BOOST_JSON_LIKELY(cs))
0302 {
0303 auto const ch = *cs;
0304 auto const c = esc[static_cast<
0305 unsigned char>(ch)];
0306 ++cs;
0307 if(! c)
0308 {
0309 ss.append(ch);
0310 }
0311 else if(c != 'u')
0312 {
0313 ss.append('\\');
0314 if(BOOST_JSON_LIKELY(ss))
0315 {
0316 ss.append(c);
0317 }
0318 else
0319 {
0320 buf_[0] = c;
0321 return suspend(
0322 state::esc1);
0323 }
0324 }
0325 else
0326 {
0327 if(BOOST_JSON_LIKELY(
0328 ss.remain() >= 6))
0329 {
0330 ss.append("\\u00", 4);
0331 ss.append(hex[static_cast<
0332 unsigned char>(ch) >> 4]);
0333 ss.append(hex[static_cast<
0334 unsigned char>(ch) & 15]);
0335 }
0336 else
0337 {
0338 ss.append('\\');
0339 buf_[0] = hex[static_cast<
0340 unsigned char>(ch) >> 4];
0341 buf_[1] = hex[static_cast<
0342 unsigned char>(ch) & 15];
0343 goto do_utf1;
0344 }
0345 }
0346 }
0347 else
0348 {
0349 ss.append('\x22');
0350 return true;
0351 }
0352 }
0353 return suspend(state::str3);
0354
0355 do_esc1:
0356 if(BOOST_JSON_LIKELY(ss))
0357 ss.append(buf_[0]);
0358 else
0359 return suspend(state::esc1);
0360 goto do_str3;
0361
0362 do_utf1:
0363 if(BOOST_JSON_LIKELY(ss))
0364 ss.append('u');
0365 else
0366 return suspend(state::utf1);
0367 do_utf2:
0368 if(BOOST_JSON_LIKELY(ss))
0369 ss.append('0');
0370 else
0371 return suspend(state::utf2);
0372 do_utf3:
0373 if(BOOST_JSON_LIKELY(ss))
0374 ss.append('0');
0375 else
0376 return suspend(state::utf3);
0377 do_utf4:
0378 if(BOOST_JSON_LIKELY(ss))
0379 ss.append(buf_[0]);
0380 else
0381 return suspend(state::utf4);
0382 do_utf5:
0383 if(BOOST_JSON_LIKELY(ss))
0384 ss.append(buf_[1]);
0385 else
0386 return suspend(state::utf5);
0387 goto do_str3;
0388 }
0389
0390 template<bool StackEmpty>
0391 bool
0392 serializer::
0393 write_number(stream& ss0)
0394 {
0395 local_stream ss(ss0);
0396 if(StackEmpty || st_.empty())
0397 {
0398 switch(jv_->kind())
0399 {
0400 default:
0401 case kind::int64:
0402 if(BOOST_JSON_LIKELY(
0403 ss.remain() >=
0404 detail::max_number_chars))
0405 {
0406 ss.advance(detail::format_int64(
0407 ss.data(), jv_->get_int64()));
0408 return true;
0409 }
0410 cs0_ = { buf_, detail::format_int64(
0411 buf_, jv_->get_int64()) };
0412 break;
0413
0414 case kind::uint64:
0415 if(BOOST_JSON_LIKELY(
0416 ss.remain() >=
0417 detail::max_number_chars))
0418 {
0419 ss.advance(detail::format_uint64(
0420 ss.data(), jv_->get_uint64()));
0421 return true;
0422 }
0423 cs0_ = { buf_, detail::format_uint64(
0424 buf_, jv_->get_uint64()) };
0425 break;
0426
0427 case kind::double_:
0428 if(BOOST_JSON_LIKELY(
0429 ss.remain() >=
0430 detail::max_number_chars))
0431 {
0432 ss.advance(
0433 detail::format_double(
0434 ss.data(),
0435 jv_->get_double(),
0436 opts_.allow_infinity_and_nan));
0437 return true;
0438 }
0439 cs0_ = { buf_, detail::format_double(
0440 buf_, jv_->get_double(), opts_.allow_infinity_and_nan) };
0441 break;
0442 }
0443 }
0444 else
0445 {
0446 state st;
0447 st_.pop(st);
0448 BOOST_ASSERT(
0449 st == state::num);
0450 }
0451 auto const n = ss.remain();
0452 if(n < cs0_.remain())
0453 {
0454 ss.append(cs0_.data(), n);
0455 cs0_.skip(n);
0456 return suspend(state::num);
0457 }
0458 ss.append(
0459 cs0_.data(), cs0_.remain());
0460 return true;
0461 }
0462
0463 template<bool StackEmpty>
0464 bool
0465 serializer::
0466 write_array(stream& ss0)
0467 {
0468 array const* pa;
0469 local_stream ss(ss0);
0470 array::const_iterator it;
0471 array::const_iterator end;
0472 if(StackEmpty || st_.empty())
0473 {
0474 pa = pa_;
0475 it = pa->begin();
0476 end = pa->end();
0477 }
0478 else
0479 {
0480 state st;
0481 st_.pop(st);
0482 st_.pop(it);
0483 st_.pop(pa);
0484 end = pa->end();
0485 switch(st)
0486 {
0487 default:
0488 case state::arr1: goto do_arr1;
0489 case state::arr2: goto do_arr2;
0490 case state::arr3: goto do_arr3;
0491 case state::arr4: goto do_arr4;
0492 break;
0493 }
0494 }
0495 do_arr1:
0496 if(BOOST_JSON_LIKELY(ss))
0497 ss.append('[');
0498 else
0499 return suspend(
0500 state::arr1, it, pa);
0501 if(it == end)
0502 goto do_arr4;
0503 for(;;)
0504 {
0505 do_arr2:
0506 jv_ = &*it;
0507 if(! write_value<StackEmpty>(ss))
0508 return suspend(
0509 state::arr2, it, pa);
0510 if(BOOST_JSON_UNLIKELY(
0511 ++it == end))
0512 break;
0513 do_arr3:
0514 if(BOOST_JSON_LIKELY(ss))
0515 ss.append(',');
0516 else
0517 return suspend(
0518 state::arr3, it, pa);
0519 }
0520 do_arr4:
0521 if(BOOST_JSON_LIKELY(ss))
0522 ss.append(']');
0523 else
0524 return suspend(
0525 state::arr4, it, pa);
0526 return true;
0527 }
0528
0529 template<bool StackEmpty>
0530 bool
0531 serializer::
0532 write_object(stream& ss0)
0533 {
0534 object const* po;
0535 local_stream ss(ss0);
0536 object::const_iterator it;
0537 object::const_iterator end;
0538 if(StackEmpty || st_.empty())
0539 {
0540 po = po_;
0541 it = po->begin();
0542 end = po->end();
0543 }
0544 else
0545 {
0546 state st;
0547 st_.pop(st);
0548 st_.pop(it);
0549 st_.pop(po);
0550 end = po->end();
0551 switch(st)
0552 {
0553 default:
0554 case state::obj1: goto do_obj1;
0555 case state::obj2: goto do_obj2;
0556 case state::obj3: goto do_obj3;
0557 case state::obj4: goto do_obj4;
0558 case state::obj5: goto do_obj5;
0559 case state::obj6: goto do_obj6;
0560 break;
0561 }
0562 }
0563 do_obj1:
0564 if(BOOST_JSON_LIKELY(ss))
0565 ss.append('{');
0566 else
0567 return suspend(
0568 state::obj1, it, po);
0569 if(BOOST_JSON_UNLIKELY(
0570 it == end))
0571 goto do_obj6;
0572 for(;;)
0573 {
0574 cs0_ = {
0575 it->key().data(),
0576 it->key().size() };
0577 do_obj2:
0578 if(BOOST_JSON_UNLIKELY(
0579 ! write_string<StackEmpty>(ss)))
0580 return suspend(
0581 state::obj2, it, po);
0582 do_obj3:
0583 if(BOOST_JSON_LIKELY(ss))
0584 ss.append(':');
0585 else
0586 return suspend(
0587 state::obj3, it, po);
0588 do_obj4:
0589 jv_ = &it->value();
0590 if(BOOST_JSON_UNLIKELY(
0591 ! write_value<StackEmpty>(ss)))
0592 return suspend(
0593 state::obj4, it, po);
0594 ++it;
0595 if(BOOST_JSON_UNLIKELY(it == end))
0596 break;
0597 do_obj5:
0598 if(BOOST_JSON_LIKELY(ss))
0599 ss.append(',');
0600 else
0601 return suspend(
0602 state::obj5, it, po);
0603 }
0604 do_obj6:
0605 if(BOOST_JSON_LIKELY(ss))
0606 {
0607 ss.append('}');
0608 return true;
0609 }
0610 return suspend(
0611 state::obj6, it, po);
0612 }
0613
0614 template<bool StackEmpty>
0615 bool
0616 serializer::
0617 write_value(stream& ss)
0618 {
0619 if(StackEmpty || st_.empty())
0620 {
0621 auto const& jv(*jv_);
0622 switch(jv.kind())
0623 {
0624 default:
0625 case kind::object:
0626 po_ = &jv.get_object();
0627 return write_object<true>(ss);
0628
0629 case kind::array:
0630 pa_ = &jv.get_array();
0631 return write_array<true>(ss);
0632
0633 case kind::string:
0634 {
0635 auto const& js = jv.get_string();
0636 cs0_ = { js.data(), js.size() };
0637 return write_string<true>(ss);
0638 }
0639
0640 case kind::int64:
0641 case kind::uint64:
0642 case kind::double_:
0643 return write_number<true>(ss);
0644
0645 case kind::bool_:
0646 if(jv.get_bool())
0647 {
0648 if(BOOST_JSON_LIKELY(
0649 ss.remain() >= 4))
0650 {
0651 ss.append("true", 4);
0652 return true;
0653 }
0654 return write_true<true>(ss);
0655 }
0656 else
0657 {
0658 if(BOOST_JSON_LIKELY(
0659 ss.remain() >= 5))
0660 {
0661 ss.append("false", 5);
0662 return true;
0663 }
0664 return write_false<true>(ss);
0665 }
0666
0667 case kind::null:
0668 if(BOOST_JSON_LIKELY(
0669 ss.remain() >= 4))
0670 {
0671 ss.append("null", 4);
0672 return true;
0673 }
0674 return write_null<true>(ss);
0675 }
0676 }
0677 else
0678 {
0679 state st;
0680 st_.peek(st);
0681 switch(st)
0682 {
0683 default:
0684 case state::nul1: case state::nul2:
0685 case state::nul3: case state::nul4:
0686 return write_null<StackEmpty>(ss);
0687
0688 case state::tru1: case state::tru2:
0689 case state::tru3: case state::tru4:
0690 return write_true<StackEmpty>(ss);
0691
0692 case state::fal1: case state::fal2:
0693 case state::fal3: case state::fal4:
0694 case state::fal5:
0695 return write_false<StackEmpty>(ss);
0696
0697 case state::str1: case state::str2:
0698 case state::str3: case state::esc1:
0699 case state::utf1: case state::utf2:
0700 case state::utf3: case state::utf4:
0701 case state::utf5:
0702 return write_string<StackEmpty>(ss);
0703
0704 case state::num:
0705 return write_number<StackEmpty>(ss);
0706
0707 case state::arr1: case state::arr2:
0708 case state::arr3: case state::arr4:
0709 return write_array<StackEmpty>(ss);
0710
0711 case state::obj1: case state::obj2:
0712 case state::obj3: case state::obj4:
0713 case state::obj5: case state::obj6:
0714 return write_object<StackEmpty>(ss);
0715 }
0716 }
0717 }
0718
0719 string_view
0720 serializer::
0721 read_some(
0722 char* dest, std::size_t size)
0723 {
0724
0725
0726
0727
0728 BOOST_ASSERT(! done_);
0729
0730 stream ss(dest, size);
0731 if(st_.empty())
0732 (this->*fn0_)(ss);
0733 else
0734 (this->*fn1_)(ss);
0735 if(st_.empty())
0736 {
0737 done_ = true;
0738 jv_ = nullptr;
0739 }
0740 return string_view(
0741 dest, ss.used(dest));
0742 }
0743
0744
0745
0746 serializer::
0747 serializer( serialize_options const& opts ) noexcept
0748 : opts_(opts)
0749 {
0750
0751 BOOST_STATIC_ASSERT(
0752 sizeof(serializer::buf_) >= 7);
0753 }
0754
0755 void
0756 serializer::
0757 reset(value const* p) noexcept
0758 {
0759 pv_ = p;
0760 fn0_ = &serializer::write_value<true>;
0761 fn1_ = &serializer::write_value<false>;
0762
0763 jv_ = p;
0764 st_.clear();
0765 done_ = false;
0766 }
0767
0768 void
0769 serializer::
0770 reset(array const* p) noexcept
0771 {
0772 pa_ = p;
0773 fn0_ = &serializer::write_array<true>;
0774 fn1_ = &serializer::write_array<false>;
0775 st_.clear();
0776 done_ = false;
0777 }
0778
0779 void
0780 serializer::
0781 reset(object const* p) noexcept
0782 {
0783 po_ = p;
0784 fn0_ = &serializer::write_object<true>;
0785 fn1_ = &serializer::write_object<false>;
0786 st_.clear();
0787 done_ = false;
0788 }
0789
0790 void
0791 serializer::
0792 reset(string const* p) noexcept
0793 {
0794 cs0_ = { p->data(), p->size() };
0795 fn0_ = &serializer::write_string<true>;
0796 fn1_ = &serializer::write_string<false>;
0797 st_.clear();
0798 done_ = false;
0799 }
0800
0801 void
0802 serializer::
0803 reset(string_view sv) noexcept
0804 {
0805 cs0_ = { sv.data(), sv.size() };
0806 fn0_ = &serializer::write_string<true>;
0807 fn1_ = &serializer::write_string<false>;
0808 st_.clear();
0809 done_ = false;
0810 }
0811
0812 string_view
0813 serializer::
0814 read(char* dest, std::size_t size)
0815 {
0816 if(! jv_)
0817 {
0818 static value const null;
0819 jv_ = &null;
0820 }
0821 return read_some(dest, size);
0822 }
0823
0824 }
0825 }
0826
0827 #ifdef _MSC_VER
0828 #pragma warning(pop)
0829 #endif
0830
0831 #endif