Less faffing around with node_constructor.

This commit is contained in:
Daniel James
2016-08-14 20:55:40 +01:00
parent 37a6903831
commit 88612a8be4
4 changed files with 103 additions and 99 deletions

View File

@ -1199,40 +1199,55 @@ namespace boost { namespace unordered { namespace detail { namespace func {
// Some nicer construct_value functions, might try to // Some nicer construct_value functions, might try to
// improve implementation later. // improve implementation later.
template <typename AllocAndPointer, BOOST_UNORDERED_EMPLACE_TEMPLATE> template <typename Alloc, BOOST_UNORDERED_EMPLACE_TEMPLATE>
inline typename AllocAndPointer::node_pointer construct_value_generic(AllocAndPointer& a, BOOST_UNORDERED_EMPLACE_ARGS) { inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
construct_value_impl(a.alloc_, a.node_->value_ptr(), construct_value_generic(Alloc& alloc, BOOST_UNORDERED_EMPLACE_ARGS)
{
node_constructor<Alloc> a(alloc);
a.create_node();
construct_value_impl(alloc, a.node_->value_ptr(),
BOOST_UNORDERED_EMPLACE_FORWARD); BOOST_UNORDERED_EMPLACE_FORWARD);
return a.release(); return a.release();
} }
template <typename AllocAndPointer, typename U> template <typename Alloc, typename U>
inline typename AllocAndPointer::node_pointer construct_value(AllocAndPointer& a, BOOST_FWD_REF(U) x) { inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
construct_value(Alloc& alloc, BOOST_FWD_REF(U) x)
{
node_constructor<Alloc> a(alloc);
a.create_node();
boost::unordered::detail::func::call_construct( boost::unordered::detail::func::call_construct(
a.alloc_, a.node_->value_ptr(), boost::forward<U>(x)); alloc, a.node_->value_ptr(), boost::forward<U>(x));
return a.release(); return a.release();
} }
// TODO: When possible, it might be better to use std::pair's // TODO: When possible, it might be better to use std::pair's
// constructor for std::piece_construct with std::tuple. // constructor for std::piece_construct with std::tuple.
template <typename AllocAndPointer, typename Key> template <typename Alloc, typename Key>
inline typename AllocAndPointer::node_pointer construct_pair(AllocAndPointer& a, BOOST_FWD_REF(Key) k) { inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
construct_pair(Alloc& alloc, BOOST_FWD_REF(Key) k)
{
node_constructor<Alloc> a(alloc);
a.create_node();
boost::unordered::detail::func::call_construct( boost::unordered::detail::func::call_construct(
a.alloc_, boost::addressof(a.node_->value_ptr()->first), alloc, boost::addressof(a.node_->value_ptr()->first),
boost::forward<Key>(k)); boost::forward<Key>(k));
boost::unordered::detail::func::call_construct( boost::unordered::detail::func::call_construct(
a.alloc_, boost::addressof(a.node_->value_ptr()->second)); alloc, boost::addressof(a.node_->value_ptr()->second));
return a.release(); return a.release();
} }
template <typename AllocAndPointer, typename Key, typename Mapped> template <typename Alloc, typename Key, typename Mapped>
inline typename AllocAndPointer::node_pointer construct_pair(AllocAndPointer& a, inline typename boost::unordered::detail::allocator_traits<Alloc>::pointer
BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) { construct_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m)
{
node_constructor<Alloc> a(alloc);
a.create_node();
boost::unordered::detail::func::call_construct( boost::unordered::detail::func::call_construct(
a.alloc_, boost::addressof(a.node_->value_ptr()->first), alloc, boost::addressof(a.node_->value_ptr()->first),
boost::forward<Key>(k)); boost::forward<Key>(k));
boost::unordered::detail::func::call_construct( boost::unordered::detail::func::call_construct(
a.alloc_, boost::addressof(a.node_->value_ptr()->second), alloc, boost::addressof(a.node_->value_ptr()->second),
boost::forward<Mapped>(m)); boost::forward<Mapped>(m));
return a.release(); return a.release();
} }

View File

@ -374,7 +374,9 @@ namespace boost { namespace unordered { namespace detail {
} }
else { else {
constructor_.create_node(); constructor_.create_node();
return boost::unordered::detail::func::construct_value(constructor_, v); boost::unordered::detail::func::call_construct(
constructor_.alloc_, constructor_.node_->value_ptr(), v);
return constructor_.release();
} }
} }
@ -386,7 +388,9 @@ namespace boost { namespace unordered { namespace detail {
else { else {
constructor_.create_node(); constructor_.create_node();
} }
return boost::unordered::detail::func::construct_value(constructor_, v); boost::unordered::detail::func::call_construct(
constructor_.alloc_, constructor_.node_->value_ptr(), v);
return constructor_.release();
} }
template <typename T> template <typename T>
@ -398,8 +402,10 @@ namespace boost { namespace unordered { namespace detail {
} }
else { else {
constructor_.create_node(); constructor_.create_node();
return boost::unordered::detail::func::construct_value( boost::unordered::detail::func::call_construct(
constructor_, boost::move(v)); constructor_.alloc_, constructor_.node_->value_ptr(),
boost::move(v));
return constructor_.release();
} }
} }
@ -411,8 +417,10 @@ namespace boost { namespace unordered { namespace detail {
else { else {
constructor_.create_node(); constructor_.create_node();
} }
return boost::unordered::detail::func::construct_value( boost::unordered::detail::func::call_construct(
constructor_, boost::move(v)); constructor_.alloc_, constructor_.node_->value_ptr(),
boost::move(v));
return constructor_.release();
} }
iterator begin() const iterator begin() const

View File

@ -473,11 +473,10 @@ namespace boost { namespace unordered { namespace detail {
template <BOOST_UNORDERED_EMPLACE_TEMPLATE> template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS) iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS)
{ {
node_constructor a(this->node_alloc());
a.create_node();
node_tmp b( node_tmp b(
boost::unordered::detail::func::construct_value_generic(a, BOOST_UNORDERED_EMPLACE_FORWARD), boost::unordered::detail::func::construct_value_generic(
a.alloc_); this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
this->node_alloc());
return iterator(emplace_impl(b)); return iterator(emplace_impl(b));
} }
@ -495,24 +494,21 @@ namespace boost { namespace unordered { namespace detail {
std::size_t distance = std::distance(i, j); std::size_t distance = std::distance(i, j);
if(distance == 1) { if(distance == 1) {
node_constructor a(this->node_alloc());
a.create_node();
node_tmp b( node_tmp b(
boost::unordered::detail::func::construct_value(a, *i), boost::unordered::detail::func::construct_value(
a.alloc_); this->node_alloc(), *i),
this->node_alloc());
emplace_impl(b); emplace_impl(b);
} }
else { else {
// Only require basic exception safety here // Only require basic exception safety here
this->reserve_for_insert(this->size_ + distance); this->reserve_for_insert(this->size_ + distance);
node_constructor a(this->node_alloc());
for (; i != j; ++i) { for (; i != j; ++i) {
a.create_node();
node_tmp b( node_tmp b(
boost::unordered::detail::func::construct_value(a, *i), boost::unordered::detail::func::construct_value(
a.alloc_); this->node_alloc(), *i),
this->node_alloc());
emplace_impl_no_rehash(b); emplace_impl_no_rehash(b);
} }
} }
@ -522,12 +518,11 @@ namespace boost { namespace unordered { namespace detail {
void insert_range(I i, I j, typename void insert_range(I i, I j, typename
boost::unordered::detail::disable_if_forward<I, void*>::type = 0) boost::unordered::detail::disable_if_forward<I, void*>::type = 0)
{ {
node_constructor a(this->node_alloc());
for (; i != j; ++i) { for (; i != j; ++i) {
a.create_node();
node_tmp b( node_tmp b(
boost::unordered::detail::func::construct_value(a, *i), boost::unordered::detail::func::construct_value(
a.alloc_); this->node_alloc(), *i),
this->node_alloc());
emplace_impl(b); emplace_impl(b);
} }
} }
@ -643,43 +638,37 @@ namespace boost { namespace unordered { namespace detail {
// fill_buckets // fill_buckets
void copy_buckets(table const& src) { void copy_buckets(table const& src) {
node_constructor constructor(this->node_alloc());
this->create_buckets(this->bucket_count_); this->create_buckets(this->bucket_count_);
for (iterator n = src.begin(); n.node_;) { for (iterator n = src.begin(); n.node_;) {
std::size_t key_hash = n.node_->hash_; std::size_t key_hash = n.node_->hash_;
iterator group_end(n.node_->group_prev_->next_); iterator group_end(n.node_->group_prev_->next_);
constructor.create_node();
iterator pos = this->add_node( iterator pos = this->add_node(
boost::unordered::detail::func::construct_value( boost::unordered::detail::func::construct_value(
constructor, *n), key_hash, iterator()); this->node_alloc(), *n), key_hash, iterator());
for (++n; n != group_end; ++n) for (++n; n != group_end; ++n)
{ {
constructor.create_node();
this->add_node( this->add_node(
boost::unordered::detail::func::construct_value( boost::unordered::detail::func::construct_value(
constructor, *n), key_hash, pos); this->node_alloc(), *n), key_hash, pos);
} }
} }
} }
void move_buckets(table& src) { void move_buckets(table const& src) {
node_constructor constructor(this->node_alloc());
this->create_buckets(this->bucket_count_); this->create_buckets(this->bucket_count_);
for (iterator n = src.begin(); n.node_;) { for (iterator n = src.begin(); n.node_;) {
std::size_t key_hash = n.node_->hash_; std::size_t key_hash = n.node_->hash_;
iterator group_end(n.node_->group_prev_->next_); iterator group_end(n.node_->group_prev_->next_);
constructor.create_node();
iterator pos = this->add_node( iterator pos = this->add_node(
boost::unordered::detail::func::construct_value( boost::unordered::detail::func::construct_value(
constructor, boost::move(*n)), key_hash, iterator()); this->node_alloc(), boost::move(*n)), key_hash, iterator());
for (++n; n != group_end; ++n) for (++n; n != group_end; ++n)
{ {
constructor.create_node();
this->add_node( this->add_node(
boost::unordered::detail::func::construct_value( boost::unordered::detail::func::construct_value(
constructor, boost::move(*n)), key_hash, pos); this->node_alloc(), boost::move(*n)), key_hash, pos);
} }
} }
} }

View File

@ -356,10 +356,9 @@ namespace boost { namespace unordered { namespace detail {
// Create the node before rehashing in case it throws an // Create the node before rehashing in case it throws an
// exception (need strong safety in such a case). // exception (need strong safety in such a case).
node_constructor a(this->node_alloc()); node_tmp b(
a.create_node(); boost::unordered::detail::func::construct_pair(this->node_alloc(), k),
node_tmp b(boost::unordered::detail::func::construct_pair(a, k), this->node_alloc());
a.alloc_);
this->reserve_for_insert(this->size_ + 1); this->reserve_for_insert(this->size_ + 1);
return *add_node(b, key_hash); return *add_node(b, key_hash);
@ -417,12 +416,10 @@ namespace boost { namespace unordered { namespace detail {
// Create the node before rehashing in case it throws an // Create the node before rehashing in case it throws an
// exception (need strong safety in such a case). // exception (need strong safety in such a case).
node_constructor a(this->node_alloc());
a.create_node();
node_tmp b( node_tmp b(
boost::unordered::detail::func::construct_value_generic( boost::unordered::detail::func::construct_value_generic(
a, BOOST_UNORDERED_EMPLACE_FORWARD), this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
a.alloc_); this->node_alloc());
// reserve has basic exception safety if the hash function // reserve has basic exception safety if the hash function
// throws, strong otherwise. // throws, strong otherwise.
@ -430,35 +427,25 @@ namespace boost { namespace unordered { namespace detail {
return emplace_return(this->add_node(b, key_hash), true); return emplace_return(this->add_node(b, key_hash), true);
} }
emplace_return emplace_impl_with_node(node_constructor& a, node_tmp& b)
{
key_type const& k = this->get_key(b.value());
std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(key_hash, k);
if (pos.node_) {
a.reclaim(b.release());
return emplace_return(pos, false);
}
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1);
return emplace_return(this->add_node(b, key_hash), true);
}
template <BOOST_UNORDERED_EMPLACE_TEMPLATE> template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS) emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS)
{ {
// Don't have a key, so construct the node first in order // Don't have a key, so construct the node first in order
// to be able to lookup the position. // to be able to lookup the position.
node_constructor a(this->node_alloc());
a.create_node();
node_tmp b( node_tmp b(
boost::unordered::detail::func::construct_value_generic( boost::unordered::detail::func::construct_value_generic(
a, BOOST_UNORDERED_EMPLACE_FORWARD), this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD),
a.alloc_); this->node_alloc());
return emplace_impl_with_node(a, b); key_type const& k = this->get_key(b.value());
std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(key_hash, k);
if (pos.node_) { return emplace_return(pos, false); }
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1);
return emplace_return(this->add_node(b, key_hash), true);
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@ -477,9 +464,7 @@ namespace boost { namespace unordered { namespace detail {
template <class InputIt> template <class InputIt>
void insert_range_impl(key_type const& k, InputIt i, InputIt j) void insert_range_impl(key_type const& k, InputIt i, InputIt j)
{ {
node_constructor a(this->node_alloc()); insert_range_impl2(k, i, j);
insert_range_impl2(a, k, i, j);
while(++i != j) { while(++i != j) {
// Note: can't use get_key as '*i' might not be value_type - it // Note: can't use get_key as '*i' might not be value_type - it
@ -490,23 +475,21 @@ namespace boost { namespace unordered { namespace detail {
// key here. Could be more efficient if '*i' is expensive. Could // key here. Could be more efficient if '*i' is expensive. Could
// be less efficient if copying the full value_type is // be less efficient if copying the full value_type is
// expensive. // expensive.
insert_range_impl2(a, extractor::extract(*i), i, j); insert_range_impl2(extractor::extract(*i), i, j);
} }
} }
template <class InputIt> template <class InputIt>
void insert_range_impl2(node_constructor& a, key_type const& k, void insert_range_impl2(key_type const& k, InputIt i, InputIt j)
InputIt i, InputIt j)
{ {
// No side effects in this initial code // No side effects in this initial code
std::size_t key_hash = this->hash(k); std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(key_hash, k); iterator pos = this->find_node(key_hash, k);
if (!pos.node_) { if (!pos.node_) {
a.create_node();
node_tmp b( node_tmp b(
boost::unordered::detail::func::construct_value(a, *i), boost::unordered::detail::func::construct_value(this->node_alloc(), *i),
a.alloc_); this->node_alloc());
if(this->size_ + 1 > this->max_load_) if(this->size_ + 1 > this->max_load_)
this->reserve_for_insert(this->size_ + this->reserve_for_insert(this->size_ +
boost::unordered::detail::insert_size(i, j)); boost::unordered::detail::insert_size(i, j));
@ -523,10 +506,23 @@ namespace boost { namespace unordered { namespace detail {
do { do {
if (!a.node_) { a.create_node(); } if (!a.node_) { a.create_node(); }
node_tmp b( boost::unordered::detail::func::call_construct(
boost::unordered::detail::func::construct_value(a, *i), a.alloc_, a.node_->value_ptr(), *i);
a.alloc_); node_tmp b(a.release(), a.alloc_);
emplace_impl_with_node(a, b);
key_type const& k = this->get_key(b.value());
std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(key_hash, k);
if (pos.node_) {
a.reclaim(b.release());
}
else {
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1);
this->add_node(b, key_hash);
}
} while(++i != j); } while(++i != j);
} }
@ -600,26 +596,22 @@ namespace boost { namespace unordered { namespace detail {
// fill_buckets // fill_buckets
void copy_buckets(table const& src) { void copy_buckets(table const& src) {
node_constructor constructor(this->node_alloc());
this->create_buckets(this->bucket_count_); this->create_buckets(this->bucket_count_);
for(iterator n = src.begin(); n.node_; ++n) { for(iterator n = src.begin(); n.node_; ++n) {
constructor.create_node();
this->add_node( this->add_node(
boost::unordered::detail::func::construct_value( boost::unordered::detail::func::construct_value(
constructor, *n), n.node_->hash_); this->node_alloc(), *n), n.node_->hash_);
} }
} }
void move_buckets(table& src) { void move_buckets(table const& src) {
node_constructor constructor(this->node_alloc());
this->create_buckets(this->bucket_count_); this->create_buckets(this->bucket_count_);
for(iterator n = src.begin(); n.node_; ++n) { for(iterator n = src.begin(); n.node_; ++n) {
constructor.create_node();
this->add_node( this->add_node(
boost::unordered::detail::func::construct_value( boost::unordered::detail::func::construct_value(
constructor, boost::move(*n)), n.node_->hash_); this->node_alloc(), boost::move(*n)), n.node_->hash_);
} }
} }