Unordered: Copy and assign using Boost.Move.

[SVN r73503]
This commit is contained in:
Daniel James
2011-08-03 08:34:33 +00:00
parent fc483e60bc
commit eced4266c2
7 changed files with 159 additions and 469 deletions

View File

@@ -307,6 +307,7 @@ namespace boost { namespace unordered { namespace detail {
}
void copy_buckets_to(buckets&) const;
void move_buckets_to(buckets&) const;
};
// Assigning and swapping the equality and hash function objects
@@ -598,7 +599,7 @@ namespace boost { namespace unordered { namespace detail {
////////////////////////////////////////////////////////////////////////////
// copy_buckets_to
//
// basic excpetion safety. If an exception is thrown this will
// basic exception safety. If an exception is thrown this will
// leave dst partially filled and the buckets unset.
template <class A, bool Unique>
@@ -635,6 +636,47 @@ namespace boost { namespace unordered { namespace detail {
}
}
}
////////////////////////////////////////////////////////////////////////////
// move_buckets_to
//
// Basic exception safety. The source nodes are left in an unusable state
// if an exception throws.
template <class A, bool Unique>
void buckets<A, Unique>::move_buckets_to(buckets& dst) const
{
BOOST_ASSERT(!dst.buckets_);
dst.create_buckets();
bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_);
{
node_constructor<A, Unique> a(dst);
node_ptr n = this->buckets_[this->bucket_count_].next_;
node_ptr prev = dst_start;
while(n) {
std::size_t hash = node::get_hash(n);
node_ptr group_end = node::next_group(n);
a.construct(boost::move(node::get_value(n)));
node_ptr first_node = a.release();
node::set_hash(first_node, hash);
node_ptr end = prev->next_ = first_node;
for(n = n->next_; n != group_end; n = n->next_) {
a.construct(boost::move(node::get_value(n)));
end = a.release();
node::set_hash(end, hash);
node::add_after_node(end, first_node);
}
prev = dst.place_in_bucket(prev, end);
}
}
}
}}}
#endif

View File

@@ -1,245 +0,0 @@
/*
Copyright 2005-2007 Adobe Systems Incorporated
Use, modification and distribution are subject to 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).
*/
/*************************************************************************************************/
#ifndef BOOST_UNORDERED_DETAIL_MOVE_HEADER
#define BOOST_UNORDERED_DETAIL_MOVE_HEADER
#include <boost/config.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/not.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/detail/workaround.hpp>
/*************************************************************************************************/
#if defined(BOOST_NO_SFINAE)
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
#elif defined(__GNUC__) && \
(__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
#elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \
BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \
BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593))
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
#endif
/*************************************************************************************************/
namespace boost {
namespace unordered {
namespace detail {
/*************************************************************************************************/
namespace move_detail {
/*************************************************************************************************/
#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
/*************************************************************************************************/
template <typename T>
struct class_has_move_assign {
class type {
typedef T& (T::*E)(T t);
typedef char (&no_type)[1];
typedef char (&yes_type)[2];
template <E e> struct sfinae { typedef yes_type type; };
template <class U>
static typename sfinae<&U::operator=>::type test(int);
template <class U>
static no_type test(...);
public:
enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
};
};
/*************************************************************************************************/
template<typename T>
struct has_move_assign : ::boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {};
/*************************************************************************************************/
class test_can_convert_anything { };
/*************************************************************************************************/
#endif // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
/*************************************************************************************************/
/*
REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where
::boost::is_convertible<T, T> fails to compile.
*/
template <typename T, typename U>
struct is_convertible : ::boost::mpl::or_<
::boost::is_same<T, U>,
::boost::is_convertible<T, U>
> { };
/*************************************************************************************************/
} //namespace move_detail
/*************************************************************************************************/
/*!
\ingroup move_related
\brief move_from is used for move_ctors.
*/
template <typename T>
struct move_from
{
explicit move_from(T& x) : source(x) { }
T& source;
private:
move_from& operator=(move_from const&);
};
/*************************************************************************************************/
#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
/*************************************************************************************************/
/*!
\ingroup move_related
\brief The is_movable trait can be used to identify movable types.
*/
template <typename T>
struct is_movable : ::boost::mpl::and_<
::boost::is_convertible<move_from<T>, T>,
move_detail::has_move_assign<T>,
::boost::mpl::not_<boost::is_convertible<move_detail::test_can_convert_anything, T> >
> { };
/*************************************************************************************************/
#else // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
// On compilers which don't have adequate SFINAE support, treat most types as unmovable,
// unless the trait is specialized.
template <typename T>
struct is_movable : ::boost::mpl::false_ { };
#endif
/*************************************************************************************************/
#if !defined(BOOST_NO_SFINAE)
/*************************************************************************************************/
/*!
\ingroup move_related
\brief copy_sink and move_sink are used to select between overloaded operations according to
whether type T is movable and convertible to type U.
\sa move
*/
template <typename T,
typename U = T,
typename R = void*>
struct copy_sink : ::boost::enable_if<
::boost::mpl::and_<
::boost::unordered::detail::move_detail::is_convertible<T, U>,
::boost::mpl::not_<is_movable<T> >
>,
R
>
{ };
/*************************************************************************************************/
/*!
\ingroup move_related
\brief move_sink and copy_sink are used to select between overloaded operations according to
whether type T is movable and convertible to type U.
\sa move
*/
template <typename T,
typename U = T,
typename R = void*>
struct move_sink : ::boost::enable_if<
::boost::mpl::and_<
::boost::unordered::detail::move_detail::is_convertible<T, U>,
is_movable<T>
>,
R
>
{ };
/*************************************************************************************************/
/*!
\ingroup move_related
\brief This version of move is selected when T is_movable . It in turn calls the move
constructor. This call, with the help of the return value optimization, will cause x to be moved
instead of copied to its destination. See adobe/test/move/main.cpp for examples.
*/
template <typename T>
T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); }
/*************************************************************************************************/
/*!
\ingroup move_related
\brief This version of move is selected when T is not movable . The net result will be that
x gets copied.
*/
template <typename T>
T& move(T& x, typename copy_sink<T>::type = 0) { return x; }
/*************************************************************************************************/
#else // BOOST_NO_SFINAE
// On compilers without SFINAE, define copy_sink to always use the copy function.
template <typename T,
typename U = T,
typename R = void*>
struct copy_sink
{
typedef R type;
};
// Always copy the element unless this is overloaded.
template <typename T>
T& move(T& x) {
return x;
}
#endif // BOOST_NO_SFINAE
} // namespace detail
} // namespace unordered
} // namespace boost
/*************************************************************************************************/
#endif
/*************************************************************************************************/

View File

@@ -212,7 +212,7 @@ namespace boost { namespace unordered { namespace detail {
this->partial_swap(x);
}
table(table& x, node_allocator const& a, move_tag)
table(table& x, node_allocator const& a, move_tag m)
: buckets(a, x.bucket_count_),
functions(x),
size_(0),
@@ -223,8 +223,11 @@ namespace boost { namespace unordered { namespace detail {
this->partial_swap(x);
}
else if(x.size_) {
x.copy_buckets_to(*this);
this->size_ = x.size_;
// Use a temporary table because move_buckets_to leaves the
// source container in a complete mess.
table tmp(x, m);
tmp.move_buckets_to(*this);
this->size_ = tmp.size_;
this->max_load_ = calculate_max_load();
}
}
@@ -335,10 +338,14 @@ namespace boost { namespace unordered { namespace detail {
else {
// Create new buckets in separate buckets
// which will clean up if anything throws an exception.
// (all can throw, but with no effect as these are new objects).
buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_));
if (x.size_) x.copy_buckets_to(b);
if (x.size_) {
// Use a temporary table because move_buckets_to leaves the
// source container in a complete mess.
table tmp(x, move_tag());
tmp.move_buckets_to(b);
}
// Start updating the data here, no throw from now on.
this->size_ = x.size_;

View File

@@ -27,6 +27,7 @@
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/move/move.hpp>
// Template parameters:
//