Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 08:14:24

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/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) // conditional expression is constant
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     // opening quote
0257 do_str1:
0258     if(BOOST_JSON_LIKELY(ss))
0259         ss.append('\x22'); // '"'
0260     else
0261         return suspend(state::str1);
0262 
0263     // fast loop,
0264     // copy unescaped
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     // slow loop,
0297     // handle escapes
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     // If this goes off it means you forgot
0725     // to call reset() before seriailzing a
0726     // new value, or you never checked done()
0727     // to see if you should stop.
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     // ensure room for \uXXXX escape plus one
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 } // namespace json
0825 } // namespace boost
0826 
0827 #ifdef _MSC_VER
0828 #pragma warning(pop)
0829 #endif
0830 
0831 #endif