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
33template <class _Tp> struct __is_swappable;
34template <class _Tp> struct __is_nothrow_swappable;
35
36
37#ifndef _LIBCPP_CXX03_LANG
38template <class _Tp>
39using __swap_result_t = typename enable_if<is_move_constructible<_Tp>::value && is_move_assignable<_Tp>::value>::type;
40#else
41template <class>
42using __swap_result_t = void;
43#endif
44
45template <class _Tp>
46inline _LIBCPP_INLINE_VISIBILITY
47_LIBCPP_CONSTEXPR_SINCE_CXX20 __swap_result_t<_Tp>
48swap(_Tp& __x, _Tp& __y) _NOEXCEPT_(is_nothrow_move_constructible<_Tp>::value &&
49                                    is_nothrow_move_assignable<_Tp>::value);
50
51template<class _Tp, size_t _Np>
52inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
53typename enable_if<
54    __is_swappable<_Tp>::value
55>::type
56swap(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value);
57
58namespace __detail
59{
60// ALL generic swap overloads MUST already have a declaration available at this point.
61
62template <class _Tp, class _Up = _Tp,
63          bool _NotVoid = !is_void<_Tp>::value && !is_void<_Up>::value>
64struct __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
80template <class _Tp, class _Up>
81struct __swappable_with<_Tp, _Up,  false> : false_type {};
82
83template <class _Tp, class _Up = _Tp, bool _Swappable = __swappable_with<_Tp, _Up>::value>
84struct __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
94template <class _Tp, class _Up>
95struct __nothrow_swappable_with<_Tp, _Up, false> : false_type {};
96
97} // namespace __detail
98
99template <class _Tp>
100struct __is_swappable
101    : public integral_constant<bool, __detail::__swappable_with<_Tp&>::value>
102{
103};
104
105template <class _Tp>
106struct __is_nothrow_swappable
107    : public integral_constant<bool, __detail::__nothrow_swappable_with<_Tp&>::value>
108{
109};
110
111#if _LIBCPP_STD_VER > 14
112
113template <class _Tp, class _Up>
114struct _LIBCPP_TEMPLATE_VIS is_swappable_with
115    : public integral_constant<bool, __detail::__swappable_with<_Tp, _Up>::value>
116{
117};
118
119template <class _Tp>
120struct _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
131template <class _Tp, class _Up>
132struct _LIBCPP_TEMPLATE_VIS is_nothrow_swappable_with
133    : public integral_constant<bool, __detail::__nothrow_swappable_with<_Tp, _Up>::value>
134{
135};
136
137template <class _Tp>
138struct _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
149template <class _Tp, class _Up>
150inline constexpr bool is_swappable_with_v = is_swappable_with<_Tp, _Up>::value;
151
152template <class _Tp>
153inline constexpr bool is_swappable_v = is_swappable<_Tp>::value;
154
155template <class _Tp, class _Up>
156inline constexpr bool is_nothrow_swappable_with_v = is_nothrow_swappable_with<_Tp, _Up>::value;
157
158template <class _Tp>
159inline 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