2 //===----------------------------------------------------------------------===//
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___ITERATOR_ITER_SWAP_H
11 #define _LIBCPP___ITERATOR_ITER_SWAP_H
13 #include <__concepts/class_or_enum.h>
14 #include <__concepts/swappable.h>
16 #include <__iterator/concepts.h>
17 #include <__iterator/iter_move.h>
18 #include <__iterator/iterator_traits.h>
19 #include <__iterator/readable_traits.h>
20 #include <__type_traits/remove_cvref.h>
21 #include <__utility/declval.h>
22 #include <__utility/forward.h>
23 #include <__utility/move.h>
25 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26 # pragma GCC system_header
30 #include <__undef_macros>
32 _LIBCPP_BEGIN_NAMESPACE_STD
34 #if _LIBCPP_STD_VER >= 20
39 namespace __iter_swap
{
40 template <class _I1
, class _I2
>
41 void iter_swap(_I1
, _I2
) = delete;
43 template <class _T1
, class _T2
>
44 concept __unqualified_iter_swap
=
45 (__class_or_enum
<remove_cvref_t
<_T1
>> || __class_or_enum
<remove_cvref_t
<_T2
>>) && requires(_T1
&& __x
, _T2
&& __y
) {
46 // NOLINTNEXTLINE(libcpp-robust-against-adl) iter_swap ADL calls should only be made through ranges::iter_swap
47 iter_swap(std::forward
<_T1
>(__x
), std::forward
<_T2
>(__y
));
50 template <class _T1
, class _T2
>
51 concept __readable_swappable
=
52 indirectly_readable
<_T1
> && indirectly_readable
<_T2
> &&
53 swappable_with
<iter_reference_t
<_T1
>, iter_reference_t
<_T2
>>;
56 // NOLINTBEGIN(libcpp-robust-against-adl) iter_swap ADL calls should only be made through ranges::iter_swap
57 template <class _T1
, class _T2
>
58 requires __unqualified_iter_swap
<_T1
, _T2
>
59 _LIBCPP_HIDE_FROM_ABI
constexpr void operator()(_T1
&& __x
, _T2
&& __y
) const
60 noexcept(noexcept(iter_swap(std::forward
<_T1
>(__x
), std::forward
<_T2
>(__y
)))) {
61 (void)iter_swap(std::forward
<_T1
>(__x
), std::forward
<_T2
>(__y
));
63 // NOLINTEND(libcpp-robust-against-adl)
65 template <class _T1
, class _T2
>
66 requires(!__unqualified_iter_swap
<_T1
, _T2
>) && __readable_swappable
<_T1
, _T2
>
67 _LIBCPP_HIDE_FROM_ABI
constexpr void operator()(_T1
&& __x
, _T2
&& __y
) const
68 noexcept(noexcept(ranges::swap(*std::forward
<_T1
>(__x
), *std::forward
<_T2
>(__y
)))) {
69 ranges::swap(*std::forward
<_T1
>(__x
), *std::forward
<_T2
>(__y
));
72 template <class _T1
, class _T2
>
73 requires(!__unqualified_iter_swap
<_T1
, _T2
> && //
74 !__readable_swappable
<_T1
, _T2
>) && //
75 indirectly_movable_storable
<_T1
, _T2
> && //
76 indirectly_movable_storable
<_T2
, _T1
>
77 _LIBCPP_HIDE_FROM_ABI
constexpr void operator()(_T1
&& __x
, _T2
&& __y
) const
78 noexcept(noexcept(iter_value_t
<_T2
>(ranges::iter_move(__y
))) && //
79 noexcept(*__y
= ranges::iter_move(__x
)) && //
80 noexcept(*std::forward
<_T1
>(__x
) = std::declval
<iter_value_t
<_T2
>>())) {
81 iter_value_t
<_T2
> __old(ranges::iter_move(__y
));
82 *__y
= ranges::iter_move(__x
);
83 *std::forward
<_T1
>(__x
) = std::move(__old
);
86 } // namespace __iter_swap
88 inline namespace __cpo
{
89 inline constexpr auto iter_swap
= __iter_swap::__fn
{};
93 template <class _I1
, class _I2
= _I1
>
94 concept indirectly_swappable
=
95 indirectly_readable
<_I1
> && indirectly_readable
<_I2
> && requires(const _I1 __i1
, const _I2 __i2
) {
96 ranges::iter_swap(__i1
, __i1
);
97 ranges::iter_swap(__i2
, __i2
);
98 ranges::iter_swap(__i1
, __i2
);
99 ranges::iter_swap(__i2
, __i1
);
102 #endif // _LIBCPP_STD_VER >= 20
104 _LIBCPP_END_NAMESPACE_STD
108 #endif // _LIBCPP___ITERATOR_ITER_SWAP_H