Unordered: Support moving allocators.

[SVN r73805]
This commit is contained in:
Daniel James
2011-08-15 21:34:01 +00:00
parent 1db630d5c9
commit 08bca9a35f
3 changed files with 106 additions and 11 deletions

View File

@ -65,7 +65,7 @@ namespace boost { namespace unordered { namespace detail {
bucket_ptr buckets_;
std::size_t bucket_count_;
std::size_t size_;
::boost::compressed_pair<bucket_allocator, node_allocator> allocators_;
compressed_pair<bucket_allocator, node_allocator> allocators_;
// Data access
@ -106,22 +106,20 @@ namespace boost { namespace unordered { namespace detail {
{
}
// TODO: Need to move allocators_, not copy. But compressed_pair
// doesn't support move parameters.
buckets(buckets& b, move_tag)
buckets(buckets& b, move_tag m)
: buckets_(),
bucket_count_(b.bucket_count_),
size_(),
allocators_(b.allocators_)
allocators_(b.allocators_, m)
{
swap(b);
}
template <typename T>
buckets(table<T>& x, move_tag)
buckets(table<T>& x, move_tag m)
: buckets_(),
bucket_count_(x.bucket_count_),
allocators_(x.allocators_)
allocators_(x.allocators_, m)
{
swap(x);
x.size_ = 0;
@ -424,7 +422,7 @@ namespace boost { namespace unordered { namespace detail {
friend class set_hash_functions<H, P>;
functions& operator=(functions const&);
typedef ::boost::compressed_pair<H, P> function_pair;
typedef compressed_pair<H, P> function_pair;
typedef BOOST_DEDUCED_TYPENAME ::boost::aligned_storage<
sizeof(function_pair),
::boost::alignment_of<function_pair>::value>::type aligned_function;

View File

@ -245,7 +245,7 @@ namespace boost { namespace unordered { namespace detail {
// aren't deleted with the wrong allocator.
if(this->buckets_) this->delete_buckets();
// TODO: Can allocator assignment throw?
this->allocators_ = x.allocators_;
this->allocators_.assign(x.allocators_);
this->swap(tmp, false_type());
}
@ -259,7 +259,7 @@ namespace boost { namespace unordered { namespace detail {
void move_assign(table& x, true_type)
{
if(this->buckets_) this->delete_buckets();
this->allocators_ = x.allocators_; // TODO: Move allocators, not copy.
this->allocators_.move_assign(x.allocators_);
move_assign_no_alloc(x);
}

View File

@ -19,16 +19,17 @@
#include <boost/assert.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/compressed_pair.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/is_empty.hpp>
#include <boost/throw_exception.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/move/move.hpp>
#include <boost/swap.hpp>
// Template parameters:
//
@ -253,6 +254,102 @@ namespace boost { namespace unordered { namespace detail {
return (std::max)(static_cast<std::size_t>(insert_size(i, j)) + 1,
num_buckets);
}
////////////////////////////////////////////////////////////////////////////
// compressed_pair
template <typename T, int Index>
struct compressed_base : private T
{
compressed_base(T const& x) : T(x) {}
compressed_base(T& x, move_tag) : T(boost::move(x)) {}
T& get() { return *this; }
T const& get() const { return *this; }
};
template <typename T, int Index>
struct uncompressed_base
{
uncompressed_base(T const& x) : value_(x) {}
uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {}
T& get() { return value_; }
T const& get() const { return value_; }
private:
T value_;
};
template <typename T, int Index>
struct generate_base
: boost::detail::if_true<
boost::is_empty<T>::value
>:: BOOST_NESTED_TEMPLATE then<
compressed_base<T, Index>,
uncompressed_base<T, Index>
>
{};
template <typename T1, typename T2>
struct compressed_pair
: private generate_base<T1, 1>::type,
private generate_base<T2, 2>::type
{
typedef BOOST_DEDUCED_TYPENAME generate_base<T1, 1>::type base1;
typedef BOOST_DEDUCED_TYPENAME generate_base<T2, 2>::type base2;
typedef T1 first_type;
typedef T2 second_type;
first_type& first() {
return static_cast<base1*>(this)->get();
}
first_type const& first() const {
return static_cast<base1 const*>(this)->get();
}
second_type& second() {
return static_cast<base2*>(this)->get();
}
second_type const& second() const {
return static_cast<base2 const*>(this)->get();
}
template <typename First, typename Second>
compressed_pair(First const& x1, Second const& x2)
: base1(x1), base2(x2) {}
compressed_pair(compressed_pair const& x)
: base1(x.first()), base2(x.second()) {}
compressed_pair(compressed_pair& x, move_tag m)
: base1(x.first(), m), base2(x.second(), m) {}
void assign(compressed_pair const& x)
{
first() = x.first();
second() = x.second();
}
void move_assign(compressed_pair& x)
{
first() = boost::move(x.first());
second() = boost::move(x.second());
}
void swap(compressed_pair& x)
{
boost::swap(first(), x.first());
boost::swap(second(), x.second());
}
private:
// Prevent assignment just to make use of assign or
// move_assign explicit.
compressed_pair& operator=(compressed_pair const&);
};
}}}
#endif