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

@ -134,4 +134,8 @@ First official release.
* Fix a bug when inserting into an `unordered_map` or `unordered_set` using
iterators which returns `value_type` by copy.
[h2 Boost 1.48.0]
* Use Boost.Move
[endsect]

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:
//

View File

@ -19,10 +19,6 @@
#include <boost/unordered/detail/equivalent.hpp>
#include <boost/unordered/detail/unique.hpp>
#if defined(BOOST_NO_RVALUE_REFERENCES)
#include <boost/unordered/detail/move.hpp>
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
#include <initializer_list>
#endif
@ -43,6 +39,7 @@ namespace unordered
template <class K, class T, class H, class P, class A>
class unordered_map
{
BOOST_COPYABLE_AND_MOVABLE(unordered_map)
public:
typedef K key_type;
typedef std::pair<const K, T> value_type;
@ -129,19 +126,30 @@ namespace unordered
~unordered_map();
#if !defined(BOOST_NO_RVALUE_REFERENCES)
unordered_map& operator=(
BOOST_COPY_ASSIGN_REF(unordered_map) x)
{
table_ = x.table_;
return *this;
}
unordered_map& operator=(
BOOST_RV_REF(unordered_map) x)
{
table_.move(x.table_);
return *this;
}
unordered_map(unordered_map const&);
unordered_map(unordered_map&&);
unordered_map(BOOST_RV_REF(unordered_map) other)
: table_(other.table_, ::boost::unordered::detail::move_tag())
{
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
unordered_map(unordered_map&&, allocator_type const&);
unordered_map& operator=(unordered_map const&);
unordered_map& operator=(unordered_map&&);
#else
unordered_map(::boost::unordered::detail::move_from<
unordered_map<K,T,H,P,A>
>);
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
unordered_map& operator=(unordered_map);
#endif
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
@ -368,6 +376,7 @@ namespace unordered
template <class K, class T, class H, class P, class A>
class unordered_multimap
{
BOOST_COPYABLE_AND_MOVABLE(unordered_multimap)
public:
typedef K key_type;
@ -455,20 +464,29 @@ namespace unordered
~unordered_multimap();
#if !defined(BOOST_NO_RVALUE_REFERENCES)
unordered_multimap(unordered_multimap const&);
unordered_multimap(unordered_multimap&&);
unordered_multimap(unordered_multimap&&, allocator_type const&);
unordered_multimap& operator=(unordered_multimap const&);
unordered_multimap& operator=(unordered_multimap&&);
#else
unordered_multimap(::boost::unordered::detail::move_from<
unordered_multimap<K,T,H,P,A>
>);
unordered_multimap& operator=(
BOOST_COPY_ASSIGN_REF(unordered_multimap) x)
{
table_ = x.table_;
return *this;
}
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
unordered_multimap& operator=(unordered_multimap);
#endif
unordered_multimap& operator=(
BOOST_RV_REF(unordered_multimap) x)
{
table_.move(x.table_);
return *this;
}
unordered_multimap(unordered_multimap const&);
unordered_multimap(BOOST_RV_REF(unordered_multimap) other)
: table_(other.table_, ::boost::unordered::detail::move_tag())
{
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
unordered_multimap(unordered_multimap&&, allocator_type const&);
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
@ -751,18 +769,13 @@ namespace unordered
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::~unordered_map() {}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(unordered_map const& other)
: table_(other.table_)
{
}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(unordered_map&& other)
: table_(other.table_, ::boost::unordered::detail::move_tag())
{
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(
@ -771,42 +784,10 @@ namespace unordered
{
}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>& unordered_map<K,T,H,P,A>::
operator=(unordered_map const& x)
{
table_ = x.table_;
return *this;
}
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>& unordered_map<K,T,H,P,A>::
operator=(unordered_map&& x)
{
table_.move(x.table_);
return *this;
}
#else
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(
::boost::unordered::detail::move_from<unordered_map<K,T,H,P,A> >
other)
: table_(other.source.table_, ::boost::unordered::detail::move_tag())
{
}
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>& unordered_map<K,T,H,P,A>::
operator=(unordered_map x)
{
table_.move(x.table_);
return *this;
}
#endif
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
template <class K, class T, class H, class P, class A>
unordered_map<K,T,H,P,A>::unordered_map(
std::initializer_list<value_type> list, size_type n,
@ -827,6 +808,7 @@ namespace unordered
table_.insert_range(list.begin(), list.end());
return *this;
}
#endif
// size and capacity
@ -1203,7 +1185,6 @@ namespace unordered
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::~unordered_multimap() {}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
unordered_multimap const& other)
@ -1211,12 +1192,7 @@ namespace unordered
{
}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
unordered_multimap&& other)
: table_(other.table_, ::boost::unordered::detail::move_tag())
{
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
@ -1225,41 +1201,6 @@ namespace unordered
{
}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>& unordered_multimap<K,T,H,P,A>::
operator=(unordered_multimap const& x)
{
table_ = x.table_;
return *this;
}
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>& unordered_multimap<K,T,H,P,A>::
operator=(unordered_multimap&& x)
{
table_.move(x.table_);
return *this;
}
#else
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>::unordered_multimap(
::boost::unordered::detail::move_from<
unordered_multimap<K,T,H,P,A> > other)
: table_(other.source.table_, ::boost::unordered::detail::move_tag())
{
}
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
template <class K, class T, class H, class P, class A>
unordered_multimap<K,T,H,P,A>& unordered_multimap<K,T,H,P,A>::
operator=(unordered_multimap x)
{
table_.move(x.table_);
return *this;
}
#endif
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)

View File

@ -19,10 +19,6 @@
#include <boost/unordered/detail/equivalent.hpp>
#include <boost/unordered/detail/unique.hpp>
#if defined(BOOST_NO_RVALUE_REFERENCES)
#include <boost/unordered/detail/move.hpp>
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
#include <initializer_list>
#endif
@ -43,6 +39,7 @@ namespace unordered
template <class T, class H, class P, class A>
class unordered_set
{
BOOST_COPYABLE_AND_MOVABLE(unordered_set)
public:
typedef T key_type;
@ -127,19 +124,29 @@ namespace unordered
~unordered_set();
#if !defined(BOOST_NO_RVALUE_REFERENCES)
unordered_set& operator=(
BOOST_COPY_ASSIGN_REF(unordered_set) x)
{
table_ = x.table_;
return *this;
}
unordered_set& operator=(
BOOST_RV_REF(unordered_set) x)
{
table_.move(x.table_);
return *this;
}
unordered_set(unordered_set const&);
unordered_set(unordered_set&&);
unordered_set(BOOST_RV_REF(unordered_set) other)
: table_(other.table_, ::boost::unordered::detail::move_tag())
{
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
unordered_set(unordered_set&&, allocator_type const&);
unordered_set& operator=(unordered_set const&);
unordered_set& operator=(unordered_set&&);
#else
unordered_set(::boost::unordered::detail::move_from<
unordered_set<T,H,P,A>
>);
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
unordered_set& operator=(unordered_set);
#endif
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
@ -349,6 +356,7 @@ namespace unordered
template <class T, class H, class P, class A>
class unordered_multiset
{
BOOST_COPYABLE_AND_MOVABLE(unordered_multiset)
public:
typedef T key_type;
@ -433,20 +441,29 @@ namespace unordered
~unordered_multiset();
#if !defined(BOOST_NO_RVALUE_REFERENCES)
unordered_multiset(unordered_multiset const&);
unordered_multiset(unordered_multiset&&);
unordered_multiset(unordered_multiset&&, allocator_type const&);
unordered_multiset& operator=(unordered_multiset const&);
unordered_multiset& operator=(unordered_multiset&&);
#else
unordered_multiset(::boost::unordered::detail::move_from<
unordered_multiset<T,H,P,A>
>);
unordered_multiset& operator=(
BOOST_COPY_ASSIGN_REF(unordered_multiset) x)
{
table_ = x.table_;
return *this;
}
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
unordered_multiset& operator=(unordered_multiset);
#endif
unordered_multiset& operator=(
BOOST_RV_REF(unordered_multiset) x)
{
table_.move(x.table_);
return *this;
}
unordered_multiset(unordered_multiset const&);
unordered_multiset(BOOST_RV_REF(unordered_multiset) other)
: table_(other.table_, ::boost::unordered::detail::move_tag())
{
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
unordered_multiset(unordered_multiset&&, allocator_type const&);
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
@ -716,18 +733,13 @@ namespace unordered
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::~unordered_set() {}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(unordered_set const& other)
: table_(other.table_)
{
}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(unordered_set&& other)
: table_(other.table_, ::boost::unordered::detail::move_tag())
{
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(
@ -736,42 +748,10 @@ namespace unordered
{
}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>& unordered_set<T,H,P,A>::
operator=(unordered_set const& x)
{
table_ = x.table_;
return *this;
}
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>& unordered_set<T,H,P,A>::
operator=(unordered_set&& x)
{
table_.move(x.table_);
return *this;
}
#else
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(
::boost::unordered::detail::move_from<unordered_set<T,H,P,A> >
other)
: table_(other.source.table_, ::boost::unordered::detail::move_tag())
{
}
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>& unordered_set<T,H,P,A>::
operator=(unordered_set x)
{
table_.move(x.table_);
return *this;
}
#endif
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
template <class T, class H, class P, class A>
unordered_set<T,H,P,A>::unordered_set(
std::initializer_list<value_type> list, size_type n,
@ -792,6 +772,7 @@ namespace unordered
table_.insert_range(list.begin(), list.end());
return *this;
}
#endif
// size and capacity
@ -1114,7 +1095,6 @@ namespace unordered
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::~unordered_multiset() {}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
unordered_multiset const& other)
@ -1122,12 +1102,7 @@ namespace unordered
{
}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
unordered_multiset&& other)
: table_(other.table_, ::boost::unordered::detail::move_tag())
{
}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
@ -1136,41 +1111,6 @@ namespace unordered
{
}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>& unordered_multiset<T,H,P,A>::
operator=(unordered_multiset const& x)
{
table_ = x.table_;
return *this;
}
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>& unordered_multiset<T,H,P,A>::
operator=(unordered_multiset&& x)
{
table_.move(x.table_);
return *this;
}
#else
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>::unordered_multiset(
::boost::unordered::detail::move_from<unordered_multiset<T,H,P,A> >
other)
: table_(other.source.table_, ::boost::unordered::detail::move_tag())
{
}
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
template <class T, class H, class P, class A>
unordered_multiset<T,H,P,A>& unordered_multiset<T,H,P,A>::
operator=(unordered_multiset x)
{
table_.move(x.table_);
return *this;
}
#endif
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)