Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:02

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, 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     // opening quote
0258 do_str1:
0259     if(BOOST_JSON_LIKELY(ss))
0260         ss.append('\x22'); // '"'
0261     else
0262         return suspend(state::str1);
0263 
0264     // fast loop,
0265     // copy unescaped
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     // slow loop,
0298     // handle escapes
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     // If this goes off it means you forgot
0733     // to call reset() before seriailzing a
0734     // new value, or you never checked done()
0735     // to see if you should stop.
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     // ensure room for \uXXXX escape plus one
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 } // namespace json
0833 } // namespace boost
0834 
0835 #ifdef _MSC_VER
0836 #pragma warning(pop)
0837 #endif
0838 
0839 #endif