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 38namespace ranges { 39namespace __iter_swap { 40template <class _I1, class _I2> 41void iter_swap(_I1, _I2) = delete; 42 43template <class _T1, class _T2> 44concept __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 50template <class _T1, class _T2> 51concept __readable_swappable = 52 indirectly_readable<_T1> && indirectly_readable<_T2> && 53 swappable_with<iter_reference_t<_T1>, iter_reference_t<_T2>>; 54 55struct __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 88inline namespace __cpo { 89inline constexpr auto iter_swap = __iter_swap::__fn{}; 90} // namespace __cpo 91} // namespace ranges 92 93template <class _I1, class _I2 = _I1> 94concept 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