Add is_swappable/is_nothrow_swappable traits
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@267079 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/algorithm b/include/algorithm
index 2ea1dae..7a6db7a 100644
--- a/include/algorithm
+++ b/include/algorithm
@@ -630,7 +630,7 @@
#include <initializer_list>
#include <type_traits>
#include <cstring>
-#include <utility>
+#include <utility> // needed to provide swap_ranges.
#include <memory>
#include <iterator>
#include <cstddef>
diff --git a/include/array b/include/array
index f0350ea..719286d 100644
--- a/include/array
+++ b/include/array
@@ -34,7 +34,7 @@
// 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 @@
_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 @@
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);
}
diff --git a/include/map b/include/map
index d04b803..8dc84e7 100644
--- a/include/map
+++ b/include/map
@@ -162,7 +162,7 @@
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 @@
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;
diff --git a/include/memory b/include/memory
index e59fd5d..7888303 100644
--- a/include/memory
+++ b/include/memory
@@ -2974,7 +2974,10 @@
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>
diff --git a/include/queue b/include/queue
index 81b83a7..2509b93 100644
--- a/include/queue
+++ b/include/queue
@@ -66,7 +66,7 @@
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 @@
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 @@
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 @@
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)))
diff --git a/include/stack b/include/stack
index 64fd652..48b3b0d 100644
--- a/include/stack
+++ b/include/stack
@@ -58,7 +58,7 @@
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 @@
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)))
{
diff --git a/include/type_traits b/include/type_traits
index 1ebdafb..99dd679 100644
--- a/include/type_traits
+++ b/include/type_traits
@@ -105,6 +105,8 @@
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 @@
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 @@
= 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 @@
= 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 @@
#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 @@
__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 @@
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
diff --git a/include/utility b/include/utility
index e9db238..27b81a0 100644
--- a/include/utility
+++ b/include/utility
@@ -82,8 +82,8 @@
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 @@
// 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 @@
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);