1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef _LIBCPP___TYPE_TRAITS_IS_SWAPPABLE_H 10 #define _LIBCPP___TYPE_TRAITS_IS_SWAPPABLE_H 11 12 #include <__config> 13 #include <__type_traits/add_lvalue_reference.h> 14 #include <__type_traits/conditional.h> 15 #include <__type_traits/enable_if.h> 16 #include <__type_traits/is_move_assignable.h> 17 #include <__type_traits/is_move_constructible.h> 18 #include <__type_traits/is_nothrow_move_assignable.h> 19 #include <__type_traits/is_nothrow_move_constructible.h> 20 #include <__type_traits/is_referenceable.h> 21 #include <__type_traits/is_same.h> 22 #include <__type_traits/is_void.h> 23 #include <__type_traits/nat.h> 24 #include <__utility/declval.h> 25 #include <cstddef> 26 27 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 28 # pragma GCC system_header 29 #endif 30 31 _LIBCPP_BEGIN_NAMESPACE_STD 32 33 template <class _Tp> struct __is_swappable; 34 template <class _Tp> struct __is_nothrow_swappable; 35 36 37 #ifndef _LIBCPP_CXX03_LANG 38 template <class _Tp> 39 using __swap_result_t = typename enable_if<is_move_constructible<_Tp>::value && is_move_assignable<_Tp>::value>::type; 40 #else 41 template <class> 42 using __swap_result_t = void; 43 #endif 44 45 template <class _Tp> 46 inline _LIBCPP_INLINE_VISIBILITY 47 _LIBCPP_CONSTEXPR_SINCE_CXX20 __swap_result_t<_Tp> 48 swap(_Tp& __x, _Tp& __y) _NOEXCEPT_(is_nothrow_move_constructible<_Tp>::value && 49 is_nothrow_move_assignable<_Tp>::value); 50 51 template<class _Tp, size_t _Np> 52 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 53 typename enable_if< 54 __is_swappable<_Tp>::value 55 >::type 56 swap(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value); 57 58 namespace __detail 59 { 60 // ALL generic swap overloads MUST already have a declaration available at this point. 61 62 template <class _Tp, class _Up = _Tp, 63 bool _NotVoid = !is_void<_Tp>::value && !is_void<_Up>::value> 64 struct __swappable_with 65 { 66 template <class _LHS, class _RHS> 67 static decltype(swap(std::declval<_LHS>(), std::declval<_RHS>())) 68 __test_swap(int); 69 template <class, class> 70 static __nat __test_swap(long); 71 72 // Extra parens are needed for the C++03 definition of decltype. 73 typedef decltype((__test_swap<_Tp, _Up>(0))) __swap1; 74 typedef decltype((__test_swap<_Up, _Tp>(0))) __swap2; 75 76 static const bool value = _IsNotSame<__swap1, __nat>::value 77 && _IsNotSame<__swap2, __nat>::value; 78 }; 79 80 template <class _Tp, class _Up> 81 struct __swappable_with<_Tp, _Up, false> : false_type {}; 82 83 template <class _Tp, class _Up = _Tp, bool _Swappable = __swappable_with<_Tp, _Up>::value> 84 struct __nothrow_swappable_with { 85 static const bool value = 86 #ifndef _LIBCPP_HAS_NO_NOEXCEPT 87 noexcept(swap(std::declval<_Tp>(), std::declval<_Up>())) 88 && noexcept(swap(std::declval<_Up>(), std::declval<_Tp>())); 89 #else 90 false; 91 #endif 92 }; 93 94 template <class _Tp, class _Up> 95 struct __nothrow_swappable_with<_Tp, _Up, false> : false_type {}; 96 97 } // namespace __detail 98 99 template <class _Tp> 100 struct __is_swappable 101 : public integral_constant<bool, __detail::__swappable_with<_Tp&>::value> 102 { 103 }; 104 105 template <class _Tp> 106 struct __is_nothrow_swappable 107 : public integral_constant<bool, __detail::__nothrow_swappable_with<_Tp&>::value> 108 { 109 }; 110 111 #if _LIBCPP_STD_VER > 14 112 113 template <class _Tp, class _Up> 114 struct _LIBCPP_TEMPLATE_VIS is_swappable_with 115 : public integral_constant<bool, __detail::__swappable_with<_Tp, _Up>::value> 116 { 117 }; 118 119 template <class _Tp> 120 struct _LIBCPP_TEMPLATE_VIS is_swappable 121 : public __conditional_t< 122 __libcpp_is_referenceable<_Tp>::value, 123 is_swappable_with< 124 __add_lvalue_reference_t<_Tp>, 125 __add_lvalue_reference_t<_Tp> >, 126 false_type 127 > 128 { 129 }; 130 131 template <class _Tp, class _Up> 132 struct _LIBCPP_TEMPLATE_VIS is_nothrow_swappable_with 133 : public integral_constant<bool, __detail::__nothrow_swappable_with<_Tp, _Up>::value> 134 { 135 }; 136 137 template <class _Tp> 138 struct _LIBCPP_TEMPLATE_VIS is_nothrow_swappable 139 : public __conditional_t< 140 __libcpp_is_referenceable<_Tp>::value, 141 is_nothrow_swappable_with< 142 __add_lvalue_reference_t<_Tp>, 143 __add_lvalue_reference_t<_Tp> >, 144 false_type 145 > 146 { 147 }; 148 149 template <class _Tp, class _Up> 150 inline constexpr bool is_swappable_with_v = is_swappable_with<_Tp, _Up>::value; 151 152 template <class _Tp> 153 inline constexpr bool is_swappable_v = is_swappable<_Tp>::value; 154 155 template <class _Tp, class _Up> 156 inline constexpr bool is_nothrow_swappable_with_v = is_nothrow_swappable_with<_Tp, _Up>::value; 157 158 template <class _Tp> 159 inline constexpr bool is_nothrow_swappable_v = is_nothrow_swappable<_Tp>::value; 160 161 #endif // _LIBCPP_STD_VER > 14 162 163 _LIBCPP_END_NAMESPACE_STD 164 165 #endif // _LIBCPP___TYPE_TRAITS_IS_SWAPPABLE_H 166