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