File indexing completed on 2025-01-18 09:39:02
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, str4, esc1,
0032 utf1, 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::str4: goto do_str4;
0238 case state::esc1: goto do_esc1;
0239 case state::utf1: goto do_utf1;
0240 case state::utf2: goto do_utf2;
0241 case state::utf3: goto do_utf3;
0242 case state::utf4: goto do_utf4;
0243 case state::utf5: goto do_utf5;
0244 }
0245 }
0246 static constexpr char hex[] = "0123456789abcdef";
0247 static constexpr char esc[] =
0248 "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
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"
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 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
0256
0257
0258 do_str1:
0259 if(BOOST_JSON_LIKELY(ss))
0260 ss.append('\x22');
0261 else
0262 return suspend(state::str1);
0263
0264
0265
0266 do_str2:
0267 if(BOOST_JSON_LIKELY(ss))
0268 {
0269 std::size_t n = cs.remain();
0270 if(BOOST_JSON_LIKELY(n > 0))
0271 {
0272 if(ss.remain() > n)
0273 n = detail::count_unescaped(
0274 cs.data(), n);
0275 else
0276 n = detail::count_unescaped(
0277 cs.data(), ss.remain());
0278 if(n > 0)
0279 {
0280 ss.append(cs.data(), n);
0281 cs.skip(n);
0282 if(! ss)
0283 return suspend(state::str2);
0284 }
0285 }
0286 else
0287 {
0288 ss.append('\x22');
0289 return true;
0290 }
0291 }
0292 else
0293 {
0294 return suspend(state::str2);
0295 }
0296
0297
0298
0299 do_str3:
0300 while(BOOST_JSON_LIKELY(ss))
0301 {
0302 if(BOOST_JSON_LIKELY(cs))
0303 {
0304 auto const ch = *cs;
0305 auto const c = esc[static_cast<
0306 unsigned char>(ch)];
0307 ++cs;
0308 if(! c)
0309 {
0310 ss.append(ch);
0311 }
0312 else if(c != 'u')
0313 {
0314 ss.append('\\');
0315 if(BOOST_JSON_LIKELY(ss))
0316 {
0317 ss.append(c);
0318 }
0319 else
0320 {
0321 buf_[0] = c;
0322 return suspend(
0323 state::esc1);
0324 }
0325 }
0326 else
0327 {
0328 if(BOOST_JSON_LIKELY(
0329 ss.remain() >= 6))
0330 {
0331 ss.append("\\u00", 4);
0332 ss.append(hex[static_cast<
0333 unsigned char>(ch) >> 4]);
0334 ss.append(hex[static_cast<
0335 unsigned char>(ch) & 15]);
0336 }
0337 else
0338 {
0339 ss.append('\\');
0340 buf_[0] = hex[static_cast<
0341 unsigned char>(ch) >> 4];
0342 buf_[1] = hex[static_cast<
0343 unsigned char>(ch) & 15];
0344 goto do_utf1;
0345 }
0346 }
0347 }
0348 else
0349 {
0350 ss.append('\x22');
0351 return true;
0352 }
0353 }
0354 return suspend(state::str3);
0355
0356 do_str4:
0357 if(BOOST_JSON_LIKELY(ss))
0358 ss.append('\x22');
0359 else
0360 return suspend(state::str4);
0361
0362 do_esc1:
0363 if(BOOST_JSON_LIKELY(ss))
0364 ss.append(buf_[0]);
0365 else
0366 return suspend(state::esc1);
0367 goto do_str3;
0368
0369 do_utf1:
0370 if(BOOST_JSON_LIKELY(ss))
0371 ss.append('u');
0372 else
0373 return suspend(state::utf1);
0374 do_utf2:
0375 if(BOOST_JSON_LIKELY(ss))
0376 ss.append('0');
0377 else
0378 return suspend(state::utf2);
0379 do_utf3:
0380 if(BOOST_JSON_LIKELY(ss))
0381 ss.append('0');
0382 else
0383 return suspend(state::utf3);
0384 do_utf4:
0385 if(BOOST_JSON_LIKELY(ss))
0386 ss.append(buf_[0]);
0387 else
0388 return suspend(state::utf4);
0389 do_utf5:
0390 if(BOOST_JSON_LIKELY(ss))
0391 ss.append(buf_[1]);
0392 else
0393 return suspend(state::utf5);
0394 goto do_str3;
0395 }
0396
0397 template<bool StackEmpty>
0398 bool
0399 serializer::
0400 write_number(stream& ss0)
0401 {
0402 local_stream ss(ss0);
0403 if(StackEmpty || st_.empty())
0404 {
0405 switch(jv_->kind())
0406 {
0407 default:
0408 case kind::int64:
0409 if(BOOST_JSON_LIKELY(
0410 ss.remain() >=
0411 detail::max_number_chars))
0412 {
0413 ss.advance(detail::format_int64(
0414 ss.data(), jv_->get_int64()));
0415 return true;
0416 }
0417 cs0_ = { buf_, detail::format_int64(
0418 buf_, jv_->get_int64()) };
0419 break;
0420
0421 case kind::uint64:
0422 if(BOOST_JSON_LIKELY(
0423 ss.remain() >=
0424 detail::max_number_chars))
0425 {
0426 ss.advance(detail::format_uint64(
0427 ss.data(), jv_->get_uint64()));
0428 return true;
0429 }
0430 cs0_ = { buf_, detail::format_uint64(
0431 buf_, jv_->get_uint64()) };
0432 break;
0433
0434 case kind::double_:
0435 if(BOOST_JSON_LIKELY(
0436 ss.remain() >=
0437 detail::max_number_chars))
0438 {
0439 ss.advance(
0440 detail::format_double(
0441 ss.data(),
0442 jv_->get_double(),
0443 opts_.allow_infinity_and_nan));
0444 return true;
0445 }
0446 cs0_ = { buf_, detail::format_double(
0447 buf_, jv_->get_double(), opts_.allow_infinity_and_nan) };
0448 break;
0449 }
0450 }
0451 else
0452 {
0453 state st;
0454 st_.pop(st);
0455 BOOST_ASSERT(
0456 st == state::num);
0457 }
0458 auto const n = ss.remain();
0459 if(n < cs0_.remain())
0460 {
0461 ss.append(cs0_.data(), n);
0462 cs0_.skip(n);
0463 return suspend(state::num);
0464 }
0465 ss.append(
0466 cs0_.data(), cs0_.remain());
0467 return true;
0468 }
0469
0470 template<bool StackEmpty>
0471 bool
0472 serializer::
0473 write_array(stream& ss0)
0474 {
0475 array const* pa;
0476 local_stream ss(ss0);
0477 array::const_iterator it;
0478 array::const_iterator end;
0479 if(StackEmpty || st_.empty())
0480 {
0481 pa = pa_;
0482 it = pa->begin();
0483 end = pa->end();
0484 }
0485 else
0486 {
0487 state st;
0488 st_.pop(st);
0489 st_.pop(it);
0490 st_.pop(pa);
0491 end = pa->end();
0492 switch(st)
0493 {
0494 default:
0495 case state::arr1: goto do_arr1;
0496 case state::arr2: goto do_arr2;
0497 case state::arr3: goto do_arr3;
0498 case state::arr4: goto do_arr4;
0499 break;
0500 }
0501 }
0502 do_arr1:
0503 if(BOOST_JSON_LIKELY(ss))
0504 ss.append('[');
0505 else
0506 return suspend(
0507 state::arr1, it, pa);
0508 if(it == end)
0509 goto do_arr4;
0510 for(;;)
0511 {
0512 do_arr2:
0513 jv_ = &*it;
0514 if(! write_value<StackEmpty>(ss))
0515 return suspend(
0516 state::arr2, it, pa);
0517 if(BOOST_JSON_UNLIKELY(
0518 ++it == end))
0519 break;
0520 do_arr3:
0521 if(BOOST_JSON_LIKELY(ss))
0522 ss.append(',');
0523 else
0524 return suspend(
0525 state::arr3, it, pa);
0526 }
0527 do_arr4:
0528 if(BOOST_JSON_LIKELY(ss))
0529 ss.append(']');
0530 else
0531 return suspend(
0532 state::arr4, it, pa);
0533 return true;
0534 }
0535
0536 template<bool StackEmpty>
0537 bool
0538 serializer::
0539 write_object(stream& ss0)
0540 {
0541 object const* po;
0542 local_stream ss(ss0);
0543 object::const_iterator it;
0544 object::const_iterator end;
0545 if(StackEmpty || st_.empty())
0546 {
0547 po = po_;
0548 it = po->begin();
0549 end = po->end();
0550 }
0551 else
0552 {
0553 state st;
0554 st_.pop(st);
0555 st_.pop(it);
0556 st_.pop(po);
0557 end = po->end();
0558 switch(st)
0559 {
0560 default:
0561 case state::obj1: goto do_obj1;
0562 case state::obj2: goto do_obj2;
0563 case state::obj3: goto do_obj3;
0564 case state::obj4: goto do_obj4;
0565 case state::obj5: goto do_obj5;
0566 case state::obj6: goto do_obj6;
0567 break;
0568 }
0569 }
0570 do_obj1:
0571 if(BOOST_JSON_LIKELY(ss))
0572 ss.append('{');
0573 else
0574 return suspend(
0575 state::obj1, it, po);
0576 if(BOOST_JSON_UNLIKELY(
0577 it == end))
0578 goto do_obj6;
0579 for(;;)
0580 {
0581 cs0_ = {
0582 it->key().data(),
0583 it->key().size() };
0584 do_obj2:
0585 if(BOOST_JSON_UNLIKELY(
0586 ! write_string<StackEmpty>(ss)))
0587 return suspend(
0588 state::obj2, it, po);
0589 do_obj3:
0590 if(BOOST_JSON_LIKELY(ss))
0591 ss.append(':');
0592 else
0593 return suspend(
0594 state::obj3, it, po);
0595 do_obj4:
0596 jv_ = &it->value();
0597 if(BOOST_JSON_UNLIKELY(
0598 ! write_value<StackEmpty>(ss)))
0599 return suspend(
0600 state::obj4, it, po);
0601 ++it;
0602 if(BOOST_JSON_UNLIKELY(it == end))
0603 break;
0604 do_obj5:
0605 if(BOOST_JSON_LIKELY(ss))
0606 ss.append(',');
0607 else
0608 return suspend(
0609 state::obj5, it, po);
0610 }
0611 do_obj6:
0612 if(BOOST_JSON_LIKELY(ss))
0613 {
0614 ss.append('}');
0615 return true;
0616 }
0617 return suspend(
0618 state::obj6, it, po);
0619 }
0620
0621 template<bool StackEmpty>
0622 bool
0623 serializer::
0624 write_value(stream& ss)
0625 {
0626 if(StackEmpty || st_.empty())
0627 {
0628 auto const& jv(*jv_);
0629 switch(jv.kind())
0630 {
0631 default:
0632 case kind::object:
0633 po_ = &jv.get_object();
0634 return write_object<true>(ss);
0635
0636 case kind::array:
0637 pa_ = &jv.get_array();
0638 return write_array<true>(ss);
0639
0640 case kind::string:
0641 {
0642 auto const& js = jv.get_string();
0643 cs0_ = { js.data(), js.size() };
0644 return write_string<true>(ss);
0645 }
0646
0647 case kind::int64:
0648 case kind::uint64:
0649 case kind::double_:
0650 return write_number<true>(ss);
0651
0652 case kind::bool_:
0653 if(jv.get_bool())
0654 {
0655 if(BOOST_JSON_LIKELY(
0656 ss.remain() >= 4))
0657 {
0658 ss.append("true", 4);
0659 return true;
0660 }
0661 return write_true<true>(ss);
0662 }
0663 else
0664 {
0665 if(BOOST_JSON_LIKELY(
0666 ss.remain() >= 5))
0667 {
0668 ss.append("false", 5);
0669 return true;
0670 }
0671 return write_false<true>(ss);
0672 }
0673
0674 case kind::null:
0675 if(BOOST_JSON_LIKELY(
0676 ss.remain() >= 4))
0677 {
0678 ss.append("null", 4);
0679 return true;
0680 }
0681 return write_null<true>(ss);
0682 }
0683 }
0684 else
0685 {
0686 state st;
0687 st_.peek(st);
0688 switch(st)
0689 {
0690 default:
0691 case state::nul1: case state::nul2:
0692 case state::nul3: case state::nul4:
0693 return write_null<StackEmpty>(ss);
0694
0695 case state::tru1: case state::tru2:
0696 case state::tru3: case state::tru4:
0697 return write_true<StackEmpty>(ss);
0698
0699 case state::fal1: case state::fal2:
0700 case state::fal3: case state::fal4:
0701 case state::fal5:
0702 return write_false<StackEmpty>(ss);
0703
0704 case state::str1: case state::str2:
0705 case state::str3: case state::str4:
0706 case state::esc1:
0707 case state::utf1: case state::utf2:
0708 case state::utf3: case state::utf4:
0709 case state::utf5:
0710 return write_string<StackEmpty>(ss);
0711
0712 case state::num:
0713 return write_number<StackEmpty>(ss);
0714
0715 case state::arr1: case state::arr2:
0716 case state::arr3: case state::arr4:
0717 return write_array<StackEmpty>(ss);
0718
0719 case state::obj1: case state::obj2:
0720 case state::obj3: case state::obj4:
0721 case state::obj5: case state::obj6:
0722 return write_object<StackEmpty>(ss);
0723 }
0724 }
0725 }
0726
0727 string_view
0728 serializer::
0729 read_some(
0730 char* dest, std::size_t size)
0731 {
0732
0733
0734
0735
0736 BOOST_ASSERT(! done_);
0737
0738 stream ss(dest, size);
0739 if(st_.empty())
0740 (this->*fn0_)(ss);
0741 else
0742 (this->*fn1_)(ss);
0743 if(st_.empty())
0744 {
0745 done_ = true;
0746 jv_ = nullptr;
0747 }
0748 return string_view(
0749 dest, ss.used(dest));
0750 }
0751
0752
0753
0754 serializer::
0755 serializer( serialize_options const& opts ) noexcept
0756 : opts_(opts)
0757 {
0758
0759 BOOST_STATIC_ASSERT(
0760 sizeof(serializer::buf_) >= 7);
0761 }
0762
0763 void
0764 serializer::
0765 reset(value const* p) noexcept
0766 {
0767 pv_ = p;
0768 fn0_ = &serializer::write_value<true>;
0769 fn1_ = &serializer::write_value<false>;
0770
0771 jv_ = p;
0772 st_.clear();
0773 done_ = false;
0774 }
0775
0776 void
0777 serializer::
0778 reset(array const* p) noexcept
0779 {
0780 pa_ = p;
0781 fn0_ = &serializer::write_array<true>;
0782 fn1_ = &serializer::write_array<false>;
0783 st_.clear();
0784 done_ = false;
0785 }
0786
0787 void
0788 serializer::
0789 reset(object const* p) noexcept
0790 {
0791 po_ = p;
0792 fn0_ = &serializer::write_object<true>;
0793 fn1_ = &serializer::write_object<false>;
0794 st_.clear();
0795 done_ = false;
0796 }
0797
0798 void
0799 serializer::
0800 reset(string const* p) noexcept
0801 {
0802 cs0_ = { p->data(), p->size() };
0803 fn0_ = &serializer::write_string<true>;
0804 fn1_ = &serializer::write_string<false>;
0805 st_.clear();
0806 done_ = false;
0807 }
0808
0809 void
0810 serializer::
0811 reset(string_view sv) noexcept
0812 {
0813 cs0_ = { sv.data(), sv.size() };
0814 fn0_ = &serializer::write_string<true>;
0815 fn1_ = &serializer::write_string<false>;
0816 st_.clear();
0817 done_ = false;
0818 }
0819
0820 string_view
0821 serializer::
0822 read(char* dest, std::size_t size)
0823 {
0824 if(! jv_)
0825 {
0826 static value const null;
0827 jv_ = &null;
0828 }
0829 return read_some(dest, size);
0830 }
0831
0832 }
0833 }
0834
0835 #ifdef _MSC_VER
0836 #pragma warning(pop)
0837 #endif
0838
0839 #endif