1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 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 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef _LIBCPP___ITERATOR_ITER_SWAP_H 11 #define _LIBCPP___ITERATOR_ITER_SWAP_H 12 13 #include <__concepts/class_or_enum.h> 14 #include <__concepts/swappable.h> 15 #include <__config> 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> 24 25 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 26 # pragma GCC system_header 27 #endif 28 29 _LIBCPP_PUSH_MACROS 30 #include <__undef_macros> 31 32 _LIBCPP_BEGIN_NAMESPACE_STD 33 34 #if _LIBCPP_STD_VER >= 20 35 36 // [iter.cust.swap] 37 38 namespace ranges { 39 namespace __iter_swap { 40 template <class _I1, class _I2> 41 void iter_swap(_I1, _I2) = delete; 42 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)); 48 }; 49 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>>; 54 55 struct __fn { 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)); 62 } 63 // NOLINTEND(libcpp-robust-against-adl) 64 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)); 70 } 71 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); 84 } 85 }; 86 } // namespace __iter_swap 87 88 inline namespace __cpo { 89 inline constexpr auto iter_swap = __iter_swap::__fn{}; 90 } // namespace __cpo 91 } // namespace ranges 92 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); 100 }; 101 102 #endif // _LIBCPP_STD_VER >= 20 103 104 _LIBCPP_END_NAMESPACE_STD 105 106 _LIBCPP_POP_MACROS 107 108 #endif // _LIBCPP___ITERATOR_ITER_SWAP_H 109