mirror of
https://github.com/boostorg/unordered.git
synced 2025-05-11 05:23:58 +00:00
Movable unordered containers, full support only for compilers with rvalue references.
Merged revisions 44076-44414 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/trunk ........ r44076 | danieljames | 2008-04-06 20:41:19 +0100 (Sun, 06 Apr 2008) | 1 line Move semantics for compilers with rvalue references. ........ r44077 | danieljames | 2008-04-06 20:48:59 +0100 (Sun, 06 Apr 2008) | 1 line Do move assignment 'properly'. ........ r44085 | danieljames | 2008-04-06 22:46:04 +0100 (Sun, 06 Apr 2008) | 1 line Use normal references for the move members, reset the source buckets_ pointer to stop the buckets getting deleted, and remove a superflous pointer check. ........ r44109 | danieljames | 2008-04-07 23:49:36 +0100 (Mon, 07 Apr 2008) | 1 line Add missing tests. ........ r44366 | danieljames | 2008-04-13 12:59:46 +0100 (Sun, 13 Apr 2008) | 1 line Avoid using rvalue references in the implementation files. ........ r44368 | danieljames | 2008-04-13 15:13:33 +0100 (Sun, 13 Apr 2008) | 6 lines Use a cut down version of the work in progress move library to implement move semantics on more compilers. Unfortunately the move constructor with allocator isn't really practical at the moment, since in the case where the container can't be moved, and the allocators aren't equal it will copy the container twice. ........ [SVN r44486]
This commit is contained in:
parent
5989e9227c
commit
cf529e496a
18
include/boost/unordered/detail/config.hpp
Normal file
18
include/boost/unordered/detail/config.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
// Copyright 2008 Daniel James.
|
||||
// Distributed under 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)
|
||||
|
||||
#if !defined(BOOST_UNORDERED_DETAIL_CONFIG_HEADER)
|
||||
#define BOOST_UNORDERED_DETAIL_CONFIG_HEADER
|
||||
|
||||
#include <boost/config.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
|
||||
#endif
|
||||
|
||||
#endif
|
@ -121,6 +121,7 @@ namespace boost {
|
||||
}
|
||||
#endif
|
||||
|
||||
struct move_tag {};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,6 +323,53 @@ namespace boost {
|
||||
buckets_(), bucket_count_(next_prime(n)),
|
||||
cached_begin_bucket_(), size_(0)
|
||||
{
|
||||
BOOST_UNORDERED_MSVC_RESET_PTR(buckets_);
|
||||
create_buckets();
|
||||
}
|
||||
|
||||
BOOST_UNORDERED_TABLE_DATA(BOOST_UNORDERED_TABLE_DATA const& x, size_type n)
|
||||
: allocators_(x.allocators_),
|
||||
buckets_(), bucket_count_(next_prime(n)),
|
||||
cached_begin_bucket_(), size_(0)
|
||||
{
|
||||
BOOST_UNORDERED_MSVC_RESET_PTR(buckets_);
|
||||
create_buckets();
|
||||
}
|
||||
|
||||
BOOST_UNORDERED_TABLE_DATA(BOOST_UNORDERED_TABLE_DATA& x, move_tag)
|
||||
: allocators_(x.allocators_),
|
||||
buckets_(x.buckets_), bucket_count_(x.bucket_count_),
|
||||
cached_begin_bucket_(x.cached_begin_bucket_), size_(x.size_)
|
||||
{
|
||||
unordered_detail::reset(x.buckets_);
|
||||
}
|
||||
|
||||
BOOST_UNORDERED_TABLE_DATA(BOOST_UNORDERED_TABLE_DATA& x,
|
||||
value_allocator const& a, size_type n, move_tag)
|
||||
: allocators_(a), buckets_(), bucket_count_(),
|
||||
cached_begin_bucket_(), size_(0)
|
||||
{
|
||||
if(allocators_ == x.allocators_) {
|
||||
buckets_ = x.buckets_;
|
||||
bucket_count_ = x.bucket_count_;
|
||||
cached_begin_bucket_ = x.cached_begin_bucket_;
|
||||
size_ = x.size_;
|
||||
unordered_detail::reset(x.buckets_);
|
||||
}
|
||||
else {
|
||||
BOOST_UNORDERED_MSVC_RESET_PTR(buckets_);
|
||||
bucket_count_ = next_prime(n);
|
||||
create_buckets();
|
||||
}
|
||||
}
|
||||
|
||||
// no throw
|
||||
~BOOST_UNORDERED_TABLE_DATA()
|
||||
{
|
||||
delete_buckets();
|
||||
}
|
||||
|
||||
void create_buckets() {
|
||||
// The array constructor will clean up in the event of an
|
||||
// exception.
|
||||
allocator_array_constructor<bucket_allocator>
|
||||
@ -341,31 +388,8 @@ namespace boost {
|
||||
buckets_ = constructor.release();
|
||||
}
|
||||
|
||||
BOOST_UNORDERED_TABLE_DATA(BOOST_UNORDERED_TABLE_DATA const& x, size_type n)
|
||||
: allocators_(x.allocators_),
|
||||
buckets_(), bucket_count_(next_prime(n)),
|
||||
cached_begin_bucket_(), size_(0)
|
||||
{
|
||||
// The array constructor will clean up in the event of an
|
||||
// exception.
|
||||
allocator_array_constructor<bucket_allocator>
|
||||
constructor(allocators_.bucket_alloc_);
|
||||
|
||||
// Creates an extra bucket to act as a sentinel.
|
||||
constructor.construct(bucket(), bucket_count_ + 1);
|
||||
|
||||
cached_begin_bucket_ = constructor.get() + static_cast<difference_type>(bucket_count_);
|
||||
|
||||
// Set up the sentinel
|
||||
cached_begin_bucket_->next_ = link_ptr(cached_begin_bucket_);
|
||||
|
||||
// Only release the buckets once everything is successfully
|
||||
// done.
|
||||
buckets_ = constructor.release();
|
||||
}
|
||||
|
||||
// no throw
|
||||
~BOOST_UNORDERED_TABLE_DATA()
|
||||
void delete_buckets()
|
||||
{
|
||||
if(buckets_) {
|
||||
bucket_ptr begin = cached_begin_bucket_;
|
||||
@ -400,6 +424,17 @@ namespace boost {
|
||||
std::swap(size_, other.size_);
|
||||
}
|
||||
|
||||
// no throw
|
||||
void move(BOOST_UNORDERED_TABLE_DATA& other)
|
||||
{
|
||||
delete_buckets();
|
||||
buckets_ = other.buckets_;
|
||||
unordered_detail::reset(other.buckets_);
|
||||
bucket_count_ = other.bucket_count_;
|
||||
cached_begin_bucket_ = other.cached_begin_bucket_;
|
||||
size_ = other.size_;
|
||||
}
|
||||
|
||||
// Return the bucket for a hashed value.
|
||||
//
|
||||
// no throw
|
||||
@ -1114,6 +1149,36 @@ namespace boost {
|
||||
copy_buckets(x.data_, data_, current_functions());
|
||||
}
|
||||
|
||||
// Move Construct
|
||||
|
||||
BOOST_UNORDERED_TABLE(BOOST_UNORDERED_TABLE& x, move_tag m)
|
||||
: func1_(x.current_functions()), // throws
|
||||
func2_(x.current_functions()), // throws
|
||||
func_(&BOOST_UNORDERED_TABLE::func1_), // no throw
|
||||
mlf_(x.mlf_), // no throw
|
||||
data_(x.data_, m) // throws
|
||||
{
|
||||
calculate_max_load(); // no throw
|
||||
}
|
||||
|
||||
BOOST_UNORDERED_TABLE(BOOST_UNORDERED_TABLE& x,
|
||||
value_allocator const& a, move_tag m)
|
||||
: func1_(x.current_functions()), // throws
|
||||
func2_(x.current_functions()), // throws
|
||||
func_(&BOOST_UNORDERED_TABLE::func1_), // no throw
|
||||
mlf_(x.mlf_), // no throw
|
||||
data_(x.data_, a,
|
||||
x.min_buckets_for_size(x.size()), m) // throws
|
||||
{
|
||||
calculate_max_load(); // no throw
|
||||
|
||||
if(x.data_.buckets_) {
|
||||
// This can throw, but BOOST_UNORDERED_TABLE_DATA's destructor will clean
|
||||
// up.
|
||||
copy_buckets(x.data_, data_, current_functions());
|
||||
}
|
||||
}
|
||||
|
||||
// Assign
|
||||
//
|
||||
// basic exception safety, if copy_functions of reserver throws
|
||||
@ -1185,6 +1250,41 @@ namespace boost {
|
||||
x.calculate_max_load();
|
||||
}
|
||||
|
||||
// Move
|
||||
//
|
||||
// ----------------------------------------------------------------
|
||||
//
|
||||
// Strong exception safety (might change unused function objects)
|
||||
//
|
||||
// Can throw if hash or predicate object's copy constructor throws
|
||||
// or if allocators are unequal.
|
||||
|
||||
void move(BOOST_UNORDERED_TABLE& x)
|
||||
{
|
||||
// This only effects the function objects that aren't in use
|
||||
// so it is strongly exception safe, via. double buffering.
|
||||
functions_ptr new_func_this = copy_functions(x); // throws
|
||||
|
||||
if(data_.allocators_ == x.data_.allocators_) {
|
||||
data_.move(x.data_); // no throw
|
||||
}
|
||||
else {
|
||||
// Create new buckets in separate HASH_TABLE_DATA objects
|
||||
// which will clean up if anything throws an exception.
|
||||
// (all can throw, but with no effect as these are new objects).
|
||||
data new_this(data_, x.min_buckets_for_size(x.data_.size_));
|
||||
copy_buckets(x.data_, new_this, this->*new_func_this);
|
||||
|
||||
// Start updating the data here, no throw from now on.
|
||||
data_.move(new_this);
|
||||
}
|
||||
|
||||
// We've made it, the rest is no throw.
|
||||
mlf_ = x.mlf_;
|
||||
func_ = new_func_this;
|
||||
calculate_max_load();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
functions const& current_functions() const
|
||||
|
228
include/boost/unordered/detail/move.hpp
Normal file
228
include/boost/unordered/detail/move.hpp
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
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/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/unordered/detail/config.hpp>
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
namespace boost {
|
||||
namespace unordered_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;
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#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 unordered_detail
|
||||
} // namespace boost
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#endif
|
||||
|
||||
/*************************************************************************************************/
|
@ -21,6 +21,10 @@
|
||||
#include <boost/unordered/detail/hash_table.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
#if !defined(BOOST_HAS_RVALUE_REFS)
|
||||
#include <boost/unordered/detail/move.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <class Key,
|
||||
@ -100,6 +104,35 @@ namespace boost
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS)
|
||||
unordered_map(unordered_map&& other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_map(unordered_map&& other, allocator_type const& a)
|
||||
: base(other.base, a, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_map& operator=(unordered_map&& x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
unordered_map(boost::unordered_detail::move_from<unordered_map> other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_map& operator=(unordered_map x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
BOOST_DEDUCED_TYPENAME implementation::iterator_base const&
|
||||
@ -424,6 +457,36 @@ namespace boost
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS)
|
||||
unordered_multimap(unordered_multimap&& other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multimap(unordered_multimap&& other, allocator_type const& a)
|
||||
: base(other.base, a, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multimap& operator=(unordered_multimap&& x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
unordered_multimap(boost::unordered_detail::move_from<unordered_multimap> other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multimap& operator=(unordered_multimap x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
private:
|
||||
|
||||
BOOST_DEDUCED_TYPENAME implementation::iterator_base const&
|
||||
|
@ -21,6 +21,10 @@
|
||||
#include <boost/unordered/detail/hash_table.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
#if !defined(BOOST_HAS_RVALUE_REFS)
|
||||
#include <boost/unordered/detail/move.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <class Value,
|
||||
@ -97,6 +101,35 @@ namespace boost
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS)
|
||||
unordered_set(unordered_set&& other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_set(unordered_set&& other, allocator_type const& a)
|
||||
: base(other.base, a, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_set& operator=(unordered_set&& x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
unordered_set(boost::unordered_detail::move_from<unordered_set> other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_set& operator=(unordered_set x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
BOOST_DEDUCED_TYPENAME implementation::iterator_base const&
|
||||
@ -392,6 +425,35 @@ namespace boost
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS)
|
||||
unordered_multiset(unordered_multiset&& other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multiset(unordered_multiset&& other, allocator_type const& a)
|
||||
: base(other.base, a, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multiset& operator=(unordered_multiset&& x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
unordered_multiset(boost::unordered_detail::move_from<unordered_multiset> other)
|
||||
: base(other.base, boost::unordered_detail::move_tag())
|
||||
{
|
||||
}
|
||||
|
||||
unordered_multiset& operator=(unordered_multiset x)
|
||||
{
|
||||
base.move(x.base);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
BOOST_DEDUCED_TYPENAME implementation::iterator_base const&
|
||||
|
@ -21,6 +21,7 @@ test-suite unordered
|
||||
[ run equivalent_keys_tests.cpp ]
|
||||
[ run constructor_tests.cpp ]
|
||||
[ run copy_tests.cpp ]
|
||||
[ run move_tests.cpp ]
|
||||
[ run assign_tests.cpp ]
|
||||
[ run insert_tests.cpp ]
|
||||
[ run insert_stable_tests.cpp ]
|
||||
|
158
test/unordered/move_tests.cpp
Normal file
158
test/unordered/move_tests.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
|
||||
// Copyright 2008 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
namespace move_tests
|
||||
{
|
||||
test::seed_t seed(98624);
|
||||
|
||||
template<class T>
|
||||
T empty(T* ptr) {
|
||||
return T();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T create(test::random_values<T> const& v,
|
||||
BOOST_DEDUCED_TYPENAME T::value_type const*& first) {
|
||||
T x(v.begin(), v.end());
|
||||
first = &*x.begin();
|
||||
return x;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T create(test::random_values<T> const& v,
|
||||
BOOST_DEDUCED_TYPENAME T::value_type const*& first,
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf,
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq,
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al,
|
||||
float mlf) {
|
||||
T x(0, hf, eq, al);
|
||||
x.max_load_factor(mlf);
|
||||
x.insert(v.begin(), v.end());
|
||||
first = &*x.begin();
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void move_construct_tests1(T* ptr, test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al;
|
||||
|
||||
{
|
||||
T y(empty(ptr));
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(y.max_load_factor() == 1.0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::random_values<T> v(1000);
|
||||
BOOST_DEDUCED_TYPENAME T::value_type const* first = 0;
|
||||
T y(create(v, first));
|
||||
BOOST_TEST(first == &*y.begin());
|
||||
test::check_container(y, v);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void move_assign_tests1(T* ptr, test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
{
|
||||
test::random_values<T> v(500);
|
||||
BOOST_DEDUCED_TYPENAME T::value_type const* first = 0;
|
||||
T y;
|
||||
y = create(v, first);
|
||||
BOOST_TEST(first == &*y.begin());
|
||||
test::check_container(y, v);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void move_construct_tests2(T* ptr,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
move_construct_tests1(ptr);
|
||||
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf(1);
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al(1);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
|
||||
|
||||
BOOST_DEDUCED_TYPENAME T::value_type const* first;
|
||||
|
||||
{
|
||||
test::random_values<T> v(500);
|
||||
T y(create(v, first, hf, eq, al, 0.5));
|
||||
BOOST_TEST(first == &*y.begin());
|
||||
test::check_container(y, v);
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(y.max_load_factor() == 0.5); // Not necessarily required.
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
// TODO: To do this correctly requires the fancy new allocator stuff.
|
||||
test::random_values<T> v(500);
|
||||
T y(create(v, first, hf, eq, al, 2.0), al2);
|
||||
BOOST_TEST(first != &*y.begin());
|
||||
test::check_container(y, v);
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
BOOST_TEST(y.max_load_factor() == 2.0); // Not necessarily required.
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::random_values<T> v(25);
|
||||
T y(create(v, first, hf, eq, al, 1.0), al);
|
||||
BOOST_TEST(first == &*y.begin());
|
||||
test::check_container(y, v);
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(y.max_load_factor() == 1.0); // Not necessarily required.
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(move_construct_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
)
|
||||
UNORDERED_TEST(move_assign_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
)
|
||||
UNORDERED_TEST(move_construct_tests2,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
Loading…
x
Reference in New Issue
Block a user