123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822 |
- //
- // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // Official repository: https://github.com/boostorg/json
- //
- #ifndef BOOST_JSON_IMPL_SERIALIZER_IPP
- #define BOOST_JSON_IMPL_SERIALIZER_IPP
- #include <boost/json/serializer.hpp>
- #include <boost/json/detail/format.hpp>
- #include <boost/json/detail/sse2.hpp>
- #include <ostream>
- #ifdef _MSC_VER
- #pragma warning(push)
- #pragma warning(disable: 4127) // conditional expression is constant
- #endif
- BOOST_JSON_NS_BEGIN
- enum class serializer::state : char
- {
- nul1, nul2, nul3, nul4,
- tru1, tru2, tru3, tru4,
- fal1, fal2, fal3, fal4, fal5,
- str1, str2, str3, str4, esc1,
- utf1, utf2, utf3, utf4, utf5,
- num,
- arr1, arr2, arr3, arr4,
- obj1, obj2, obj3, obj4, obj5, obj6
- };
- //----------------------------------------------------------
- serializer::
- ~serializer() noexcept = default;
- bool
- serializer::
- suspend(state st)
- {
- st_.push(st);
- return false;
- }
- bool
- serializer::
- suspend(
- state st,
- array::const_iterator it,
- array const* pa)
- {
- st_.push(pa);
- st_.push(it);
- st_.push(st);
- return false;
- }
- bool
- serializer::
- suspend(
- state st,
- object::const_iterator it,
- object const* po)
- {
- st_.push(po);
- st_.push(it);
- st_.push(st);
- return false;
- }
- template<bool StackEmpty>
- bool
- serializer::
- write_null(stream& ss0)
- {
- local_stream ss(ss0);
- if(! StackEmpty && ! st_.empty())
- {
- state st;
- st_.pop(st);
- switch(st)
- {
- default:
- case state::nul1: goto do_nul1;
- case state::nul2: goto do_nul2;
- case state::nul3: goto do_nul3;
- case state::nul4: goto do_nul4;
- }
- }
- do_nul1:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('n');
- else
- return suspend(state::nul1);
- do_nul2:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('u');
- else
- return suspend(state::nul2);
- do_nul3:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('l');
- else
- return suspend(state::nul3);
- do_nul4:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('l');
- else
- return suspend(state::nul4);
- return true;
- }
- template<bool StackEmpty>
- bool
- serializer::
- write_true(stream& ss0)
- {
- local_stream ss(ss0);
- if(! StackEmpty && ! st_.empty())
- {
- state st;
- st_.pop(st);
- switch(st)
- {
- default:
- case state::tru1: goto do_tru1;
- case state::tru2: goto do_tru2;
- case state::tru3: goto do_tru3;
- case state::tru4: goto do_tru4;
- }
- }
- do_tru1:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('t');
- else
- return suspend(state::tru1);
- do_tru2:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('r');
- else
- return suspend(state::tru2);
- do_tru3:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('u');
- else
- return suspend(state::tru3);
- do_tru4:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('e');
- else
- return suspend(state::tru4);
- return true;
- }
- template<bool StackEmpty>
- bool
- serializer::
- write_false(stream& ss0)
- {
- local_stream ss(ss0);
- if(! StackEmpty && ! st_.empty())
- {
- state st;
- st_.pop(st);
- switch(st)
- {
- default:
- case state::fal1: goto do_fal1;
- case state::fal2: goto do_fal2;
- case state::fal3: goto do_fal3;
- case state::fal4: goto do_fal4;
- case state::fal5: goto do_fal5;
- }
- }
- do_fal1:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('f');
- else
- return suspend(state::fal1);
- do_fal2:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('a');
- else
- return suspend(state::fal2);
- do_fal3:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('l');
- else
- return suspend(state::fal3);
- do_fal4:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('s');
- else
- return suspend(state::fal4);
- do_fal5:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('e');
- else
- return suspend(state::fal5);
- return true;
- }
- template<bool StackEmpty>
- bool
- serializer::
- write_string(stream& ss0)
- {
- local_stream ss(ss0);
- local_const_stream cs(cs0_);
- if(! StackEmpty && ! st_.empty())
- {
- state st;
- st_.pop(st);
- switch(st)
- {
- default:
- case state::str1: goto do_str1;
- case state::str2: goto do_str2;
- case state::str3: goto do_str3;
- case state::str4: goto do_str4;
- case state::esc1: goto do_esc1;
- case state::utf1: goto do_utf1;
- case state::utf2: goto do_utf2;
- case state::utf3: goto do_utf3;
- case state::utf4: goto do_utf4;
- case state::utf5: goto do_utf5;
- }
- }
- static constexpr char hex[] = "0123456789abcdef";
- static constexpr char esc[] =
- "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
- "\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
- "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0"
- "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
- "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
- "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
- "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
- "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
- // opening quote
- do_str1:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('\x22'); // '"'
- else
- return suspend(state::str1);
- // fast loop,
- // copy unescaped
- do_str2:
- if(BOOST_JSON_LIKELY(ss))
- {
- std::size_t n = cs.remain();
- if(BOOST_JSON_LIKELY(n > 0))
- {
- if(ss.remain() > n)
- n = detail::count_unescaped(
- cs.data(), n);
- else
- n = detail::count_unescaped(
- cs.data(), ss.remain());
- if(n > 0)
- {
- ss.append(cs.data(), n);
- cs.skip(n);
- if(! ss)
- return suspend(state::str2);
- }
- }
- else
- {
- ss.append('\x22'); // '"'
- return true;
- }
- }
- else
- {
- return suspend(state::str2);
- }
- // slow loop,
- // handle escapes
- do_str3:
- while(BOOST_JSON_LIKELY(ss))
- {
- if(BOOST_JSON_LIKELY(cs))
- {
- auto const ch = *cs;
- auto const c = esc[static_cast<
- unsigned char>(ch)];
- ++cs;
- if(! c)
- {
- ss.append(ch);
- }
- else if(c != 'u')
- {
- ss.append('\\');
- if(BOOST_JSON_LIKELY(ss))
- {
- ss.append(c);
- }
- else
- {
- buf_[0] = c;
- return suspend(
- state::esc1);
- }
- }
- else
- {
- if(BOOST_JSON_LIKELY(
- ss.remain() >= 6))
- {
- ss.append("\\u00", 4);
- ss.append(hex[static_cast<
- unsigned char>(ch) >> 4]);
- ss.append(hex[static_cast<
- unsigned char>(ch) & 15]);
- }
- else
- {
- ss.append('\\');
- buf_[0] = hex[static_cast<
- unsigned char>(ch) >> 4];
- buf_[1] = hex[static_cast<
- unsigned char>(ch) & 15];
- goto do_utf1;
- }
- }
- }
- else
- {
- ss.append('\x22'); // '"'
- return true;
- }
- }
- return suspend(state::str3);
- do_str4:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('\x22'); // '"'
- else
- return suspend(state::str4);
- do_esc1:
- if(BOOST_JSON_LIKELY(ss))
- ss.append(buf_[0]);
- else
- return suspend(state::esc1);
- goto do_str3;
- do_utf1:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('u');
- else
- return suspend(state::utf1);
- do_utf2:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('0');
- else
- return suspend(state::utf2);
- do_utf3:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('0');
- else
- return suspend(state::utf3);
- do_utf4:
- if(BOOST_JSON_LIKELY(ss))
- ss.append(buf_[0]);
- else
- return suspend(state::utf4);
- do_utf5:
- if(BOOST_JSON_LIKELY(ss))
- ss.append(buf_[1]);
- else
- return suspend(state::utf5);
- goto do_str3;
- }
- template<bool StackEmpty>
- bool
- serializer::
- write_number(stream& ss0)
- {
- local_stream ss(ss0);
- if(StackEmpty || st_.empty())
- {
- switch(jv_->kind())
- {
- default:
- case kind::int64:
- if(BOOST_JSON_LIKELY(
- ss.remain() >=
- detail::max_number_chars))
- {
- ss.advance(detail::format_int64(
- ss.data(), jv_->get_int64()));
- return true;
- }
- cs0_ = { buf_, detail::format_int64(
- buf_, jv_->get_int64()) };
- break;
- case kind::uint64:
- if(BOOST_JSON_LIKELY(
- ss.remain() >=
- detail::max_number_chars))
- {
- ss.advance(detail::format_uint64(
- ss.data(), jv_->get_uint64()));
- return true;
- }
- cs0_ = { buf_, detail::format_uint64(
- buf_, jv_->get_uint64()) };
- break;
- case kind::double_:
- if(BOOST_JSON_LIKELY(
- ss.remain() >=
- detail::max_number_chars))
- {
- ss.advance(detail::format_double(
- ss.data(), jv_->get_double()));
- return true;
- }
- cs0_ = { buf_, detail::format_double(
- buf_, jv_->get_double()) };
- break;
- }
- }
- else
- {
- state st;
- st_.pop(st);
- BOOST_ASSERT(
- st == state::num);
- }
- auto const n = ss.remain();
- if(n < cs0_.remain())
- {
- ss.append(cs0_.data(), n);
- cs0_.skip(n);
- return suspend(state::num);
- }
- ss.append(
- cs0_.data(), cs0_.remain());
- return true;
- }
- template<bool StackEmpty>
- bool
- serializer::
- write_array(stream& ss0)
- {
- array const* pa;
- local_stream ss(ss0);
- array::const_iterator it;
- array::const_iterator end;
- if(StackEmpty || st_.empty())
- {
- pa = pa_;
- it = pa->begin();
- end = pa->end();
- }
- else
- {
- state st;
- st_.pop(st);
- st_.pop(it);
- st_.pop(pa);
- end = pa->end();
- switch(st)
- {
- default:
- case state::arr1: goto do_arr1;
- case state::arr2: goto do_arr2;
- case state::arr3: goto do_arr3;
- case state::arr4: goto do_arr4;
- break;
- }
- }
- do_arr1:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('[');
- else
- return suspend(
- state::arr1, it, pa);
- if(it == end)
- goto do_arr4;
- for(;;)
- {
- do_arr2:
- jv_ = &*it;
- if(! write_value<StackEmpty>(ss))
- return suspend(
- state::arr2, it, pa);
- if(BOOST_JSON_UNLIKELY(
- ++it == end))
- break;
- do_arr3:
- if(BOOST_JSON_LIKELY(ss))
- ss.append(',');
- else
- return suspend(
- state::arr3, it, pa);
- }
- do_arr4:
- if(BOOST_JSON_LIKELY(ss))
- ss.append(']');
- else
- return suspend(
- state::arr4, it, pa);
- return true;
- }
- template<bool StackEmpty>
- bool
- serializer::
- write_object(stream& ss0)
- {
- object const* po;
- local_stream ss(ss0);
- object::const_iterator it;
- object::const_iterator end;
- if(StackEmpty || st_.empty())
- {
- po = po_;
- it = po->begin();
- end = po->end();
- }
- else
- {
- state st;
- st_.pop(st);
- st_.pop(it);
- st_.pop(po);
- end = po->end();
- switch(st)
- {
- default:
- case state::obj1: goto do_obj1;
- case state::obj2: goto do_obj2;
- case state::obj3: goto do_obj3;
- case state::obj4: goto do_obj4;
- case state::obj5: goto do_obj5;
- case state::obj6: goto do_obj6;
- break;
- }
- }
- do_obj1:
- if(BOOST_JSON_LIKELY(ss))
- ss.append('{');
- else
- return suspend(
- state::obj1, it, po);
- if(BOOST_JSON_UNLIKELY(
- it == end))
- goto do_obj6;
- for(;;)
- {
- cs0_ = {
- it->key().data(),
- it->key().size() };
- do_obj2:
- if(BOOST_JSON_UNLIKELY(
- ! write_string<StackEmpty>(ss)))
- return suspend(
- state::obj2, it, po);
- do_obj3:
- if(BOOST_JSON_LIKELY(ss))
- ss.append(':');
- else
- return suspend(
- state::obj3, it, po);
- do_obj4:
- jv_ = &it->value();
- if(BOOST_JSON_UNLIKELY(
- ! write_value<StackEmpty>(ss)))
- return suspend(
- state::obj4, it, po);
- ++it;
- if(BOOST_JSON_UNLIKELY(it == end))
- break;
- do_obj5:
- if(BOOST_JSON_LIKELY(ss))
- ss.append(',');
- else
- return suspend(
- state::obj5, it, po);
- }
- do_obj6:
- if(BOOST_JSON_LIKELY(ss))
- {
- ss.append('}');
- return true;
- }
- return suspend(
- state::obj6, it, po);
- }
- template<bool StackEmpty>
- bool
- serializer::
- write_value(stream& ss)
- {
- if(StackEmpty || st_.empty())
- {
- auto const& jv(*jv_);
- switch(jv.kind())
- {
- default:
- case kind::object:
- po_ = &jv.get_object();
- return write_object<true>(ss);
- case kind::array:
- pa_ = &jv.get_array();
- return write_array<true>(ss);
- case kind::string:
- {
- auto const& js = jv.get_string();
- cs0_ = { js.data(), js.size() };
- return write_string<true>(ss);
- }
- case kind::int64:
- case kind::uint64:
- case kind::double_:
- return write_number<true>(ss);
- case kind::bool_:
- if(jv.get_bool())
- {
- if(BOOST_JSON_LIKELY(
- ss.remain() >= 4))
- {
- ss.append("true", 4);
- return true;
- }
- return write_true<true>(ss);
- }
- else
- {
- if(BOOST_JSON_LIKELY(
- ss.remain() >= 5))
- {
- ss.append("false", 5);
- return true;
- }
- return write_false<true>(ss);
- }
- case kind::null:
- if(BOOST_JSON_LIKELY(
- ss.remain() >= 4))
- {
- ss.append("null", 4);
- return true;
- }
- return write_null<true>(ss);
- }
- }
- else
- {
- state st;
- st_.peek(st);
- switch(st)
- {
- default:
- case state::nul1: case state::nul2:
- case state::nul3: case state::nul4:
- return write_null<StackEmpty>(ss);
- case state::tru1: case state::tru2:
- case state::tru3: case state::tru4:
- return write_true<StackEmpty>(ss);
- case state::fal1: case state::fal2:
- case state::fal3: case state::fal4:
- case state::fal5:
- return write_false<StackEmpty>(ss);
- case state::str1: case state::str2:
- case state::str3: case state::str4:
- case state::esc1:
- case state::utf1: case state::utf2:
- case state::utf3: case state::utf4:
- case state::utf5:
- return write_string<StackEmpty>(ss);
- case state::num:
- return write_number<StackEmpty>(ss);
- case state::arr1: case state::arr2:
- case state::arr3: case state::arr4:
- return write_array<StackEmpty>(ss);
- case state::obj1: case state::obj2:
- case state::obj3: case state::obj4:
- case state::obj5: case state::obj6:
- return write_object<StackEmpty>(ss);
- }
- }
- }
- string_view
- serializer::
- read_some(
- char* dest, std::size_t size)
- {
- // If this goes off it means you forgot
- // to call reset() before seriailzing a
- // new value, or you never checked done()
- // to see if you should stop.
- BOOST_ASSERT(! done_);
- stream ss(dest, size);
- if(st_.empty())
- (this->*fn0_)(ss);
- else
- (this->*fn1_)(ss);
- if(st_.empty())
- {
- done_ = true;
- jv_ = nullptr;
- }
- return string_view(
- dest, ss.used(dest));
- }
- //----------------------------------------------------------
- serializer::
- serializer() noexcept
- {
- // ensure room for \uXXXX escape plus one
- BOOST_STATIC_ASSERT(
- sizeof(serializer::buf_) >= 7);
- }
- void
- serializer::
- reset(value const* p) noexcept
- {
- pv_ = p;
- fn0_ = &serializer::write_value<true>;
- fn1_ = &serializer::write_value<false>;
- jv_ = p;
- st_.clear();
- done_ = false;
- }
- void
- serializer::
- reset(array const* p) noexcept
- {
- pa_ = p;
- fn0_ = &serializer::write_array<true>;
- fn1_ = &serializer::write_array<false>;
- st_.clear();
- done_ = false;
- }
- void
- serializer::
- reset(object const* p) noexcept
- {
- po_ = p;
- fn0_ = &serializer::write_object<true>;
- fn1_ = &serializer::write_object<false>;
- st_.clear();
- done_ = false;
- }
- void
- serializer::
- reset(string const* p) noexcept
- {
- cs0_ = { p->data(), p->size() };
- fn0_ = &serializer::write_string<true>;
- fn1_ = &serializer::write_string<false>;
- st_.clear();
- done_ = false;
- }
- void
- serializer::
- reset(string_view sv) noexcept
- {
- cs0_ = { sv.data(), sv.size() };
- fn0_ = &serializer::write_string<true>;
- fn1_ = &serializer::write_string<false>;
- st_.clear();
- done_ = false;
- }
- string_view
- serializer::
- read(char* dest, std::size_t size)
- {
- if(! jv_)
- {
- static value const null;
- jv_ = &null;
- }
- return read_some(dest, size);
- }
- BOOST_JSON_NS_END
- #ifdef _MSC_VER
- #pragma warning(pop)
- #endif
- #endif
|