Add is_swappable/is_nothrow_swappable traits

llvm-svn: 267079
This commit is contained in:
Eric Fiselier 2016-04-21 23:38:59 +00:00
parent c89755e4cb
commit f07dd8d0a9
19 changed files with 729 additions and 115 deletions

View File

@ -630,7 +630,7 @@ template <class BidirectionalIterator, class Compare>
#include <initializer_list>
#include <type_traits>
#include <cstring>
#include <utility>
#include <utility> // needed to provide swap_ranges.
#include <memory>
#include <iterator>
#include <cstddef>

View File

@ -34,7 +34,7 @@ struct array
// No explicit construct/copy/destroy for aggregate type
void fill(const T& u);
void swap(array& a) noexcept(noexcept(swap(declval<T&>(), declval<T&>())));
void swap(array& a) noexcept(is_nothrow_swappable_v<T>);
// iterators:
iterator begin() noexcept;
@ -141,8 +141,15 @@ struct _LIBCPP_TYPE_VIS_ONLY array
_LIBCPP_INLINE_VISIBILITY void fill(const value_type& __u)
{_VSTD::fill_n(__elems_, _Size, __u);}
_LIBCPP_INLINE_VISIBILITY
void swap(array& __a) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value)
{_VSTD::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_);}
void swap(array& __a) _NOEXCEPT_(_Size == 0 || __is_nothrow_swappable<_Tp>::value)
{ __swap_dispatch((std::integral_constant<bool, _Size == 0>()), __a); }
_LIBCPP_INLINE_VISIBILITY
void __swap_dispatch(std::true_type, array&) {}
_LIBCPP_INLINE_VISIBILITY
void __swap_dispatch(std::false_type, array& __a)
{ _VSTD::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_);}
// iterators:
_LIBCPP_INLINE_VISIBILITY
@ -276,11 +283,12 @@ template <class _Tp, size_t _Size>
inline _LIBCPP_INLINE_VISIBILITY
typename enable_if
<
_Size == 0 ||
__is_swappable<_Tp>::value,
void
>::type
swap(array<_Tp, _Size>& __x, array<_Tp, _Size>& __y)
_NOEXCEPT_(__is_nothrow_swappable<_Tp>::value)
_NOEXCEPT_(noexcept(__x.swap(__y)))
{
__x.swap(__y);
}

View File

@ -162,7 +162,7 @@ public:
void swap(map& m)
noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
__is_nothrow_swappable<key_compare>::value); // C++17
is_nothrow_swappable<key_compare>::value); // C++17
// observers:
allocator_type get_allocator() const noexcept;
@ -357,7 +357,7 @@ public:
void swap(multimap& m)
noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
__is_nothrow_swappable<key_compare>::value); // C++17
is_nothrow_swappable<key_compare>::value); // C++17
// observers:
allocator_type get_allocator() const noexcept;

View File

@ -2974,7 +2974,10 @@ private:
template <class _Tp, class _Dp>
inline _LIBCPP_INLINE_VISIBILITY
void
typename enable_if<
__is_swappable<_Dp>::value,
void
>::type
swap(unique_ptr<_Tp, _Dp>& __x, unique_ptr<_Tp, _Dp>& __y) _NOEXCEPT {__x.swap(__y);}
template <class _T1, class _D1, class _T2, class _D2>

View File

@ -66,7 +66,7 @@ public:
template <class... Args> void emplace(Args&&... args);
void pop();
void swap(queue& q) noexcept(noexcept(swap(c, q.c)));
void swap(queue& q) noexcept(is_nothrow_swappable_v<Container>)
};
template <class T, class Container>
@ -153,7 +153,8 @@ public:
void pop();
void swap(priority_queue& q)
noexcept(noexcept(swap(c, q.c)) && noexcept(swap(comp.q.comp)));
noexcept(is_nothrow_swappable_v<Container> &&
is_nothrow_swappable_v<Comp>)
};
template <class T, class Container, class Compare>
@ -369,7 +370,10 @@ operator<=(const queue<_Tp, _Container>& __x,const queue<_Tp, _Container>& __y)
template <class _Tp, class _Container>
inline _LIBCPP_INLINE_VISIBILITY
void
typename enable_if<
__is_swappable<_Container>::value,
void
>::type
swap(queue<_Tp, _Container>& __x, queue<_Tp, _Container>& __y)
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
{
@ -700,7 +704,11 @@ priority_queue<_Tp, _Container, _Compare>::swap(priority_queue& __q)
template <class _Tp, class _Container, class _Compare>
inline _LIBCPP_INLINE_VISIBILITY
void
typename enable_if<
__is_swappable<_Container>::value
&& __is_swappable<_Compare>::value,
void
>::type
swap(priority_queue<_Tp, _Container, _Compare>& __x,
priority_queue<_Tp, _Container, _Compare>& __y)
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))

View File

@ -58,7 +58,7 @@ public:
template <class... Args> void emplace(Args&&... args);
void pop();
void swap(stack& c) noexcept(noexcept(swap(c, q.c)));
void swap(stack& c) noexcept(is_nothrow_swappable_v<Container>)
};
template <class T, class Container>
@ -275,7 +275,10 @@ operator<=(const stack<_Tp, _Container>& __x, const stack<_Tp, _Container>& __y)
template <class _Tp, class _Container>
inline _LIBCPP_INLINE_VISIBILITY
void
typename enable_if<
__is_swappable<_Container>::value,
void
>::type
swap(stack<_Tp, _Container>& __x, stack<_Tp, _Container>& __y)
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
{

View File

@ -105,6 +105,8 @@ namespace std
template <class T, class U> struct is_assignable;
template <class T> struct is_copy_assignable;
template <class T> struct is_move_assignable;
template <class T, class U> struct is_swappable_with; // C++17
template <class T> struct is_swappable; // C++17
template <class T> struct is_destructible;
template <class T, class... Args> struct is_trivially_constructible;
@ -123,6 +125,8 @@ namespace std
template <class T, class U> struct is_nothrow_assignable;
template <class T> struct is_nothrow_copy_assignable;
template <class T> struct is_nothrow_move_assignable;
template <class T, class U> struct is_nothrow_swappable_with; // C++17
template <class T> struct is_nothrow_swappable; // C++17
template <class T> struct is_nothrow_destructible;
template <class T> struct has_virtual_destructor;
@ -300,6 +304,10 @@ namespace std
= is_copy_assignable<T>::value; // C++17
template <class T> constexpr bool is_move_assignable_v
= is_move_assignable<T>::value; // C++17
template <class T, class U> constexpr bool is_swappable_with_v
= is_swappable_with<T, U>::value; // C++17
template <class T> constexpr bool is_swappable_v
= is_swappable<T>::value; // C++17
template <class T> constexpr bool is_destructible_v
= is_destructible<T>::value; // C++17
template <class T, class... Args> constexpr bool is_trivially_constructible_v
@ -332,6 +340,10 @@ namespace std
= is_nothrow_copy_assignable<T>::value; // C++17
template <class T> constexpr bool is_nothrow_move_assignable_v
= is_nothrow_move_assignable<T>::value; // C++17
template <class T, class U> constexpr bool is_nothrow_swappable_with_v
= is_nothrow_swappable_with<T, U>::value; // C++17
template <class T> constexpr bool is_nothrow_swappable_v
= is_nothrow_swappable<T>::value; // C++17
template <class T> constexpr bool is_nothrow_destructible_v
= is_nothrow_destructible<T>::value; // C++17
template <class T> constexpr bool has_virtual_destructor_v
@ -4421,6 +4433,9 @@ constexpr bool is_nothrow_callable_v = is_nothrow_callable<_Fn, _Ret>::value;
#endif // !defined(_LIBCPP_CXX03_LANG)
template <class _Tp> struct __is_swappable;
template <class _Tp> struct __is_nothrow_swappable;
template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
#ifndef _LIBCPP_HAS_NO_ADVANCED_SFINAE
@ -4440,6 +4455,13 @@ swap(_Tp& __x, _Tp& __y) _NOEXCEPT_(is_nothrow_move_constructible<_Tp>::value &&
__y = _VSTD::move(__t);
}
template<class _Tp, size_t _Np>
inline _LIBCPP_INLINE_VISIBILITY
typename enable_if<
__is_swappable<_Tp>::value
>::type
swap(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value);
template <class _ForwardIterator1, class _ForwardIterator2>
inline _LIBCPP_INLINE_VISIBILITY
void
@ -4455,55 +4477,103 @@ iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b)
namespace __detail
{
// ALL generic swap overloads MUST already have a declaration available at this point.
using _VSTD::swap;
__nat swap(__any, __any);
template <class _Tp>
struct __swappable
template <class _Tp, class _Up = _Tp,
bool _NotVoid = !is_void<_Tp>::value && !is_void<_Up>::value>
struct __swappable_with
{
typedef decltype(swap(_VSTD::declval<_Tp&>(), _VSTD::declval<_Tp&>())) type;
static const bool value = !is_same<type, __nat>::value;
typedef decltype(swap(_VSTD::declval<_Tp>(), _VSTD::declval<_Up>())) __swap1;
typedef decltype(swap(_VSTD::declval<_Up>(), _VSTD::declval<_Tp>())) __swap2;
static const bool value = !is_same<__swap1, __nat>::value
&& !is_same<__swap2, __nat>::value;
};
template <class _Tp, class _Up>
struct __swappable_with<_Tp, _Up, false> : false_type {};
template <class _Tp, class _Up = _Tp, bool _Swappable = __swappable_with<_Tp, _Up>::value>
struct __nothrow_swappable_with {
static const bool value =
#ifndef _LIBCPP_HAS_NO_NOEXCEPT
noexcept(swap(_VSTD::declval<_Tp>(), _VSTD::declval<_Up>()))
&& noexcept(swap(_VSTD::declval<_Up>(), _VSTD::declval<_Tp>()));
#else
false;
#endif
};
template <class _Tp, class _Up>
struct __nothrow_swappable_with<_Tp, _Up, false> : false_type {};
} // __detail
template <class _Tp>
struct __is_swappable
: public integral_constant<bool, __detail::__swappable<_Tp>::value>
{
};
#if __has_feature(cxx_noexcept) || (_GNUC_VER >= 407 && __cplusplus >= 201103L)
template <bool, class _Tp>
struct __is_nothrow_swappable_imp
: public integral_constant<bool, noexcept(swap(_VSTD::declval<_Tp&>(),
_VSTD::declval<_Tp&>()))>
{
};
template <class _Tp>
struct __is_nothrow_swappable_imp<false, _Tp>
: public false_type
: public integral_constant<bool, __detail::__swappable_with<_Tp&>::value>
{
};
template <class _Tp>
struct __is_nothrow_swappable
: public __is_nothrow_swappable_imp<__is_swappable<_Tp>::value, _Tp>
: public integral_constant<bool, __detail::__nothrow_swappable_with<_Tp&>::value>
{
};
#else // __has_feature(cxx_noexcept)
#if _LIBCPP_STD_VER > 14
template <class _Tp, class _Up>
struct _LIBCPP_TYPE_VIS_ONLY is_swappable_with
: public integral_constant<bool, __detail::__swappable_with<_Tp, _Up>::value>
{
};
template <class _Tp>
struct __is_nothrow_swappable
: public false_type
struct _LIBCPP_TYPE_VIS_ONLY is_swappable
: public conditional<
__is_referenceable<_Tp>::value,
is_swappable_with<
typename add_lvalue_reference<_Tp>::type,
typename add_lvalue_reference<_Tp>::type>,
false_type
>::type
{
};
#endif // __has_feature(cxx_noexcept)
template <class _Tp, class _Up>
struct _LIBCPP_TYPE_VIS_ONLY is_nothrow_swappable_with
: public integral_constant<bool, __detail::__nothrow_swappable_with<_Tp, _Up>::value>
{
};
template <class _Tp>
struct _LIBCPP_TYPE_VIS_ONLY is_nothrow_swappable
: public conditional<
__is_referenceable<_Tp>::value,
is_nothrow_swappable_with<
typename add_lvalue_reference<_Tp>::type,
typename add_lvalue_reference<_Tp>::type>,
false_type
>::type
{
};
template <class _Tp, class _Up>
constexpr bool is_swappable_with_v = is_swappable_with<_Tp, _Up>::value;
template <class _Tp>
constexpr bool is_swappable_v = is_swappable<_Tp>::value;
template <class _Tp, class _Up>
constexpr bool is_nothrow_swappable_with_v = is_nothrow_swappable_with<_Tp, _Up>::value;
template <class _Tp>
constexpr bool is_nothrow_swappable_v = is_nothrow_swappable<_Tp>::value;
#endif // _LIBCPP_STD_VER > 14
#ifdef _LIBCPP_UNDERLYING_TYPE

View File

@ -82,8 +82,8 @@ struct pair
is_nothrow_move_assignable<T2>::value);
template <class U, class V> pair& operator=(pair<U, V>&& p);
void swap(pair& p) noexcept(noexcept(swap(first, p.first)) &&
noexcept(swap(second, p.second)));
void swap(pair& p) noexcept(is_nothrow_swappable_v<T1> &&
is_nothrow_swappable_v<T2>);
};
template <class T1, class T2> bool operator==(const pair<T1,T2>&, const pair<T1,T2>&); // constexpr in C++14
@ -225,10 +225,6 @@ operator>=(const _Tp& __x, const _Tp& __y)
// swap_ranges
// forward
template<class _Tp, size_t _Np>
inline _LIBCPP_INLINE_VISIBILITY
void swap(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value);
template <class _ForwardIterator1, class _ForwardIterator2>
inline _LIBCPP_INLINE_VISIBILITY
@ -240,9 +236,12 @@ swap_ranges(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardItera
return __first2;
}
// forward declared in <type_traits>
template<class _Tp, size_t _Np>
inline _LIBCPP_INLINE_VISIBILITY
void
typename enable_if<
__is_swappable<_Tp>::value
>::type
swap(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value)
{
_VSTD::swap_ranges(__a, __a + _Np, __b);

View File

@ -14,10 +14,28 @@
#include <array>
#include <cassert>
#include "test_macros.h"
// std::array is explicitly allowed to be initialized with A a = { init-list };.
// Disable the missing braces warning for this reason.
#include "disable_missing_braces_warning.h"
struct NonSwappable {
NonSwappable() {}
private:
NonSwappable(NonSwappable const&);
NonSwappable& operator=(NonSwappable const&);
};
template <class Tp>
decltype(swap(std::declval<Tp>(), std::declval<Tp>()))
can_swap_imp(int);
template <class Tp>
std::false_type can_swap_imp(...);
template <class Tp>
struct can_swap : std::is_same<decltype(can_swap_imp<Tp>(0)), void> {};
int main()
{
{
@ -44,4 +62,17 @@ int main()
assert(c1.size() == 0);
assert(c2.size() == 0);
}
{
typedef NonSwappable T;
typedef std::array<T, 42> C1;
typedef std::array<T, 0> C0;
static_assert(!can_swap<C1&>::value, "");
static_assert(can_swap<C0&>::value, "");
C0 l = {};
C0 r = {};
swap(l, r);
#if TEST_STD_VER >= 11
static_assert(noexcept(swap(l, r)), "");
#endif
}
}

View File

@ -15,10 +15,19 @@
#include <cassert>
#include <array>
#include "test_macros.h"
// std::array is explicitly allowed to be initialized with A a = { init-list };.
// Disable the missing braces warning for this reason.
#include "disable_missing_braces_warning.h"
struct NonSwappable {
NonSwappable() {}
private:
NonSwappable(NonSwappable const&);
NonSwappable& operator=(NonSwappable const&);
};
int main()
{
{
@ -70,5 +79,15 @@ int main()
assert(c1.size() == 0);
assert(c2.size() == 0);
}
{
typedef NonSwappable T;
typedef std::array<T, 0> C0;
C0 l = {};
C0 r = {};
l.swap(r);
#if TEST_STD_VER >= 11
static_assert(noexcept(l.swap(r)), "");
#endif
}
}

View File

@ -16,6 +16,7 @@
#include <memory>
#include <cassert>
#include "test_macros.h"
#include "../deleter.h"
struct A
@ -34,6 +35,16 @@ struct A
int A::count = 0;
template <class T>
struct NonSwappableDeleter {
explicit NonSwappableDeleter(int) {}
NonSwappableDeleter& operator=(NonSwappableDeleter const&) { return *this; }
void operator()(T*) const {}
private:
NonSwappableDeleter(NonSwappableDeleter const&);
};
int main()
{
{
@ -74,4 +85,18 @@ int main()
assert(A::count == 6);
}
assert(A::count == 0);
#if TEST_STD_VER >= 11
{
// test that unique_ptr's specialized swap is disabled when the deleter
// is non-swappable. Instead we should pick up the generic swap(T, T)
// and perform 3 move constructions.
typedef NonSwappableDeleter<int> D;
D d(42);
int x = 42;
int y = 43;
std::unique_ptr<int, D&> p(&x, d);
std::unique_ptr<int, D&> p2(&y, d);
std::swap(p, p2);
}
#endif
}

View File

@ -0,0 +1,83 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11, c++14
// type_traits
// is_swappable
#include <type_traits>
#include <vector>
#include "test_macros.h"
namespace MyNS {
// Make the test types non-copyable so that generic std::swap is not valid.
struct A {
A(A const&) = delete;
A& operator=(A const&) = delete;
};
struct B {
B(B const&) = delete;
B& operator=(B const&) = delete;
};
void swap(A&, A&) noexcept {}
void swap(B&, B&) {}
struct M {
M(M const&) = delete;
M& operator=(M const&) = delete;
};
void swap(M&&, M&&) noexcept {}
struct ThrowingMove {
ThrowingMove(ThrowingMove&&){}
ThrowingMove& operator=(ThrowingMove&&) {}
};
} // namespace MyNS
int main()
{
using namespace MyNS;
{
// Test that is_swappable applies an lvalue reference to the type.
static_assert(std::is_nothrow_swappable<int>::value, "");
static_assert(std::is_nothrow_swappable<int&>::value, "");
static_assert(!std::is_nothrow_swappable<M>::value, "");
static_assert(!std::is_nothrow_swappable<M&&>::value, "");
}
{
// Test that it correctly deduces the noexcept of swap.
static_assert(std::is_nothrow_swappable<A>::value, "");
static_assert(!std::is_nothrow_swappable<B>::value
&& std::is_swappable<B>::value, "");
static_assert(!std::is_nothrow_swappable<ThrowingMove>::value
&& std::is_swappable<ThrowingMove>::value);
}
{
// Test that it doesn't drop the qualifiers
static_assert(!std::is_nothrow_swappable<const A>::value, "");
}
{
// test non-referenceable types
static_assert(!std::is_nothrow_swappable<void>::value, "");
static_assert(!std::is_nothrow_swappable<int() const>::value, "");
static_assert(!std::is_nothrow_swappable<int(int, ...) const &>::value, "");
}
{
// test for presence of is_nothrow_swappable_v
static_assert(std::is_nothrow_swappable_v<int>);
static_assert(!std::is_nothrow_swappable_v<void>);
}
}

View File

@ -0,0 +1,81 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11, c++14
// type_traits
// is_nothrow_swappable_with
#include <type_traits>
#include <vector>
#include "test_macros.h"
namespace MyNS {
struct A {
A(A const&) = delete;
A& operator=(A const&) = delete;
};
struct B {
B(B const&) = delete;
B& operator=(B const&) = delete;
};
struct C {};
struct D {};
void swap(A&, A&) {}
void swap(A&, B&) noexcept {}
void swap(B&, A&) noexcept {}
void swap(A&, C&) noexcept {}
void swap(C&, A&) {}
struct M {};
void swap(M&&, M&&) noexcept {}
} // namespace MyNS
int main()
{
using namespace MyNS;
{
// Test that is_swappable_with doesn't apply an lvalue reference
// to the type. Instead it is up to the user.
static_assert(!std::is_nothrow_swappable_with<int, int>::value, "");
static_assert(std::is_nothrow_swappable_with<int&, int&>::value, "");
static_assert(std::is_nothrow_swappable_with<M, M>::value, "");
static_assert(std::is_swappable_with<A&, A&>::value &&
!std::is_nothrow_swappable_with<A&, A&>::value, "");
}
{
// test that hetrogenius swap is allowed only if both 'swap(A, B)' and
// 'swap(B, A)' are valid.
static_assert(std::is_nothrow_swappable_with<A&, B&>::value, "");
static_assert(!std::is_nothrow_swappable_with<A&, C&>::value &&
std::is_swappable_with<A&, C&>::value, "");
static_assert(!std::is_nothrow_swappable_with<D&, C&>::value, "");
}
{
// test we guard against cv void inputs as required.
static_assert(!std::is_nothrow_swappable_with_v<void, int>);
static_assert(!std::is_nothrow_swappable_with_v<int, void>);
static_assert(!std::is_nothrow_swappable_with_v<const void, const volatile void>);
}
{
// test for presense of is_nothrow_swappable_with_v
static_assert(std::is_nothrow_swappable_with_v<int&, int&>);
static_assert(!std::is_nothrow_swappable_with_v<int&&, int&&>);
}
}

View File

@ -0,0 +1,77 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11, c++14
// type_traits
// is_swappable
#include <type_traits>
#include <utility>
#include <vector>
#include "test_macros.h"
namespace MyNS {
// Make the test types non-copyable so that generic std::swap is not valid.
struct A {
A(A const&) = delete;
A& operator=(A const&) = delete;
};
struct B {
B(B const&) = delete;
B& operator=(B const&) = delete;
};
struct C {};
struct D {};
void swap(A&, A&) {}
void swap(A&, B&) {}
void swap(B&, A&) {}
void swap(A&, C&) {} // missing swap(C, A)
void swap(D&, C&) {}
struct M {
M(M const&) = delete;
M& operator=(M const&) = delete;
};
void swap(M&&, M&&) {}
} // namespace MyNS
int main()
{
using namespace MyNS;
{
// Test that is_swappable applies an lvalue reference to the type.
static_assert(std::is_swappable<A>::value, "");
static_assert(std::is_swappable<A&>::value, "");
static_assert(!std::is_swappable<M>::value, "");
static_assert(!std::is_swappable<M&&>::value, "");
}
static_assert(!std::is_swappable<B>::value, "");
static_assert(std::is_swappable<C>::value, "");
{
// test non-referencable types
static_assert(!std::is_swappable<void>::value, "");
static_assert(!std::is_swappable<int() const>::value, "");
static_assert(!std::is_swappable<int() &>::value, "");
}
{
// test for presense of is_swappable_v
static_assert(std::is_swappable_v<int>);
static_assert(!std::is_swappable_v<M>);
}
}

View File

@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// type_traits
// is_swappable
// IMPORTANT: The include order is part of the test. We want to pick up
// the following definitions in this order:
// 1) is_swappable, is_nothrow_swappable
// 2) iter_swap, swap_ranges
// 3) swap(T (&)[N], T(&)[N]
// This test checks that (1) and (2) see forward declarations
// for (3).
#include <type_traits>
#include <algorithm>
#include <utility>
#include "test_macros.h"
int main()
{
// Use a builtin type so we don't get ADL lookup.
typedef double T[42][50];
{
static_assert(std::__is_swappable<T>::value, "");
#if TEST_STD_VER > 14
static_assert(std::is_swappable_v<T>);
#endif
}
{
T t1 = {};
T t2 = {};
std::iter_swap(t1, t2);
std::swap_ranges(t1, t1 + 42, t2);
}
}

View File

@ -0,0 +1,78 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11, c++14
// type_traits
// is_swappable_with
#include <type_traits>
#include <vector>
#include "test_macros.h"
namespace MyNS {
struct A {
A(A const&) = delete;
A& operator=(A const&) = delete;
};
struct B {
B(B const&) = delete;
B& operator=(B const&) = delete;
};
struct C {};
struct D {};
void swap(A&, A&) {}
void swap(A&, B&) {}
void swap(B&, A&) {}
void swap(A&, C&) {} // missing swap(C, A)
void swap(D&, C&) {}
struct M {};
void swap(M&&, M&&) {}
} // namespace MyNS
int main()
{
using namespace MyNS;
{
// Test that is_swappable_with doesn't apply an lvalue reference
// to the type. Instead it is up to the user.
static_assert(!std::is_swappable_with<int, int>::value, "");
static_assert(std::is_swappable_with<int&, int&>::value, "");
static_assert(std::is_swappable_with<M, M>::value, "");
static_assert(std::is_swappable_with<A&, A&>::value, "");
}
{
// test that heterogeneous swap is allowed only if both 'swap(A, B)' and
// 'swap(B, A)' are valid.
static_assert(std::is_swappable_with<A&, B&>::value, "");
static_assert(!std::is_swappable_with<A&, C&>::value, "");
static_assert(!std::is_swappable_with<D&, C&>::value, "");
}
{
// test that cv void is guarded against as required.
static_assert(!std::is_swappable_with_v<void, int>);
static_assert(!std::is_swappable_with_v<int, void>);
static_assert(!std::is_swappable_with_v<const void, const volatile void>);
}
{
// test for presence of is_swappable_with_v
static_assert(std::is_swappable_with_v<int&, int&>);
static_assert(!std::is_swappable_with_v<D&, C&>);
}
}

View File

@ -16,38 +16,88 @@
#include <utility>
#include <cassert>
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
#include <memory>
#include "test_macros.h"
#if TEST_STD_VER >= 11
struct CopyOnly {
CopyOnly() {}
CopyOnly(CopyOnly const&) noexcept {}
CopyOnly& operator=(CopyOnly const&) { return *this; }
};
struct MoveOnly {
MoveOnly() {}
MoveOnly(MoveOnly&&) {}
MoveOnly& operator=(MoveOnly&&) noexcept { return *this; }
};
struct NoexceptMoveOnly {
NoexceptMoveOnly() {}
NoexceptMoveOnly(NoexceptMoveOnly&&) noexcept {}
NoexceptMoveOnly& operator=(NoexceptMoveOnly&&) noexcept { return *this; }
};
struct NotMoveConstructible {
NotMoveConstructible& operator=(NotMoveConstructible&&) { return *this; }
private:
NotMoveConstructible(NotMoveConstructible&&);
};
struct NotMoveAssignable {
NotMoveAssignable(NotMoveAssignable&&);
private:
NotMoveAssignable& operator=(NotMoveAssignable&&);
};
template <class Tp>
auto can_swap_test(int) -> decltype(std::swap(std::declval<Tp>(), std::declval<Tp>()));
template <class Tp>
auto can_swap_test(...) -> std::false_type;
template <class Tp>
constexpr bool can_swap() {
return std::is_same<decltype(can_swap_test<Tp>(0)), void>::value;
}
#endif
void
test()
{
int i = 1;
int j = 2;
std::swap(i, j);
assert(i == 2);
assert(j == 1);
}
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
void
test1()
{
std::unique_ptr<int> i(new int(1));
std::unique_ptr<int> j(new int(2));
std::swap(i, j);
assert(*i == 2);
assert(*j == 1);
}
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
int main()
{
test();
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
test1();
{
int i = 1;
int j = 2;
std::swap(i, j);
assert(i == 2);
assert(j == 1);
}
#if TEST_STD_VER >= 11
{
std::unique_ptr<int> i(new int(1));
std::unique_ptr<int> j(new int(2));
std::swap(i, j);
assert(*i == 2);
assert(*j == 1);
}
{
// test that the swap
static_assert(can_swap<CopyOnly&>(), "");
static_assert(can_swap<MoveOnly&>(), "");
static_assert(can_swap<NoexceptMoveOnly&>(), "");
static_assert(!can_swap<NotMoveConstructible&>(), "");
static_assert(!can_swap<NotMoveAssignable&>(), "");
CopyOnly c;
MoveOnly m;
NoexceptMoveOnly nm;
static_assert(!noexcept(std::swap(c, c)), "");
static_assert(!noexcept(std::swap(m, m)), "");
static_assert(noexcept(std::swap(nm, nm)), "");
}
#endif
}

View File

@ -16,50 +16,86 @@
#include <utility>
#include <cassert>
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
#include <memory>
#include "test_macros.h"
#if TEST_STD_VER >= 11
struct CopyOnly {
CopyOnly() {}
CopyOnly(CopyOnly const&) noexcept {}
CopyOnly& operator=(CopyOnly const&) { return *this; }
};
struct NoexceptMoveOnly {
NoexceptMoveOnly() {}
NoexceptMoveOnly(NoexceptMoveOnly&&) noexcept {}
NoexceptMoveOnly& operator=(NoexceptMoveOnly&&) noexcept { return *this; }
};
struct NotMoveConstructible {
NotMoveConstructible() {}
NotMoveConstructible& operator=(NotMoveConstructible&&) { return *this; }
private:
NotMoveConstructible(NotMoveConstructible&&);
};
template <class Tp>
auto can_swap_test(int) -> decltype(std::swap(std::declval<Tp>(), std::declval<Tp>()));
template <class Tp>
auto can_swap_test(...) -> std::false_type;
template <class Tp>
constexpr bool can_swap() {
return std::is_same<decltype(can_swap_test<Tp>(0)), void>::value;
}
#endif
void
test()
{
int i[3] = {1, 2, 3};
int j[3] = {4, 5, 6};
std::swap(i, j);
assert(i[0] == 4);
assert(i[1] == 5);
assert(i[2] == 6);
assert(j[0] == 1);
assert(j[1] == 2);
assert(j[2] == 3);
}
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
void
test1()
{
std::unique_ptr<int> i[3];
for (int k = 0; k < 3; ++k)
i[k].reset(new int(k+1));
std::unique_ptr<int> j[3];
for (int k = 0; k < 3; ++k)
j[k].reset(new int(k+4));
std::swap(i, j);
assert(*i[0] == 4);
assert(*i[1] == 5);
assert(*i[2] == 6);
assert(*j[0] == 1);
assert(*j[1] == 2);
assert(*j[2] == 3);
}
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
int main()
{
test();
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
test1();
{
int i[3] = {1, 2, 3};
int j[3] = {4, 5, 6};
std::swap(i, j);
assert(i[0] == 4);
assert(i[1] == 5);
assert(i[2] == 6);
assert(j[0] == 1);
assert(j[1] == 2);
assert(j[2] == 3);
}
#if TEST_STD_VER >= 11
{
std::unique_ptr<int> i[3];
for (int k = 0; k < 3; ++k)
i[k].reset(new int(k+1));
std::unique_ptr<int> j[3];
for (int k = 0; k < 3; ++k)
j[k].reset(new int(k+4));
std::swap(i, j);
assert(*i[0] == 4);
assert(*i[1] == 5);
assert(*i[2] == 6);
assert(*j[0] == 1);
assert(*j[1] == 2);
assert(*j[2] == 3);
}
{
using CA = CopyOnly[42];
using MA = NoexceptMoveOnly[42];
using NA = NotMoveConstructible[42];
static_assert(can_swap<CA&>(), "");
static_assert(can_swap<MA&>(), "");
static_assert(!can_swap<NA&>(), "");
CA ca;
MA ma;
static_assert(!noexcept(std::swap(ca, ca)), "");
static_assert(noexcept(std::swap(ma, ma)), "");
}
#endif
}

View File

@ -85,7 +85,7 @@
<tr><td><a href="http://wg21.link/P0033R1">P0033R1</a></td><td>LWG</td><td>Re-enabling shared_from_this</td><td>Jacksonville</td><td></td><td></td></tr>
<tr><td><a href="http://wg21.link/P0005R4">P0005R4</a></td><td>LWG</td><td>Adopt not_fn from Library Fundamentals 2 for C++17</td><td>Jacksonville</td><td></td><td></td></tr>
<tr><td><a href="http://wg21.link/P0152R1">P0152R1</a></td><td>LWG</td><td>constexpr atomic::is_always_lock_free</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr>
<tr><td><a href="http://wg21.link/P0185R1">P0185R1</a></td><td>LWG</td><td>Adding [nothrow-]swappable traits</td><td>Jacksonville</td><td></td><td></td></tr>
<tr><td><a href="http://wg21.link/P0185R1">P0185R1</a></td><td>LWG</td><td>Adding [nothrow-]swappable traits</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr>
<tr><td><a href="http://wg21.link/P0253R1">P0253R1</a></td><td>LWG</td><td>Fixing a design mistake in the searchers interface</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr>
<tr><td><a href="http://wg21.link/P0025R0">P0025R0</a></td><td>LWG</td><td>An algorithm to "clamp" a value between a pair of boundary values</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr>
<tr><td><a href="http://wg21.link/P0154R1">P0154R1</a></td><td>LWG</td><td>constexpr std::hardware_{constructive,destructive}_interference_size</td><td>Jacksonville</td><td></td><td></td></tr>