Unordered: Generic copy/move implementation.

[SVN r80379]
This commit is contained in:
Daniel James
2012-09-03 20:02:10 +00:00
parent 7a4930f1a1
commit 73c269398a
3 changed files with 64 additions and 117 deletions

View File

@ -710,20 +710,12 @@ namespace boost { namespace unordered { namespace detail {
}
////////////////////////////////////////////////////////////////////////
// copy_buckets_to
//
// Basic exception safety. If an exception is thrown this will
// leave dst partially filled and the buckets unset.
// fill_buckets
static void copy_buckets_to(buckets const& src, buckets& dst)
template <class NodeCreator>
static void fill_buckets(iterator n, buckets& dst,
NodeCreator& creator)
{
BOOST_ASSERT(!dst.buckets_);
dst.create_buckets(dst.bucket_count_);
node_constructor a(dst.node_alloc());
iterator n = src.get_start();
previous_pointer prev = dst.get_previous_start();
while (n.node_) {
@ -733,10 +725,7 @@ namespace boost { namespace unordered { namespace detail {
static_cast<node_pointer>(n.node_->group_prev_)->next_
));
a.construct_node();
a.construct_value2(*n);
node_pointer first_node = a.release();
node_pointer first_node = creator.create(*n);
node_pointer end = first_node;
first_node->hash_ = key_hash;
prev->next_ = static_cast<link_pointer>(first_node);
@ -744,56 +733,7 @@ namespace boost { namespace unordered { namespace detail {
for (++n; n != group_end; ++n)
{
a.construct_node();
a.construct_value2(*n);
end = a.release();
end->hash_ = key_hash;
add_after_node(end, first_node);
++dst.size_;
}
prev = place_in_bucket(dst, prev, end);
}
}
////////////////////////////////////////////////////////////////////////
// move_buckets_to
//
// Basic exception safety. The source nodes are left in an unusable
// state if an exception throws.
static void move_buckets_to(buckets& src, buckets& dst)
{
BOOST_ASSERT(!dst.buckets_);
dst.create_buckets(dst.bucket_count_);
node_constructor a(dst.node_alloc());
iterator n = src.get_start();
previous_pointer prev = dst.get_previous_start();
while (n.node_) {
std::size_t key_hash = n.node_->hash_;
iterator group_end(
static_cast<node_pointer>(
static_cast<node_pointer>(n.node_->group_prev_)->next_
));
a.construct_node();
a.construct_value2(boost::move(*n));
node_pointer first_node = a.release();
node_pointer end = first_node;
first_node->hash_ = key_hash;
prev->next_ = static_cast<link_pointer>(first_node);
++dst.size_;
for(++n; n != group_end; ++n)
{
a.construct_node();
a.construct_value2(boost::move(*n));
end = a.release();
end = creator.create(*n);
end->hash_ = key_hash;
add_after_node(end, first_node);
++dst.size_;

View File

@ -54,6 +54,45 @@ namespace boost { namespace unordered { namespace detail {
value_base& operator=(value_base const&);
};
template <typename NodeAlloc>
struct copy_nodes
{
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
node_allocator_traits;
node_constructor<NodeAlloc> constructor;
explicit copy_nodes(NodeAlloc& a) : constructor(a) {}
typename node_allocator_traits::pointer create(
typename node_allocator_traits::value_type::value_type const& v)
{
constructor.construct_node();
constructor.construct_value2(v);
return constructor.release();
}
};
template <typename NodeAlloc>
struct move_nodes
{
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
node_allocator_traits;
node_constructor<NodeAlloc> constructor;
explicit move_nodes(NodeAlloc& a) : constructor(a) {}
typename node_allocator_traits::pointer create(
typename node_allocator_traits::value_type::value_type& v)
{
constructor.construct_node();
constructor.construct_value2(boost::move(v));
return constructor.release();
}
};
template <typename Types>
struct table :
boost::unordered::detail::buckets<
@ -173,7 +212,9 @@ namespace boost { namespace unordered { namespace detail {
max_load_(0)
{
if(x.size_) {
table_impl::copy_buckets_to(x, *this);
this->create_buckets(this->bucket_count_);
copy_nodes<node_allocator> copy(this->node_alloc());
table_impl::fill_buckets(x.get_start(), *this, copy);
this->max_load_ = calculate_max_load();
}
}
@ -199,11 +240,15 @@ namespace boost { namespace unordered { namespace detail {
this->move_buckets_from(x);
}
else if(x.size_) {
// Use a temporary table because move_buckets_to leaves the
// Use a temporary table because moving the nodes leaves the
// source container in a complete mess.
buckets tmp(x, m);
table_impl::move_buckets_to(tmp, *this);
this->create_buckets(this->bucket_count_);
move_nodes<node_allocator> move(this->node_alloc());
table_impl::fill_buckets(tmp.get_start(), *this, move);
this->max_load_ = calculate_max_load();
}
}
@ -271,7 +316,11 @@ namespace boost { namespace unordered { namespace detail {
buckets b(this->node_alloc(),
x.min_buckets_for_size(x.size_));
buckets tmp(x, move_tag());
table_impl::move_buckets_to(tmp, b);
b.create_buckets(b.bucket_count_);
move_nodes<node_allocator> move(b.node_alloc());
table_impl::fill_buckets(tmp.get_start(), b, move);
b.swap(*this);
}
else {

View File

@ -617,58 +617,16 @@ namespace boost { namespace unordered { namespace detail {
}
////////////////////////////////////////////////////////////////////////
// copy_buckets_to
//
// Basic exception safety. If an exception is thrown this will
// leave dst partially filled and the buckets unset.
// fill_buckets
static void copy_buckets_to(buckets const& src, buckets& dst)
template <class NodeCreator>
static void fill_buckets(iterator n, buckets& dst,
NodeCreator& creator)
{
BOOST_ASSERT(!dst.buckets_);
dst.create_buckets(dst.bucket_count_);
node_constructor a(dst.node_alloc());
iterator n = src.get_start();
previous_pointer prev = dst.get_previous_start();
while(n.node_) {
a.construct_node();
a.construct_value2(*n);
node_pointer node = a.release();
node->hash_ = n.node_->hash_;
prev->next_ = static_cast<link_pointer>(node);
++dst.size_;
++n;
prev = place_in_bucket(dst, prev);
}
}
////////////////////////////////////////////////////////////////////////
// move_buckets_to
//
// Basic exception safety. The source nodes are left in an unusable
// state if an exception throws.
static void move_buckets_to(buckets& src, buckets& dst)
{
BOOST_ASSERT(!dst.buckets_);
dst.create_buckets(dst.bucket_count_);
node_constructor a(dst.node_alloc());
iterator n = src.get_start();
previous_pointer prev = dst.get_previous_start();
while (n.node_) {
a.construct_node();
a.construct_value2(boost::move(*n));
node_pointer node = a.release();
node_pointer node = creator.create(*n);
node->hash_ = n.node_->hash_;
prev->next_ = static_cast<link_pointer>(node);
++dst.size_;