forked from boostorg/unordered
Swap noexcept support
Not properly supported as we don't have is_nothrow_swappable yet.
This commit is contained in:
@ -31,12 +31,15 @@
|
||||
#include <boost/type_traits/add_lvalue_reference.hpp>
|
||||
#include <boost/type_traits/aligned_storage.hpp>
|
||||
#include <boost/type_traits/alignment_of.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
#include <boost/type_traits/is_class.hpp>
|
||||
#include <boost/type_traits/is_const.hpp>
|
||||
#include <boost/type_traits/is_empty.hpp>
|
||||
#include <boost/type_traits/is_nothrow_move_assignable.hpp>
|
||||
#include <boost/type_traits/is_nothrow_move_constructible.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/is_scalar.hpp>
|
||||
#include <boost/type_traits/remove_const.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
#include <boost/utility/addressof.hpp>
|
||||
@ -751,6 +754,19 @@ namespace boost {
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// is_nothrow_swappable
|
||||
//
|
||||
// TODO: Replace this very basic implementation when the full type_traits
|
||||
// implementation is available.
|
||||
|
||||
template <class T>
|
||||
struct is_nothrow_swappable
|
||||
: boost::integral_constant<bool,
|
||||
boost::is_scalar<T>::value && !boost::is_const<T>::value>
|
||||
{
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// value_base
|
||||
//
|
||||
@ -2756,6 +2772,9 @@ namespace boost {
|
||||
static const bool nothrow_move_constructible =
|
||||
boost::is_nothrow_move_constructible<H>::value &&
|
||||
boost::is_nothrow_move_constructible<P>::value;
|
||||
static const bool nothrow_swappable =
|
||||
boost::unordered::detail::is_nothrow_swappable<H>::value &&
|
||||
boost::unordered::detail::is_nothrow_swappable<P>::value;
|
||||
|
||||
private:
|
||||
friend class boost::unordered::detail::set_hash_functions<H, P,
|
||||
@ -3279,14 +3298,12 @@ namespace boost {
|
||||
allocators_.swap(other.allocators_);
|
||||
}
|
||||
|
||||
// Only swaps the allocators if propagate_on_container_swap
|
||||
void swap(table& x)
|
||||
// Not nothrow swappable
|
||||
void swap(table& x, false_type)
|
||||
{
|
||||
set_hash_functions op1(*this, x);
|
||||
set_hash_functions op2(x, *this);
|
||||
|
||||
// I think swap can throw if Propagate::value,
|
||||
// since the allocators' swap can throw. Not sure though.
|
||||
swap_allocators(
|
||||
x, boost::unordered::detail::integral_constant<bool,
|
||||
allocator_traits<
|
||||
@ -3301,6 +3318,34 @@ namespace boost {
|
||||
op2.commit();
|
||||
}
|
||||
|
||||
// Nothrow swappable
|
||||
void swap(table& x, true_type)
|
||||
{
|
||||
swap_allocators(
|
||||
x, boost::unordered::detail::integral_constant<bool,
|
||||
allocator_traits<
|
||||
node_allocator>::propagate_on_container_swap::value>());
|
||||
|
||||
boost::swap(buckets_, x.buckets_);
|
||||
boost::swap(bucket_count_, x.bucket_count_);
|
||||
boost::swap(size_, x.size_);
|
||||
std::swap(mlf_, x.mlf_);
|
||||
std::swap(max_load_, x.max_load_);
|
||||
this->current_functions().swap(x.current_functions());
|
||||
}
|
||||
|
||||
// Only swaps the allocators if propagate_on_container_swap.
|
||||
// If not propagate_on_container_swap and allocators aren't
|
||||
// equal, behaviour is undefined.
|
||||
void swap(table& x)
|
||||
{
|
||||
BOOST_ASSERT(allocator_traits<
|
||||
node_allocator>::propagate_on_container_swap::value ||
|
||||
node_alloc() == x.node_alloc());
|
||||
swap(x, boost::unordered::detail::integral_constant<bool,
|
||||
functions::nothrow_swappable>());
|
||||
}
|
||||
|
||||
// Only call with nodes allocated with the currect allocator, or
|
||||
// one that is equal to it. (Can't assert because other's
|
||||
// allocators might have already been moved).
|
||||
|
@ -715,11 +715,10 @@ namespace boost {
|
||||
BOOST_UNORDERED_DEPRECATED("Use erase instead")
|
||||
void erase_return_void(const_iterator it) { erase(it); }
|
||||
|
||||
void swap(unordered_map&);
|
||||
// C++17 support: BOOST_NOEXCEPT_IF(
|
||||
// value_allocator_traits::is_always_equal::value &&
|
||||
// is_nothrow_move_assignable_v<H> &&
|
||||
// is_nothrow_move_assignable_v<P>)
|
||||
void swap(unordered_map&)
|
||||
BOOST_NOEXCEPT_IF(value_allocator_traits::is_always_equal::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<H>::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<P>::value);
|
||||
void clear() BOOST_NOEXCEPT { table_.clear_impl(); }
|
||||
|
||||
template <typename H2, typename P2>
|
||||
@ -1327,11 +1326,10 @@ namespace boost {
|
||||
BOOST_UNORDERED_DEPRECATED("Use erase instead")
|
||||
void erase_return_void(const_iterator it) { erase(it); }
|
||||
|
||||
void swap(unordered_multimap&);
|
||||
// C++17 support: BOOST_NOEXCEPT_IF(
|
||||
// value_allocator_traits::is_always_equal::value &&
|
||||
// is_nothrow_move_assignable_v<H> &&
|
||||
// is_nothrow_move_assignable_v<P>)
|
||||
void swap(unordered_multimap&)
|
||||
BOOST_NOEXCEPT_IF(value_allocator_traits::is_always_equal::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<H>::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<P>::value);
|
||||
void clear() BOOST_NOEXCEPT { table_.clear_impl(); }
|
||||
|
||||
template <typename H2, typename P2>
|
||||
@ -1740,10 +1738,9 @@ namespace boost {
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
void unordered_map<K, T, H, P, A>::swap(unordered_map& other)
|
||||
// C++17 support: BOOST_NOEXCEPT_IF(
|
||||
// value_allocator_traits::is_always_equal::value &&
|
||||
// is_nothrow_move_assignable_v<H> &&
|
||||
// is_nothrow_move_assignable_v<P>)
|
||||
BOOST_NOEXCEPT_IF(value_allocator_traits::is_always_equal::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<H>::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<P>::value)
|
||||
{
|
||||
table_.swap(other.table_);
|
||||
}
|
||||
@ -2217,10 +2214,9 @@ namespace boost {
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
void unordered_multimap<K, T, H, P, A>::swap(unordered_multimap& other)
|
||||
// C++17 support: BOOST_NOEXCEPT_IF(
|
||||
// value_allocator_traits::is_always_equal::value &&
|
||||
// is_nothrow_move_assignable_v<H> &&
|
||||
// is_nothrow_move_assignable_v<P>)
|
||||
BOOST_NOEXCEPT_IF(value_allocator_traits::is_always_equal::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<H>::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<P>::value)
|
||||
{
|
||||
table_.swap(other.table_);
|
||||
}
|
||||
|
@ -441,11 +441,10 @@ namespace boost {
|
||||
BOOST_UNORDERED_DEPRECATED("Use erase instead")
|
||||
void erase_return_void(const_iterator it) { erase(it); }
|
||||
|
||||
void swap(unordered_set&);
|
||||
// C++17 support: BOOST_NOEXCEPT_IF(
|
||||
// value_allocator_traits::is_always_equal::value &&
|
||||
// is_nothrow_move_assignable_v<H> &&
|
||||
// is_nothrow_move_assignable_v<P>)
|
||||
void swap(unordered_set&)
|
||||
BOOST_NOEXCEPT_IF(value_allocator_traits::is_always_equal::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<H>::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<P>::value);
|
||||
void clear() BOOST_NOEXCEPT { table_.clear_impl(); }
|
||||
|
||||
template <typename H2, typename P2>
|
||||
@ -991,11 +990,10 @@ namespace boost {
|
||||
BOOST_UNORDERED_DEPRECATED("Use erase instead")
|
||||
void erase_return_void(const_iterator it) { erase(it); }
|
||||
|
||||
void swap(unordered_multiset&);
|
||||
// C++17 support: BOOST_NOEXCEPT_IF(
|
||||
// value_allocator_traits::is_always_equal::value &&
|
||||
// is_nothrow_move_assignable_v<H> &&
|
||||
// is_nothrow_move_assignable_v<P>)
|
||||
void swap(unordered_multiset&)
|
||||
BOOST_NOEXCEPT_IF(value_allocator_traits::is_always_equal::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<H>::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<P>::value);
|
||||
void clear() BOOST_NOEXCEPT { table_.clear_impl(); }
|
||||
|
||||
template <typename H2, typename P2>
|
||||
@ -1365,10 +1363,9 @@ namespace boost {
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
void unordered_set<T, H, P, A>::swap(unordered_set& other)
|
||||
// C++17 support: BOOST_NOEXCEPT_IF(
|
||||
// value_allocator_traits::is_always_equal::value &&
|
||||
// is_nothrow_move_assignable_v<H> &&
|
||||
// is_nothrow_move_assignable_v<P>)
|
||||
BOOST_NOEXCEPT_IF(value_allocator_traits::is_always_equal::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<H>::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<P>::value)
|
||||
{
|
||||
table_.swap(other.table_);
|
||||
}
|
||||
@ -1760,10 +1757,9 @@ namespace boost {
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
void unordered_multiset<T, H, P, A>::swap(unordered_multiset& other)
|
||||
// C++17 support: BOOST_NOEXCEPT_IF(
|
||||
// value_allocator_traits::is_always_equal::value &&
|
||||
// is_nothrow_move_assignable_v<H> &&
|
||||
// is_nothrow_move_assignable_v<P>)
|
||||
BOOST_NOEXCEPT_IF(value_allocator_traits::is_always_equal::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<H>::value&&
|
||||
boost::unordered::detail::is_nothrow_swappable<P>::value)
|
||||
{
|
||||
table_.swap(other.table_);
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ namespace noexcept_tests {
|
||||
};
|
||||
|
||||
typedef hash_nothrow<true, false, false> hash_nothrow_move;
|
||||
typedef hash_nothrow<false, false, true> hash_nothrow_swap;
|
||||
|
||||
template <bool nothrow_move_construct, bool nothrow_move_assign,
|
||||
bool nothrow_swap>
|
||||
@ -137,14 +138,18 @@ namespace noexcept_tests {
|
||||
};
|
||||
|
||||
typedef equal_to_nothrow<true, false, false> equal_to_nothrow_move;
|
||||
typedef equal_to_nothrow<false, false, true> equal_to_nothrow_swap;
|
||||
|
||||
bool have_is_nothrow_move = false;
|
||||
bool have_is_nothrow_swap = false;
|
||||
|
||||
UNORDERED_AUTO_TEST (check_is_nothrow_move) {
|
||||
BOOST_TEST(
|
||||
!boost::is_nothrow_move_constructible<hash_possible_exception>::value);
|
||||
have_is_nothrow_move =
|
||||
boost::is_nothrow_move_constructible<hash_nothrow_move>::value;
|
||||
have_is_nothrow_swap =
|
||||
boost::unordered::detail::is_nothrow_swappable<hash_nothrow_swap>::value;
|
||||
|
||||
// Copied from boost::is_nothrow_move_constructible implementation
|
||||
// to make sure this does actually detect it when expected.
|
||||
@ -156,6 +161,17 @@ namespace noexcept_tests {
|
||||
!BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800)
|
||||
BOOST_TEST(have_is_nothrow_move);
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_NOEXCEPT) && \
|
||||
!defined(BOOST_NO_CXX11_DECLTYPE) && \
|
||||
!defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS)
|
||||
// TODO: Turn test on when unordered starts to use is_nothrow_swap
|
||||
// BOOST_TEST(have_is_nothrow_swap);
|
||||
#endif
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM
|
||||
<< "have_is_nothrow_move: " << have_is_nothrow_move << std::endl
|
||||
<< "have_is_nothrow_swap: " << have_is_nothrow_swap << std::endl;
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test_noexcept) {
|
||||
@ -203,6 +219,40 @@ namespace noexcept_tests {
|
||||
throwing_test_exception = false;
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test_nothrow_swap_when_noexcept) {
|
||||
typedef boost::unordered_set<int, hash_nothrow_swap, equal_to_nothrow_swap>
|
||||
throwing_set;
|
||||
|
||||
if (have_is_nothrow_swap) {
|
||||
BOOST_TEST(
|
||||
boost::unordered::detail::is_nothrow_swappable<throwing_set>::value);
|
||||
}
|
||||
|
||||
throwing_test_exception = false;
|
||||
|
||||
throwing_set x1;
|
||||
throwing_set x2;
|
||||
x1.insert(10);
|
||||
x1.insert(50);
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
x2.insert(i);
|
||||
}
|
||||
|
||||
try {
|
||||
throwing_test_exception = true;
|
||||
|
||||
x1.swap(x2);
|
||||
BOOST_TEST(x1.size() == 100);
|
||||
BOOST_TEST(x2.size() == 2);
|
||||
BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50);
|
||||
BOOST_TEST(have_is_nothrow_swap);
|
||||
} catch (test_exception) {
|
||||
BOOST_TEST(!have_is_nothrow_swap);
|
||||
}
|
||||
|
||||
throwing_test_exception = false;
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
Reference in New Issue
Block a user