123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714 |
- //
- // Copyright (c) 2019 Vinnie Falco ([email protected])
- //
- // 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_VALUE_IPP
- #define BOOST_JSON_IMPL_VALUE_IPP
- #include <boost/container_hash/hash.hpp>
- #include <boost/json/value.hpp>
- #include <boost/json/parser.hpp>
- #include <cstring>
- #include <istream>
- #include <limits>
- #include <new>
- #include <utility>
- namespace boost {
- namespace json {
- namespace
- {
- int parse_depth_xalloc = std::ios::xalloc();
- int parse_flags_xalloc = std::ios::xalloc();
- struct value_hasher
- {
- std::size_t& seed;
- template< class T >
- void operator()( T&& t ) const noexcept
- {
- boost::hash_combine( seed, t );
- }
- };
- enum class stream_parse_flags
- {
- allow_comments = 1 << 0,
- allow_trailing_commas = 1 << 1,
- allow_invalid_utf8 = 1 << 2,
- };
- long
- to_bitmask( parse_options const& opts )
- {
- using E = stream_parse_flags;
- return
- (opts.allow_comments ?
- static_cast<long>(E::allow_comments) : 0) |
- (opts.allow_trailing_commas ?
- static_cast<long>(E::allow_trailing_commas) : 0) |
- (opts.allow_invalid_utf8 ?
- static_cast<long>(E::allow_invalid_utf8) : 0);
- }
- parse_options
- get_parse_options( std::istream& is )
- {
- long const flags = is.iword(parse_flags_xalloc);
- using E = stream_parse_flags;
- parse_options opts;
- opts.allow_comments =
- flags & static_cast<long>(E::allow_comments) ? true : false;
- opts.allow_trailing_commas =
- flags & static_cast<long>(E::allow_trailing_commas) ? true : false;
- opts.allow_invalid_utf8 =
- flags & static_cast<long>(E::allow_invalid_utf8) ? true : false;
- return opts;
- }
- } // namespace
- value::
- ~value() noexcept
- {
- switch(kind())
- {
- case json::kind::null:
- case json::kind::bool_:
- case json::kind::int64:
- case json::kind::uint64:
- case json::kind::double_:
- sca_.~scalar();
- break;
- case json::kind::string:
- str_.~string();
- break;
- case json::kind::array:
- arr_.~array();
- break;
- case json::kind::object:
- obj_.~object();
- break;
- }
- }
- value::
- value(
- value const& other,
- storage_ptr sp)
- {
- switch(other.kind())
- {
- case json::kind::null:
- ::new(&sca_) scalar(
- std::move(sp));
- break;
- case json::kind::bool_:
- ::new(&sca_) scalar(
- other.sca_.b,
- std::move(sp));
- break;
- case json::kind::int64:
- ::new(&sca_) scalar(
- other.sca_.i,
- std::move(sp));
- break;
- case json::kind::uint64:
- ::new(&sca_) scalar(
- other.sca_.u,
- std::move(sp));
- break;
- case json::kind::double_:
- ::new(&sca_) scalar(
- other.sca_.d,
- std::move(sp));
- break;
- case json::kind::string:
- ::new(&str_) string(
- other.str_,
- std::move(sp));
- break;
- case json::kind::array:
- ::new(&arr_) array(
- other.arr_,
- std::move(sp));
- break;
- case json::kind::object:
- ::new(&obj_) object(
- other.obj_,
- std::move(sp));
- break;
- }
- }
- value::
- value(value&& other) noexcept
- {
- relocate(this, other);
- ::new(&other.sca_) scalar(sp_);
- }
- value::
- value(
- value&& other,
- storage_ptr sp)
- {
- switch(other.kind())
- {
- case json::kind::null:
- ::new(&sca_) scalar(
- std::move(sp));
- break;
- case json::kind::bool_:
- ::new(&sca_) scalar(
- other.sca_.b, std::move(sp));
- break;
- case json::kind::int64:
- ::new(&sca_) scalar(
- other.sca_.i, std::move(sp));
- break;
- case json::kind::uint64:
- ::new(&sca_) scalar(
- other.sca_.u, std::move(sp));
- break;
- case json::kind::double_:
- ::new(&sca_) scalar(
- other.sca_.d, std::move(sp));
- break;
- case json::kind::string:
- ::new(&str_) string(
- std::move(other.str_),
- std::move(sp));
- break;
- case json::kind::array:
- ::new(&arr_) array(
- std::move(other.arr_),
- std::move(sp));
- break;
- case json::kind::object:
- ::new(&obj_) object(
- std::move(other.obj_),
- std::move(sp));
- break;
- }
- }
- //----------------------------------------------------------
- //
- // Conversion
- //
- //----------------------------------------------------------
- value::
- value(
- std::initializer_list<value_ref> init,
- storage_ptr sp)
- {
- if(value_ref::maybe_object(init))
- {
- ::new(&obj_) object(
- value_ref::make_object(
- init, std::move(sp)));
- }
- else
- {
- #ifndef BOOST_JSON_LEGACY_INIT_LIST_BEHAVIOR
- if( init.size() == 1 )
- {
- ::new(&sca_) scalar();
- value temp = init.begin()->make_value( std::move(sp) );
- swap(temp);
- }
- else
- #endif
- {
- ::new(&arr_) array(
- value_ref::make_array(
- init, std::move(sp)));
- }
- }
- }
- //----------------------------------------------------------
- //
- // Assignment
- //
- //----------------------------------------------------------
- value&
- value::
- operator=(value const& other)
- {
- value(other,
- storage()).swap(*this);
- return *this;
- }
- value&
- value::
- operator=(value&& other)
- {
- value(std::move(other),
- storage()).swap(*this);
- return *this;
- }
- value&
- value::
- operator=(
- std::initializer_list<value_ref> init)
- {
- value(init,
- storage()).swap(*this);
- return *this;
- }
- value&
- value::
- operator=(string_view s)
- {
- value(s, storage()).swap(*this);
- return *this;
- }
- value&
- value::
- operator=(char const* s)
- {
- value(s, storage()).swap(*this);
- return *this;
- }
- value&
- value::
- operator=(string const& str)
- {
- value(str, storage()).swap(*this);
- return *this;
- }
- value&
- value::
- operator=(string&& str)
- {
- value(std::move(str),
- storage()).swap(*this);
- return *this;
- }
- value&
- value::
- operator=(array const& arr)
- {
- value(arr, storage()).swap(*this);
- return *this;
- }
- value&
- value::
- operator=(array&& arr)
- {
- value(std::move(arr),
- storage()).swap(*this);
- return *this;
- }
- value&
- value::
- operator=(object const& obj)
- {
- value(obj, storage()).swap(*this);
- return *this;
- }
- value&
- value::
- operator=(object&& obj)
- {
- value(std::move(obj),
- storage()).swap(*this);
- return *this;
- }
- //----------------------------------------------------------
- //
- // Modifiers
- //
- //----------------------------------------------------------
- string&
- value::
- emplace_string() noexcept
- {
- return *::new(&str_) string(destroy());
- }
- array&
- value::
- emplace_array() noexcept
- {
- return *::new(&arr_) array(destroy());
- }
- object&
- value::
- emplace_object() noexcept
- {
- return *::new(&obj_) object(destroy());
- }
- void
- value::
- swap(value& other)
- {
- if(*storage() == *other.storage())
- {
- // fast path
- union U
- {
- value tmp;
- U(){}
- ~U(){}
- };
- U u;
- relocate(&u.tmp, *this);
- relocate(this, other);
- relocate(&other, u.tmp);
- return;
- }
- // copy
- value temp1(
- std::move(*this),
- other.storage());
- value temp2(
- std::move(other),
- this->storage());
- other.~value();
- ::new(&other) value(pilfer(temp1));
- this->~value();
- ::new(this) value(pilfer(temp2));
- }
- std::istream&
- operator>>(
- std::istream& is,
- value& jv)
- {
- using Traits = std::istream::traits_type;
- // sentry prepares the stream for reading and finalizes it in destructor
- std::istream::sentry sentry(is);
- if( !sentry )
- return is;
- parse_options opts = get_parse_options( is );
- if( auto depth = static_cast<std::size_t>( is.iword(parse_depth_xalloc) ) )
- opts.max_depth = depth;
- unsigned char parser_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
- stream_parser p( {}, opts, parser_buf );
- p.reset( jv.storage() );
- char read_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
- std::streambuf& buf = *is.rdbuf();
- std::ios::iostate err = std::ios::goodbit;
- #ifndef BOOST_NO_EXCEPTIONS
- try
- #endif
- {
- while( true )
- {
- system::error_code ec;
- // we peek the buffer; this either makes sure that there's no
- // more input, or makes sure there's something in the internal
- // buffer (so in_avail will return a positive number)
- std::istream::int_type c = is.rdbuf()->sgetc();
- // if we indeed reached EOF, we check if we parsed a full JSON
- // document; if not, we error out
- if( Traits::eq_int_type(c, Traits::eof()) )
- {
- err |= std::ios::eofbit;
- p.finish(ec);
- if( ec.failed() )
- break;
- }
- // regardless of reaching EOF, we might have parsed a full JSON
- // document; if so, we successfully finish
- if( p.done() )
- {
- jv = p.release();
- return is;
- }
- // at this point we definitely have more input, specifically in
- // buf's internal buffer; we also definitely haven't parsed a whole
- // document
- std::streamsize available = buf.in_avail();
- // if this assert fails, the streambuf is buggy
- BOOST_ASSERT( available > 0 );
- available = ( std::min )(
- static_cast<std::size_t>(available), sizeof(read_buf) );
- // we read from the internal buffer of buf into our buffer
- available = buf.sgetn( read_buf, available );
- std::size_t consumed = p.write_some(
- read_buf, static_cast<std::size_t>(available), ec );
- // if the parser hasn't consumed the entire input we've took from
- // buf, we put the remaining data back; this should succeed,
- // because we only read data from buf's internal buffer
- while( consumed++ < static_cast<std::size_t>(available) )
- {
- std::istream::int_type const status = buf.sungetc();
- BOOST_ASSERT( status != Traits::eof() );
- (void)status;
- }
- if( ec.failed() )
- break;
- }
- }
- #ifndef BOOST_NO_EXCEPTIONS
- catch(...)
- {
- try
- {
- is.setstate(std::ios::badbit);
- }
- // we ignore the exception, because we need to throw the original
- // exception instead
- catch( std::ios::failure const& ) { }
- if( is.exceptions() & std::ios::badbit )
- throw;
- }
- #endif
- is.setstate(err | std::ios::failbit);
- return is;
- }
- std::istream&
- operator>>(
- std::istream& is,
- parse_options const& opts)
- {
- is.iword(parse_flags_xalloc) = to_bitmask(opts);
- is.iword(parse_depth_xalloc) = static_cast<long>(opts.max_depth);
- return is;
- }
- //----------------------------------------------------------
- //
- // private
- //
- //----------------------------------------------------------
- storage_ptr
- value::
- destroy() noexcept
- {
- switch(kind())
- {
- case json::kind::null:
- case json::kind::bool_:
- case json::kind::int64:
- case json::kind::uint64:
- case json::kind::double_:
- break;
- case json::kind::string:
- {
- auto sp = str_.storage();
- str_.~string();
- return sp;
- }
- case json::kind::array:
- {
- auto sp = arr_.storage();
- arr_.~array();
- return sp;
- }
- case json::kind::object:
- {
- auto sp = obj_.storage();
- obj_.~object();
- return sp;
- }
- }
- return std::move(sp_);
- }
- bool
- value::
- equal(value const& other) const noexcept
- {
- switch(kind())
- {
- default: // unreachable()?
- case json::kind::null:
- return other.kind() == json::kind::null;
- case json::kind::bool_:
- return
- other.kind() == json::kind::bool_ &&
- get_bool() == other.get_bool();
- case json::kind::int64:
- switch(other.kind())
- {
- case json::kind::int64:
- return get_int64() == other.get_int64();
- case json::kind::uint64:
- if(get_int64() < 0)
- return false;
- return static_cast<std::uint64_t>(
- get_int64()) == other.get_uint64();
- default:
- return false;
- }
- case json::kind::uint64:
- switch(other.kind())
- {
- case json::kind::uint64:
- return get_uint64() == other.get_uint64();
- case json::kind::int64:
- if(other.get_int64() < 0)
- return false;
- return static_cast<std::uint64_t>(
- other.get_int64()) == get_uint64();
- default:
- return false;
- }
- case json::kind::double_:
- return
- other.kind() == json::kind::double_ &&
- get_double() == other.get_double();
- case json::kind::string:
- return
- other.kind() == json::kind::string &&
- get_string() == other.get_string();
- case json::kind::array:
- return
- other.kind() == json::kind::array &&
- get_array() == other.get_array();
- case json::kind::object:
- return
- other.kind() == json::kind::object &&
- get_object() == other.get_object();
- }
- }
- //----------------------------------------------------------
- //
- // key_value_pair
- //
- //----------------------------------------------------------
- // empty keys point here
- BOOST_JSON_REQUIRE_CONST_INIT
- char const
- key_value_pair::empty_[1] = { 0 };
- key_value_pair::
- key_value_pair(
- pilfered<json::value> key,
- pilfered<json::value> value) noexcept
- : value_(value)
- {
- std::size_t len;
- key_ = access::release_key(key.get(), len);
- len_ = static_cast<std::uint32_t>(len);
- }
- key_value_pair::
- key_value_pair(
- key_value_pair const& other,
- storage_ptr sp)
- : value_(other.value_, std::move(sp))
- {
- auto p = reinterpret_cast<
- char*>(value_.storage()->
- allocate(other.len_ + 1,
- alignof(char)));
- std::memcpy(
- p, other.key_, other.len_);
- len_ = other.len_;
- p[len_] = 0;
- key_ = p;
- }
- //----------------------------------------------------------
- namespace detail
- {
- std::size_t
- hash_value_impl( value const& jv ) noexcept
- {
- std::size_t seed = 0;
- kind const k = jv.kind();
- boost::hash_combine( seed, k != kind::int64 ? k : kind::uint64 );
- visit( value_hasher{seed}, jv );
- return seed;
- }
- } // namespace detail
- } // namespace json
- } // namespace boost
- //----------------------------------------------------------
- //
- // std::hash specialization
- //
- //----------------------------------------------------------
- std::size_t
- std::hash<::boost::json::value>::operator()(
- ::boost::json::value const& jv) const noexcept
- {
- return ::boost::hash< ::boost::json::value >()( jv );
- }
- //----------------------------------------------------------
- #endif
|