This commit is contained in:
Vinnie Falco 2019-11-08 15:22:52 -08:00
parent adcebea5a9
commit a0e46853a8
15 changed files with 494 additions and 273 deletions

View File

@ -325,8 +325,13 @@ struct nlohmann_impl : public any_impl
} }
void void
serialize(string_view, int) const override serialize(string_view s, int repeat) const override
{ {
auto jv = nlohmann::json::parse(
s.begin(), s.end());
while(repeat--)
auto s = jv.dump();
} }
}; };
@ -369,7 +374,7 @@ benchParse(
std::endl; std::endl;
for(unsigned j = 0; j < vi.size(); ++j) for(unsigned j = 0; j < vi.size(); ++j)
{ {
for(unsigned k = 0; k < 10; ++k) for(unsigned k = 0; k < 7; ++k)
{ {
auto const when = clock_type::now(); auto const when = clock_type::now();
vi[j]->parse(vs[i].text, 250); vi[j]->parse(vs[i].text, 250);
@ -401,14 +406,14 @@ benchSerialize(
std::endl; std::endl;
for(unsigned j = 0; j < vi.size(); ++j) for(unsigned j = 0; j < vi.size(); ++j)
{ {
for(unsigned k = 0; k < 5; ++k) for(unsigned k = 0; k < 7; ++k)
{ {
auto const when = clock_type::now(); auto const when = clock_type::now();
vi[j]->serialize(vs[i].text, 1000); vi[j]->serialize(vs[i].text, 1000);
auto const ms = std::chrono::duration_cast< auto const ms = std::chrono::duration_cast<
std::chrono::milliseconds>( std::chrono::milliseconds>(
clock_type::now() - when).count(); clock_type::now() - when).count();
if(k > 9) if(k > 4)
dout << " " << vi[j]->name() << ": " << dout << " " << vi[j]->name() << ": " <<
std::to_string(ms) << "ms" << std::to_string(ms) << "ms" <<
std::endl; std::endl;
@ -442,13 +447,13 @@ main(
std::vector<std::unique_ptr<any_impl const>> vi; std::vector<std::unique_ptr<any_impl const>> vi;
vi.reserve(10); vi.reserve(10);
//vi.emplace_back(new boost_default_impl); //vi.emplace_back(new boost_default_impl);
vi.emplace_back(new boost_impl); //.emplace_back(new boost_impl);
//vi.emplace_back(new boost_vec_impl); //vi.emplace_back(new boost_vec_impl);
vi.emplace_back(new rapidjson_impl); //vi.emplace_back(new rapidjson_impl);
//vi.emplace_back(new nlohmann_impl); vi.emplace_back(new nlohmann_impl);
benchParse(vs, vi); //benchParse(vs, vi);
//benchSerialize(vs, vi); benchSerialize(vs, vi);
} }
catch(system_error const& se) catch(system_error const& se)
{ {

View File

@ -487,6 +487,7 @@ public:
std::initializer_list<value> init, std::initializer_list<value> init,
storage_ptr sp = {}); storage_ptr sp = {});
explicit
BOOST_JSON_DECL BOOST_JSON_DECL
array(unchecked_array&& ua); array(unchecked_array&& ua);
@ -1594,6 +1595,11 @@ private:
impl_type& operator=( impl_type& operator=(
impl_type const&) = default; impl_type const&) = default;
inline
impl_type(
size_type capacity,
storage_ptr const& sp);
inline inline
impl_type& impl_type&
operator=( operator=(
@ -1611,12 +1617,6 @@ private:
void void
swap(impl_type& rhs) noexcept; swap(impl_type& rhs) noexcept;
inline
void
construct(
size_type capacity,
storage_ptr const& sp);
BOOST_JSON_DECL BOOST_JSON_DECL
void void
destroy(storage_ptr const& sp) noexcept; destroy(storage_ptr const& sp) noexcept;
@ -1636,7 +1636,7 @@ private:
array( array(
InputIt first, InputIt last, InputIt first, InputIt last,
storage_ptr sp, storage_ptr sp,
std::random_access_iterator_tag); std::forward_iterator_tag);
template<class InputIt> template<class InputIt>
iterator iterator
@ -1650,7 +1650,7 @@ private:
insert( insert(
const_iterator pos, const_iterator pos,
InputIt first, InputIt last, InputIt first, InputIt last,
std::random_access_iterator_tag); std::forward_iterator_tag);
inline inline
void void
@ -1686,7 +1686,7 @@ private:
class undo_assign; class undo_assign;
class undo_insert; class undo_insert;
storage_ptr sp_; storage_ptr sp_; // must come first
impl_type impl_; impl_type impl_;
}; };

View File

@ -420,12 +420,13 @@ array::
array( array(
InputIt first, InputIt last, InputIt first, InputIt last,
storage_ptr sp, storage_ptr sp,
std::random_access_iterator_tag) std::forward_iterator_tag)
: sp_(std::move(sp)) : sp_(std::move(sp))
{ {
undo_create u(*this); undo_create u(*this);
auto const n = static_cast< auto const n =
unsigned long long>(last - first); static_cast<std::size_t>(
std::distance(first, last));
if(n > max_size()) if(n > max_size())
BOOST_JSON_THROW( BOOST_JSON_THROW(
std::length_error( std::length_error(
@ -471,11 +472,12 @@ array::
insert( insert(
const_iterator pos, const_iterator pos,
InputIt first, InputIt last, InputIt first, InputIt last,
std::random_access_iterator_tag) -> std::forward_iterator_tag) ->
iterator iterator
{ {
auto const n = static_cast< auto const n =
unsigned long long>(last - first); static_cast<std::size_t>(
std::distance(first, last));
if(n > max_size()) if(n > max_size())
BOOST_JSON_THROW( BOOST_JSON_THROW(
std::length_error( std::length_error(

View File

@ -24,6 +24,25 @@ namespace json {
//---------------------------------------------------------- //----------------------------------------------------------
array::
impl_type::
impl_type(
size_type capacity_,
storage_ptr const& sp)
{
// The choice of minimum capacity
// affects the speed of parsing.
// if( capacity_ < min_capacity_)
// capacity_ = min_capacity_;
vec = reinterpret_cast<value*>(
sp->allocate(
capacity_ * sizeof(value),
alignof(value)));
size = 0;
capacity = capacity_;
}
array:: array::
impl_type:: impl_type::
impl_type(impl_type&& other) noexcept impl_type(impl_type&& other) noexcept
@ -76,25 +95,6 @@ destroy(
} }
} }
void
array::
impl_type::
construct(
size_type capacity_,
storage_ptr const& sp)
{
// The choice of minimum capacity
// affects the speed of parsing.
if( capacity_ < min_capacity_)
capacity_ = min_capacity_;
vec = reinterpret_cast<value*>(
sp->allocate(
capacity_ * sizeof(value),
alignof(value)));
size = 0;
capacity = capacity_;
}
//---------------------------------------------------------- //----------------------------------------------------------
array:: array::
@ -281,12 +281,10 @@ array(
array:: array::
array(unchecked_array&& ua) array(unchecked_array&& ua)
: sp_(ua.get_storage()) : sp_(ua.get_storage())
, impl_(ua.size(), sp_) // exact
{ {
undo_create u(*this);
reserve(ua.size());
impl_.size = ua.size(); impl_.size = ua.size();
ua.relocate(impl_.vec); ua.relocate(impl_.vec);
u.commit = true;
} }
//---------------------------------------------------------- //----------------------------------------------------------
@ -346,13 +344,18 @@ shrink_to_fit() noexcept
impl_.capacity <= min_capacity_) impl_.capacity <= min_capacity_)
return; return;
impl_type impl;
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
try try
{ {
#endif #endif
impl.construct( impl_type impl(impl_.size, sp_);
impl_.size, sp_); relocate(
impl.vec,
impl_.vec, impl_.size);
impl.size = impl_.size;
impl_.size = 0;
impl_.swap(impl);
impl.destroy(sp_);
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} }
catch(...) catch(...)
@ -361,14 +364,6 @@ shrink_to_fit() noexcept
return; return;
} }
#endif #endif
relocate(
impl.vec,
impl_.vec, impl_.size);
impl.size = impl_.size;
impl_.size = 0;
impl_.swap(impl);
impl.destroy(sp_);
} }
//---------------------------------------------------------- //----------------------------------------------------------
@ -628,15 +623,16 @@ reserve_impl(size_type capacity)
else if(capacity < hint) else if(capacity < hint)
capacity = hint; capacity = hint;
} }
impl_type impl; if( capacity < min_capacity_)
impl.construct(capacity, sp_); capacity = min_capacity_;
impl_type impl(capacity, sp_);
relocate( relocate(
impl.vec, impl.vec,
impl_.vec, impl_.size); impl_.vec, impl_.size);
impl.size = impl_.size; impl.size = impl_.size;
impl_.size = 0; impl_.size = 0;
impl_.swap(impl); impl_.destroy(sp_);
impl.destroy(sp_); impl_ = impl;
} }
void void

View File

@ -14,7 +14,7 @@
#include <boost/json/detail/except.hpp> #include <boost/json/detail/except.hpp>
#include <boost/json/detail/exchange.hpp> #include <boost/json/detail/exchange.hpp>
#include <boost/json/detail/string.hpp> #include <boost/json/detail/string.hpp>
#include <algorithm> #include <iterator>
#include <cmath> #include <cmath>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@ -123,66 +123,35 @@ bucket_end() const noexcept ->
return bucket_begin() + buckets(); return bucket_begin() + buckets();
} }
//---------------------------------------------------------- //----------------------------------------------------------
class object::undo_construct struct object::undo_construct
{ {
object& self_; object* self;
public:
bool commit = false;
~undo_construct() ~undo_construct()
{ {
if(! commit) if(self)
self_.impl_.destroy( self->impl_.destroy(
self_.sp_); self->sp_);
}
explicit
undo_construct(
object& self) noexcept
: self_(self)
{
} }
}; };
//---------------------------------------------------------- //----------------------------------------------------------
class object::undo_insert struct object::place_one
{ {
object& self_; virtual
void
operator()(void* dest) = 0;
};
public: struct object::place_range
value_type* const first;
value_type* last;
bool commit = false;
~undo_insert()
{ {
if(commit) virtual
{ bool
self_.impl_.grow(last - first); operator()(void* dest) = 0;
}
else
{
for(auto it = first; it != last; ++it)
self_.impl_.remove(
self_.impl_.bucket(it->key()), it);
value_type::destroy(
first, static_cast<
std::size_t>(last - first));
}
}
explicit
undo_insert(
object& self) noexcept
: self_(self)
, first(self_.impl_.end())
, last(first)
{
}
}; };
//---------------------------------------------------------- //----------------------------------------------------------
@ -200,11 +169,11 @@ object(
storage_ptr sp) storage_ptr sp)
: sp_(std::move(sp)) : sp_(std::move(sp))
{ {
undo_construct u(*this); undo_construct u{this};
insert_range( insert_range(
first, last, first, last,
min_capacity); min_capacity);
u.commit = true; u.self = nullptr;
} }
//---------------------------------------------------------- //----------------------------------------------------------
@ -355,22 +324,30 @@ object::
insert(P&& p) -> insert(P&& p) ->
std::pair<iterator, bool> std::pair<iterator, bool>
{ {
reserve(size() + 1); struct place_impl : place_one
auto& e = *::new( {
impl_.end()) value_type( P&& p;
std::forward<P>(p), sp_); storage_ptr const& sp;
auto const result = find_impl(e.key());
if(result.first) place_impl(
P&& p_,
storage_ptr const& sp_)
: p(std::forward<P>(p_))
, sp(sp_)
{ {
e.~value_type();
return { result.first, false };
} }
auto& head =
impl_.bucket(result.second); void
e.next_ = head; operator()(void* dest) override
head = &e; {
impl_.grow(1); ::new(dest) value_type(
return { &e, true }; std::forward<P>(p), sp);
}
};
place_impl f(
std::forward<P>(p), sp_);
return insert_impl(f);
} }
template<class M> template<class M>
@ -380,6 +357,30 @@ insert_or_assign(
key_type key, M&& m) -> key_type key, M&& m) ->
std::pair<iterator, bool> std::pair<iterator, bool>
{ {
struct place_impl : place_one
{
key_type key;
M&& m;
storage_ptr const& sp;
place_impl(
key_type key_,
M&& m_,
storage_ptr const& sp_)
: key(key_)
, m(std::forward<M>(m_))
, sp(sp_)
{
}
void
operator()(void* dest) override
{
::new(dest) value_type(key,
std::forward<M>(m), sp);
}
};
auto const result = find_impl(key); auto const result = find_impl(key);
if(result.first) if(result.first)
{ {
@ -387,16 +388,11 @@ insert_or_assign(
std::forward<M>(m); std::forward<M>(m);
return { result.first, false }; return { result.first, false };
} }
reserve(size() + 1);
auto& e = *::new( place_impl f(key,
impl_.end()) value_type( std::forward<M>(m), sp_);
key, std::forward<M>(m), sp_); return { insert_impl(
auto& head = result.second, f), true };
impl_.bucket(result.second);
e.next_ = head;
head = &e;
impl_.grow(1);
return { &e, true };
} }
template<class Arg> template<class Arg>
@ -407,17 +403,33 @@ emplace(
Arg&& arg) -> Arg&& arg) ->
std::pair<iterator, bool> std::pair<iterator, bool>
{ {
auto const result = find_impl(key); struct place_impl : place_one
if(result.first) {
return { result.first, false }; key_type key;
reserve(size() + 1); Arg&& arg;
auto p = ::new(impl_.end()) value_type( storage_ptr const& sp;
key, std::forward<Arg>(arg), sp_);
auto& head = impl_.bucket(result.second); place_impl(
p->next_ = head; key_type key_,
head = p; Arg&& arg_,
impl_.grow(1); storage_ptr const& sp_)
return { p, true }; : key(key_)
, arg(std::forward<Arg>(arg_))
, sp(sp_)
{
}
void
operator()(void* dest) override
{
::new(dest) value_type(key,
std::forward<Arg>(arg), sp);
}
};
place_impl f(key,
std::forward<Arg>(arg), sp_);
return emplace_impl(key, f);
} }
//---------------------------------------------------------- //----------------------------------------------------------
@ -482,33 +494,15 @@ insert_range(
std::size_t min_capacity, std::size_t min_capacity,
std::input_iterator_tag) std::input_iterator_tag)
{ {
// Since input iterators cannot be rewound,
// we keep inserted elements on an exception.
//
reserve(min_capacity); reserve(min_capacity);
undo_insert u(*this);
while(first != last) while(first != last)
{ {
reserve(size() + 1); insert(*first);
auto& e = *::new( ++first;
u.last) value_type(*first++, sp_);
auto& head = impl_.bucket(e.key());
for(auto it = head;;
it = it->next_)
{
if(it)
{
if(it->key() != e.key())
continue;
e.~value_type();
} }
else
{
e.next_ = head;
head = &e;
++u.last;
}
break;
}
}
u.commit = true;
} }
template<class InputIt> template<class InputIt>
@ -518,42 +512,44 @@ insert_range(
InputIt first, InputIt first,
InputIt last, InputIt last,
std::size_t min_capacity, std::size_t min_capacity,
std::random_access_iterator_tag) std::forward_iterator_tag)
{ {
auto n = static_cast< struct place_impl : place_range
std::size_t>(last - first); {
InputIt it;
std::size_t n;
storage_ptr const& sp;
place_impl(
InputIt it_,
std::size_t n_,
storage_ptr const& sp_)
: it(it_)
, n(n_)
, sp(sp_)
{
}
bool
operator()(void* dest) override
{
if(n-- == 0)
return false;
::new(dest) value_type(*it++, sp);
return true;
}
};
auto const n = static_cast<std::size_t>(
std::distance(first, last));
auto const n0 = size(); auto const n0 = size();
if(n > max_size() - n0) if(n > max_size() - n0)
BOOST_JSON_THROW( BOOST_JSON_THROW(
detail::object_too_large_exception()); detail::object_too_large_exception());
if( min_capacity < n0 + n) if( min_capacity < n0 + n)
min_capacity = n0 + n; min_capacity = n0 + n;
reserve(min_capacity); place_impl f(first, n, sp_);
undo_insert u(*this); insert_range_impl(min_capacity, f);
while(n--)
{
auto& e = *::new(
u.last) value_type(*first++, sp_);
auto& head = impl_.bucket(e.key());
for(auto it = head;;
it = it->next_)
{
if(it)
{
if(it->key() != e.key())
continue;
e.~value_type();
}
else
{
e.next_ = head;
head = &e;
++u.last;
}
break;
}
}
u.commit = true;
} }
} // json } // json

View File

@ -148,6 +148,52 @@ swap(impl_type& rhs) noexcept
rhs.tab_ = tmp; rhs.tab_ = tmp;
} }
//----------------------------------------------------------
class object::undo_insert
{
object& self_;
public:
std::size_t const first;
std::size_t last;
bool commit = false;
~undo_insert()
{
if(commit)
{
self_.impl_.grow(last - first);
}
else
{
auto p0 = self_.impl_.begin() + first;
auto p1 = self_.impl_.begin() + last;
for(auto it = p0; it != p1; ++it)
self_.impl_.remove(
self_.impl_.bucket(it->key()), it);
value_type::destroy(p0, last - first);
}
}
explicit
undo_insert(
object& self) noexcept
: self_(self)
, first(
self_.impl_.end() -
self_.impl_.begin())
, last(first)
{
}
value_type*
pos() noexcept
{
return self_.begin() + last;
}
};
//---------------------------------------------------------- //----------------------------------------------------------
// //
// object // object
@ -188,11 +234,11 @@ object(
} }
else else
{ {
undo_construct u(*this); undo_construct u{this};
insert_range( insert_range(
other.begin(), other.begin(),
other.end(), 0); other.end(), 0);
u.commit = true; u.self = nullptr;
} }
} }
@ -208,11 +254,11 @@ object(
object const& other) object const& other)
: sp_(other.sp_) : sp_(other.sp_)
{ {
undo_construct u(*this); undo_construct u{this};
insert_range( insert_range(
other.begin(), other.begin(),
other.end(), 0); other.end(), 0);
u.commit = true; u.self = nullptr;
} }
object:: object::
@ -221,11 +267,11 @@ object(
storage_ptr sp) storage_ptr sp)
: sp_(std::move(sp)) : sp_(std::move(sp))
{ {
undo_construct u(*this); undo_construct u{this};
insert_range( insert_range(
other.begin(), other.begin(),
other.end(), 0); other.end(), 0);
u.commit = true; u.self = nullptr;
} }
object:: object::
@ -235,12 +281,12 @@ object(
storage_ptr sp) storage_ptr sp)
: sp_(std::move(sp)) : sp_(std::move(sp))
{ {
undo_construct u(*this); undo_construct u{this};
insert_range( insert_range(
init.begin(), init.begin(),
init.end(), init.end(),
min_capacity); min_capacity);
u.commit = true; u.self = nullptr;
} }
object:: object::
@ -565,6 +611,106 @@ rehash(std::size_t new_capacity)
impl_.rebuild(); impl_.rebuild();
} }
auto
object::
emplace_impl(
key_type key,
place_one& f) ->
std::pair<iterator, bool>
{
auto const result = find_impl(key);
if(result.first)
return { result.first, false };
reserve(size() + 1);
auto& e = *impl_.end();
f(&e);
auto& head =
impl_.bucket(result.second);
e.next_ = head;
head = &e;
impl_.grow(1);
return { &e, true };
}
auto
object::
insert_impl(
place_one& f) ->
std::pair<iterator, bool>
{
reserve(size() + 1);
auto& e = *impl_.end();
f(&e);
auto const result =
find_impl(e.key());
if(result.first)
{
e.~value_type();
return { result.first, false };
}
auto& head =
impl_.bucket(result.second);
e.next_ = head;
head = &e;
impl_.grow(1);
return { &e, true };
}
auto
object::
insert_impl(
std::size_t hash,
place_one& f) ->
iterator
{
reserve(size() + 1);
auto& e = *impl_.end();
f(&e);
auto& head =
impl_.bucket(hash);
e.next_ = head;
head = &e;
impl_.grow(1);
return &e;
}
void
object::
insert_range_impl(
std::size_t min_capacity,
place_range& f)
{
reserve(min_capacity);
undo_insert u(*this);
for(;;)
{
reserve(size() + 1);
auto& e = *u.pos();
if(! f(&e))
break;
auto& head =
impl_.bucket(e.key());
for(auto it = head;;
it = it->next_)
{
if(it)
{
if(it->key() != e.key())
continue;
e.~value_type();
}
else
{
e.next_ = head;
head = &e;
++u.last;
}
break;
}
}
u.commit = true;
}
} // json } // json
} // boost } // boost

View File

@ -97,6 +97,7 @@ void
parser:: parser::
on_document_begin(error_code&) on_document_begin(error_code&)
{ {
lev_ = level{ 0, false };
st_.placeholder(sizeof(value)); st_.placeholder(sizeof(value));
} }
@ -115,7 +116,6 @@ void
parser:: parser::
on_object_begin(error_code&) on_object_begin(error_code&)
{ {
lev_ = level{ 0, false };
st_.push(lev_); st_.push(lev_);
lev_ = level{ 0, true }; lev_ = level{ 0, true };
st_.placeholder(sizeof( st_.placeholder(sizeof(
@ -204,6 +204,7 @@ on_key(
st_.push(s); st_.push(s);
key_ += static_cast<size_type>( key_ += static_cast<size_type>(
s.size()); s.size());
st_.align();
st_.push(key_); st_.push(key_);
key_ = 0; key_ = 0;
} }

View File

@ -136,6 +136,20 @@ from_json(T& t, value const& v)
//---------------------------------------------------------- //----------------------------------------------------------
value::
value(unchecked_object&& uo)
: obj_(std::move(uo))
, kind_(json::kind::object)
{
}
value::
value(unchecked_array&& ua)
: arr_(std::move(ua))
, kind_(json::kind::array)
{
}
template<class Bool, class> template<class Bool, class>
value:: value::
value(Bool b, storage_ptr sp) noexcept value(Bool b, storage_ptr sp) noexcept
@ -165,6 +179,7 @@ value_type(
Args&&... args) Args&&... args)
: value_(std::forward<Args>(args)...) : value_(std::forward<Args>(args)...)
, len_(key.size()) , len_(key.size())
#if 0
, key_( , key_(
[&] [&]
{ {
@ -178,7 +193,16 @@ value_type(
s[key.size()] = 0; s[key.size()] = 0;
return s; return s;
}()) }())
#endif
{ {
if(key.size() > detail::max_string_length_)
BOOST_JSON_THROW(
detail::string_too_large_exception());
key_ = reinterpret_cast<
char*>(value_.get_storage()->
allocate(key.size() + 1));
std::memcpy(key_, key.data(), key.size());
key_[key.size()] = 0;
} }
//---------------------------------------------------------- //----------------------------------------------------------

View File

@ -446,34 +446,6 @@ maybe_object(
// //
//---------------------------------------------------------- //----------------------------------------------------------
storage_ptr const&
value::
get_storage() const noexcept
{
switch(kind_)
{
case json::kind::object:
return obj_.get_storage();
case json::kind::array:
return arr_.get_storage();
case json::kind::string:
return str_.get_storage();
case json::kind::int64:
case json::kind::uint64:
case json::kind::double_:
case json::kind::boolean:
case json::kind::null:
default:
break;
}
return sca_.sp;
}
//----------------------------------------------------------
storage_ptr storage_ptr
value:: value::
destroy() noexcept destroy() noexcept

View File

@ -225,7 +225,7 @@ private:
bucket_end() const noexcept; bucket_end() const noexcept;
}; };
class undo_construct; struct undo_construct;
class undo_insert; class undo_insert;
template<class T> template<class T>
@ -242,7 +242,7 @@ private:
return 1.0; return 1.0;
} }
storage_ptr sp_; storage_ptr sp_; // must come first
impl_type impl_; impl_type impl_;
public: public:
@ -553,6 +553,7 @@ public:
/** /**
*/ */
explicit
BOOST_JSON_DECL BOOST_JSON_DECL
object(unchecked_object&& uo); object(unchecked_object&& uo);
@ -1345,12 +1346,8 @@ public:
contains(key_type key) const noexcept; contains(key_type key) const noexcept;
private: private:
struct place struct place_one;
{ struct place_range;
virtual
void
operator()(void* dest) = 0;
};
template<class It> template<class It>
using iter_cat = typename using iter_cat = typename
@ -1376,15 +1373,39 @@ private:
digest(key_type key) noexcept; digest(key_type key) noexcept;
BOOST_JSON_DECL BOOST_JSON_DECL
std::pair< std::pair<value_type*, std::size_t>
value_type*,
std::size_t>
find_impl(key_type key) const noexcept; find_impl(key_type key) const noexcept;
BOOST_JSON_DECL BOOST_JSON_DECL
void void
rehash(std::size_t new_capacity); rehash(std::size_t new_capacity);
BOOST_JSON_DECL
std::pair<iterator, bool>
emplace_impl(
key_type key, place_one& f);
BOOST_JSON_DECL
std::pair<iterator, bool>
insert_impl(place_one& f);
BOOST_JSON_DECL
iterator
insert_impl(
std::size_t hash,
place_one& f);
BOOST_JSON_DECL
std::pair<iterator, bool>
insert_or_assign_impl(
key_type key, place_one& f);
BOOST_JSON_DECL
void
insert_range_impl(
std::size_t min_capacity,
place_range& f);
template<class InputIt> template<class InputIt>
void void
insert_range( insert_range(
@ -1399,7 +1420,7 @@ private:
InputIt first, InputIt first,
InputIt last, InputIt last,
std::size_t min_capacity, std::size_t min_capacity,
std::random_access_iterator_tag); std::forward_iterator_tag);
template<class InputIt> template<class InputIt>
void void

View File

@ -31,8 +31,9 @@ class parser final
{ {
struct level struct level
{ {
size_type size; std::int32_t size;
bool obj; bool obj;
char pad[3];
}; };
class stack class stack
@ -97,8 +98,9 @@ class parser final
object::value_type& object::value_type&
emplace_pair(Arg&& arg) emplace_pair(Arg&& arg)
{ {
size_type len; std::size_t len;
pop_impl(len); pop_impl(len);
size_ -= alignup(len) - len;
auto key = pop_string(len); auto key = pop_string(len);
auto const n = sizeof(object::value_type); auto const n = sizeof(object::value_type);
// size for n was placeheld // size for n was placeheld
@ -114,7 +116,10 @@ class parser final
placeholder( placeholder(
std::size_t bytes) std::size_t bytes)
{ {
bytes = alignup(bytes); BOOST_JSON_ASSERT(
alignup(bytes) == bytes);
BOOST_JSON_ASSERT(
alignup(size_) == size_);
prepare(bytes); prepare(bytes);
size_ += bytes; size_ += bytes;
} }
@ -123,14 +128,26 @@ class parser final
unreserve( unreserve(
std::size_t bytes) std::size_t bytes)
{ {
bytes = alignup(bytes); BOOST_JSON_ASSERT(
alignup(bytes) == bytes);
BOOST_JSON_ASSERT(
alignup(size_) == size_);
BOOST_JSON_ASSERT( BOOST_JSON_ASSERT(
bytes <= size_); bytes <= size_);
size_ -= bytes; size_ -= bytes;
} }
void void
push(size_type u) align()
{
auto const n = alignup(size_);
if(n > capacity_)
grow(n - size_);
size_ = n;
}
void
push(std::size_t u)
{ {
push_impl(u); push_impl(u);
} }
@ -147,7 +164,7 @@ class parser final
prepare(s.size()); prepare(s.size());
std::memcpy(base_ + size_, std::memcpy(base_ + size_,
s.data(), s.size()); s.data(), s.size());
size_ += alignup(s.size()); size_ += s.size();
} }
void void
@ -159,11 +176,16 @@ class parser final
unchecked_array unchecked_array
pop_array(size_type size) noexcept pop_array(size_type size) noexcept
{ {
BOOST_JSON_ASSERT(
alignup(size_) == size_);
if(size == 0) if(size == 0)
return { nullptr, 0, sp_ }; return { nullptr, 0, sp_ };
auto const n = sizeof(value) * size; auto const n =
sizeof(value) * size;
BOOST_JSON_ASSERT(
alignup(n) == n);
BOOST_JSON_ASSERT(n <= size_); BOOST_JSON_ASSERT(n <= size_);
size_ -= alignup(n); size_ -= n;
return { reinterpret_cast< return { reinterpret_cast<
value*>(base_ + size_), value*>(base_ + size_),
size, sp_ }; size, sp_ };
@ -172,19 +194,23 @@ class parser final
unchecked_object unchecked_object
pop_object(size_type size) noexcept pop_object(size_type size) noexcept
{ {
BOOST_JSON_ASSERT(
alignup(size_) == size_);
if(size == 0) if(size == 0)
return { nullptr, 0, sp_ }; return { nullptr, 0, sp_ };
auto const n = sizeof( auto const n = sizeof(
object::value_type) * size; object::value_type) * size;
BOOST_JSON_ASSERT(
alignup(n) == n);
BOOST_JSON_ASSERT(n <= size_); BOOST_JSON_ASSERT(n <= size_);
size_ -= alignup(n); size_ -= n;
return { reinterpret_cast< return { reinterpret_cast<
object::value_type*>(base_ + size_), object::value_type*>(base_ + size_),
size, sp_ }; size, sp_ };
} }
string_view string_view
pop_string(size_type len) noexcept pop_string(std::size_t len) noexcept
{ {
BOOST_JSON_ASSERT(len <= size_); BOOST_JSON_ASSERT(len <= size_);
size_ -= len; size_ -= len;
@ -205,7 +231,6 @@ class parser final
void void
prepare(std::size_t n) prepare(std::size_t n)
{ {
n = alignup(n);
if(n > capacity_ - size_) if(n > capacity_ - size_)
grow(n); grow(n);
} }
@ -238,7 +263,11 @@ class parser final
void void
push_impl(T t) push_impl(T t)
{ {
auto const n = alignup(sizeof(T)); BOOST_JSON_ASSERT((sizeof(T) %
sizeof(max_align_t)) == 0);
BOOST_JSON_ASSERT((size_ %
sizeof(max_align_t)) == 0);
auto const n = sizeof(T);
if(n > capacity_ - size_) if(n > capacity_ - size_)
grow(n); grow(n);
::new(base_ + size_) T(t); ::new(base_ + size_) T(t);
@ -249,9 +278,13 @@ class parser final
void void
pop_impl(T& t) noexcept pop_impl(T& t) noexcept
{ {
BOOST_JSON_ASSERT( BOOST_JSON_ASSERT((sizeof(T) %
size_ >= sizeof(T)); sizeof(max_align_t)) == 0);
size_ -= alignup(sizeof(T)); BOOST_JSON_ASSERT((size_ %
sizeof(max_align_t)) == 0);
auto const n = sizeof(T);
BOOST_JSON_ASSERT(size_ >= n);
size_ -= n;
std::memcpy( std::memcpy(
&t, base_ + size_, sizeof(T)); &t, base_ + size_, sizeof(T));
} }

View File

@ -112,7 +112,7 @@ private:
union union
{ {
char* p; char* p;
char buf[20]; // SBO char buf[4]; // SBO
}; };
#endif #endif
@ -227,7 +227,7 @@ private:
}; };
storage_ptr sp_; storage_ptr sp_; // must come first
impl impl_; impl impl_;
public: public:

View File

@ -33,6 +33,8 @@ namespace boost {
namespace json { namespace json {
class value; class value;
class unchecked_object;
class unchecked_array;
/** Customization point for assigning to and from class types. /** Customization point for assigning to and from class types.
*/ */
@ -109,7 +111,7 @@ class value
#ifndef GENERATING_DOCUMENTATION #ifndef GENERATING_DOCUMENTATION
struct scalar struct scalar
{ {
storage_ptr sp; storage_ptr sp; // must come first
union union
{ {
std::uint64_t u; std::uint64_t u;
@ -132,6 +134,7 @@ class value
// XSL scripts have trouble with private anon unions // XSL scripts have trouble with private anon unions
union union
{ {
storage_ptr sp_; // must come first
object obj_; object obj_;
array arr_; array arr_;
string str_; string str_;
@ -377,6 +380,11 @@ public:
{ {
} }
/** Construct an array.
*/
inline
value(unchecked_object&& uo);
/** Construct an array. /** Construct an array.
*/ */
value(array arr) noexcept value(array arr) noexcept
@ -402,6 +410,11 @@ public:
{ {
} }
/** Construct an array.
*/
inline
value(unchecked_array&& ua);
/** Construct a string. /** Construct a string.
*/ */
value( value(
@ -1055,9 +1068,11 @@ public:
No-throw guarantee. No-throw guarantee.
*/ */
BOOST_JSON_DECL
storage_ptr const& storage_ptr const&
get_storage() const noexcept; get_storage() const noexcept
{
return sp_;
}
/** Return a pointer to an object, or nullptr. /** Return a pointer to an object, or nullptr.

View File

@ -92,6 +92,12 @@ struct fail_storage
std::size_t fail_max = 1; std::size_t fail_max = 1;
std::size_t fail = 0; std::size_t fail = 0;
std::size_t nalloc = 0;
~fail_storage()
{
BEAST_EXPECT(nalloc == 0);
}
void* void*
allocate( allocate(
@ -104,7 +110,9 @@ struct fail_storage
fail = 0; fail = 0;
throw test_failure{}; throw test_failure{};
} }
return ::operator new(n); auto p = ::operator new(n);
++nalloc;
return p;
} }
void void
@ -113,6 +121,8 @@ struct fail_storage
std::size_t, std::size_t,
std::size_t) noexcept std::size_t) noexcept
{ {
if(BEAST_EXPECT(nalloc > 0))
--nalloc;
::operator delete(p); ::operator delete(p);
} }
}; };