Add is_swappable/is_nothrow_swappable traits
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@267079 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -630,7 +630,7 @@ template <class BidirectionalIterator, class Compare>
|
|||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <utility>
|
#include <utility> // needed to provide swap_ranges.
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ struct array
|
|||||||
|
|
||||||
// No explicit construct/copy/destroy for aggregate type
|
// No explicit construct/copy/destroy for aggregate type
|
||||||
void fill(const T& u);
|
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:
|
// iterators:
|
||||||
iterator begin() noexcept;
|
iterator begin() noexcept;
|
||||||
@@ -141,8 +141,15 @@ struct _LIBCPP_TYPE_VIS_ONLY array
|
|||||||
_LIBCPP_INLINE_VISIBILITY void fill(const value_type& __u)
|
_LIBCPP_INLINE_VISIBILITY void fill(const value_type& __u)
|
||||||
{_VSTD::fill_n(__elems_, _Size, __u);}
|
{_VSTD::fill_n(__elems_, _Size, __u);}
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
void swap(array& __a) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value)
|
void swap(array& __a) _NOEXCEPT_(_Size == 0 || __is_nothrow_swappable<_Tp>::value)
|
||||||
{_VSTD::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_);}
|
{ __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:
|
// iterators:
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
@@ -276,11 +283,12 @@ template <class _Tp, size_t _Size>
|
|||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY
|
||||||
typename enable_if
|
typename enable_if
|
||||||
<
|
<
|
||||||
|
_Size == 0 ||
|
||||||
__is_swappable<_Tp>::value,
|
__is_swappable<_Tp>::value,
|
||||||
void
|
void
|
||||||
>::type
|
>::type
|
||||||
swap(array<_Tp, _Size>& __x, array<_Tp, _Size>& __y)
|
swap(array<_Tp, _Size>& __x, array<_Tp, _Size>& __y)
|
||||||
_NOEXCEPT_(__is_nothrow_swappable<_Tp>::value)
|
_NOEXCEPT_(noexcept(__x.swap(__y)))
|
||||||
{
|
{
|
||||||
__x.swap(__y);
|
__x.swap(__y);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ public:
|
|||||||
|
|
||||||
void swap(map& m)
|
void swap(map& m)
|
||||||
noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
|
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:
|
// observers:
|
||||||
allocator_type get_allocator() const noexcept;
|
allocator_type get_allocator() const noexcept;
|
||||||
@@ -357,7 +357,7 @@ public:
|
|||||||
|
|
||||||
void swap(multimap& m)
|
void swap(multimap& m)
|
||||||
noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
|
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:
|
// observers:
|
||||||
allocator_type get_allocator() const noexcept;
|
allocator_type get_allocator() const noexcept;
|
||||||
|
|||||||
@@ -2974,7 +2974,10 @@ private:
|
|||||||
|
|
||||||
template <class _Tp, class _Dp>
|
template <class _Tp, class _Dp>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
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);}
|
swap(unique_ptr<_Tp, _Dp>& __x, unique_ptr<_Tp, _Dp>& __y) _NOEXCEPT {__x.swap(__y);}
|
||||||
|
|
||||||
template <class _T1, class _D1, class _T2, class _D2>
|
template <class _T1, class _D1, class _T2, class _D2>
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public:
|
|||||||
template <class... Args> void emplace(Args&&... args);
|
template <class... Args> void emplace(Args&&... args);
|
||||||
void pop();
|
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>
|
template <class T, class Container>
|
||||||
@@ -153,7 +153,8 @@ public:
|
|||||||
void pop();
|
void pop();
|
||||||
|
|
||||||
void swap(priority_queue& q)
|
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>
|
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>
|
template <class _Tp, class _Container>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY
|
||||||
void
|
typename enable_if<
|
||||||
|
__is_swappable<_Container>::value,
|
||||||
|
void
|
||||||
|
>::type
|
||||||
swap(queue<_Tp, _Container>& __x, queue<_Tp, _Container>& __y)
|
swap(queue<_Tp, _Container>& __x, queue<_Tp, _Container>& __y)
|
||||||
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__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>
|
template <class _Tp, class _Container, class _Compare>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
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,
|
swap(priority_queue<_Tp, _Container, _Compare>& __x,
|
||||||
priority_queue<_Tp, _Container, _Compare>& __y)
|
priority_queue<_Tp, _Container, _Compare>& __y)
|
||||||
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
|
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public:
|
|||||||
template <class... Args> void emplace(Args&&... args);
|
template <class... Args> void emplace(Args&&... args);
|
||||||
void pop();
|
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>
|
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>
|
template <class _Tp, class _Container>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY
|
||||||
void
|
typename enable_if<
|
||||||
|
__is_swappable<_Container>::value,
|
||||||
|
void
|
||||||
|
>::type
|
||||||
swap(stack<_Tp, _Container>& __x, stack<_Tp, _Container>& __y)
|
swap(stack<_Tp, _Container>& __x, stack<_Tp, _Container>& __y)
|
||||||
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
|
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -105,6 +105,8 @@ namespace std
|
|||||||
template <class T, class U> struct is_assignable;
|
template <class T, class U> struct is_assignable;
|
||||||
template <class T> struct is_copy_assignable;
|
template <class T> struct is_copy_assignable;
|
||||||
template <class T> struct is_move_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> struct is_destructible;
|
||||||
|
|
||||||
template <class T, class... Args> struct is_trivially_constructible;
|
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, class U> struct is_nothrow_assignable;
|
||||||
template <class T> struct is_nothrow_copy_assignable;
|
template <class T> struct is_nothrow_copy_assignable;
|
||||||
template <class T> struct is_nothrow_move_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 is_nothrow_destructible;
|
||||||
|
|
||||||
template <class T> struct has_virtual_destructor;
|
template <class T> struct has_virtual_destructor;
|
||||||
@@ -300,6 +304,10 @@ namespace std
|
|||||||
= is_copy_assignable<T>::value; // C++17
|
= is_copy_assignable<T>::value; // C++17
|
||||||
template <class T> constexpr bool is_move_assignable_v
|
template <class T> constexpr bool is_move_assignable_v
|
||||||
= is_move_assignable<T>::value; // C++17
|
= 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
|
template <class T> constexpr bool is_destructible_v
|
||||||
= is_destructible<T>::value; // C++17
|
= is_destructible<T>::value; // C++17
|
||||||
template <class T, class... Args> constexpr bool is_trivially_constructible_v
|
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
|
= is_nothrow_copy_assignable<T>::value; // C++17
|
||||||
template <class T> constexpr bool is_nothrow_move_assignable_v
|
template <class T> constexpr bool is_nothrow_move_assignable_v
|
||||||
= is_nothrow_move_assignable<T>::value; // C++17
|
= 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
|
template <class T> constexpr bool is_nothrow_destructible_v
|
||||||
= is_nothrow_destructible<T>::value; // C++17
|
= is_nothrow_destructible<T>::value; // C++17
|
||||||
template <class T> constexpr bool has_virtual_destructor_v
|
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)
|
#endif // !defined(_LIBCPP_CXX03_LANG)
|
||||||
|
|
||||||
|
template <class _Tp> struct __is_swappable;
|
||||||
|
template <class _Tp> struct __is_nothrow_swappable;
|
||||||
|
|
||||||
template <class _Tp>
|
template <class _Tp>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY
|
||||||
#ifndef _LIBCPP_HAS_NO_ADVANCED_SFINAE
|
#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);
|
__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>
|
template <class _ForwardIterator1, class _ForwardIterator2>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY
|
||||||
void
|
void
|
||||||
@@ -4455,55 +4477,103 @@ iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b)
|
|||||||
|
|
||||||
namespace __detail
|
namespace __detail
|
||||||
{
|
{
|
||||||
|
// ALL generic swap overloads MUST already have a declaration available at this point.
|
||||||
using _VSTD::swap;
|
using _VSTD::swap;
|
||||||
__nat swap(__any, __any);
|
__nat swap(__any, __any);
|
||||||
|
|
||||||
template <class _Tp>
|
template <class _Tp, class _Up = _Tp,
|
||||||
struct __swappable
|
bool _NotVoid = !is_void<_Tp>::value && !is_void<_Up>::value>
|
||||||
|
struct __swappable_with
|
||||||
{
|
{
|
||||||
typedef decltype(swap(_VSTD::declval<_Tp&>(), _VSTD::declval<_Tp&>())) type;
|
typedef decltype(swap(_VSTD::declval<_Tp>(), _VSTD::declval<_Up>())) __swap1;
|
||||||
static const bool value = !is_same<type, __nat>::value;
|
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
|
} // __detail
|
||||||
|
|
||||||
template <class _Tp>
|
template <class _Tp>
|
||||||
struct __is_swappable
|
struct __is_swappable
|
||||||
: public integral_constant<bool, __detail::__swappable<_Tp>::value>
|
: public integral_constant<bool, __detail::__swappable_with<_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
|
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class _Tp>
|
template <class _Tp>
|
||||||
struct __is_nothrow_swappable
|
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>
|
template <class _Tp>
|
||||||
struct __is_nothrow_swappable
|
struct _LIBCPP_TYPE_VIS_ONLY is_swappable
|
||||||
: public false_type
|
: 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
|
#ifdef _LIBCPP_UNDERLYING_TYPE
|
||||||
|
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ struct pair
|
|||||||
is_nothrow_move_assignable<T2>::value);
|
is_nothrow_move_assignable<T2>::value);
|
||||||
template <class U, class V> pair& operator=(pair<U, V>&& p);
|
template <class U, class V> pair& operator=(pair<U, V>&& p);
|
||||||
|
|
||||||
void swap(pair& p) noexcept(noexcept(swap(first, p.first)) &&
|
void swap(pair& p) noexcept(is_nothrow_swappable_v<T1> &&
|
||||||
noexcept(swap(second, p.second)));
|
is_nothrow_swappable_v<T2>);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T1, class T2> bool operator==(const pair<T1,T2>&, const pair<T1,T2>&); // constexpr in C++14
|
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
|
// 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>
|
template <class _ForwardIterator1, class _ForwardIterator2>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY
|
||||||
@@ -240,9 +236,12 @@ swap_ranges(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardItera
|
|||||||
return __first2;
|
return __first2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// forward declared in <type_traits>
|
||||||
template<class _Tp, size_t _Np>
|
template<class _Tp, size_t _Np>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
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)
|
swap(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value)
|
||||||
{
|
{
|
||||||
_VSTD::swap_ranges(__a, __a + _Np, __b);
|
_VSTD::swap_ranges(__a, __a + _Np, __b);
|
||||||
|
|||||||
@@ -14,10 +14,28 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "test_macros.h"
|
||||||
// std::array is explicitly allowed to be initialized with A a = { init-list };.
|
// std::array is explicitly allowed to be initialized with A a = { init-list };.
|
||||||
// Disable the missing braces warning for this reason.
|
// Disable the missing braces warning for this reason.
|
||||||
#include "disable_missing_braces_warning.h"
|
#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()
|
int main()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -44,4 +62,17 @@ int main()
|
|||||||
assert(c1.size() == 0);
|
assert(c1.size() == 0);
|
||||||
assert(c2.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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,19 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
#include "test_macros.h"
|
||||||
|
|
||||||
// std::array is explicitly allowed to be initialized with A a = { init-list };.
|
// std::array is explicitly allowed to be initialized with A a = { init-list };.
|
||||||
// Disable the missing braces warning for this reason.
|
// Disable the missing braces warning for this reason.
|
||||||
#include "disable_missing_braces_warning.h"
|
#include "disable_missing_braces_warning.h"
|
||||||
|
|
||||||
|
struct NonSwappable {
|
||||||
|
NonSwappable() {}
|
||||||
|
private:
|
||||||
|
NonSwappable(NonSwappable const&);
|
||||||
|
NonSwappable& operator=(NonSwappable const&);
|
||||||
|
};
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -70,5 +79,15 @@ int main()
|
|||||||
assert(c1.size() == 0);
|
assert(c1.size() == 0);
|
||||||
assert(c2.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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "test_macros.h"
|
||||||
#include "../deleter.h"
|
#include "../deleter.h"
|
||||||
|
|
||||||
struct A
|
struct A
|
||||||
@@ -34,6 +35,16 @@ struct A
|
|||||||
|
|
||||||
int A::count = 0;
|
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()
|
int main()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -74,4 +85,18 @@ int main()
|
|||||||
assert(A::count == 6);
|
assert(A::count == 6);
|
||||||
}
|
}
|
||||||
assert(A::count == 0);
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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&&>);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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&>);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,38 +16,88 @@
|
|||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
|
||||||
#include <memory>
|
#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
|
#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()
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,50 +16,86 @@
|
|||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
|
||||||
#include <memory>
|
#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
|
#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()
|
int main()
|
||||||
{
|
{
|
||||||
test();
|
{
|
||||||
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
int i[3] = {1, 2, 3};
|
||||||
test1();
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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/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/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/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/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/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>
|
<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>
|
||||||
|
|||||||
Reference in New Issue
Block a user