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 // UNSUPPORTED: c++03, c++11, c++14, c++17 10 // UNSUPPORTED: libcpp-has-no-incomplete-ranges 11 12 // friend constexpr void iter_swap(const inner-iterator& x, const inner-iterator& y) 13 // noexcept(noexcept(ranges::iter_swap(x.i_.<current>, y.i_.<current>))) 14 // requires indirectly_swappable<iterator_t<Base>>; 15 16 #include <ranges> 17 18 #include <cassert> 19 #include <type_traits> 20 #include <utility> 21 #include "../types.h" 22 23 namespace adl { 24 25 template <bool IsNoexcept = false> 26 struct Iterator { 27 using value_type = int; 28 using difference_type = ptrdiff_t; 29 30 value_type* ptr_ = nullptr; 31 int* iter_swap_invocations_ = nullptr; 32 33 constexpr Iterator() = default; 34 constexpr explicit Iterator(int& iter_swaps) : iter_swap_invocations_(&iter_swaps) {} 35 36 value_type& operator*() const { return *ptr_; } 37 38 Iterator& operator++() { ++ptr_; return *this; } 39 Iterator operator++(int) { 40 Iterator prev = *this; 41 ++ptr_; 42 return prev; 43 } 44 45 Iterator& operator--() { --ptr_; return *this; } 46 Iterator operator--(int) { 47 Iterator prev = *this; 48 --ptr_; 49 return prev; 50 } 51 52 constexpr friend void iter_swap(Iterator a, Iterator) noexcept(IsNoexcept) { 53 if (a.iter_swap_invocations_) { 54 ++(*a.iter_swap_invocations_); 55 } 56 } 57 58 friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; } 59 }; 60 61 template <bool IsNoexcept = false> 62 struct View : std::ranges::view_base { 63 int* iter_swaps = nullptr; 64 65 constexpr View() = default; 66 constexpr View(int& iter_swap_invocations) : iter_swaps(&iter_swap_invocations) { 67 } 68 69 constexpr adl::Iterator<IsNoexcept> begin() { return adl::Iterator<IsNoexcept>(*iter_swaps); } 70 constexpr adl::Iterator<IsNoexcept> end() { return adl::Iterator<IsNoexcept>(*iter_swaps); } 71 }; 72 73 } // namespace adl 74 75 constexpr bool test() { 76 // Can use `iter_swap` with `inner-iterator`; `View` is a forward range. 77 { 78 // Non-const iterator. 79 { 80 SplitViewDiff v("abc def", " "); 81 auto segment = *v.begin(); 82 83 auto i1 = segment.begin(); 84 auto i2 = i1++; 85 static_assert(std::is_void_v<decltype(iter_swap(i1, i2))>); 86 assert(*i1 == 'b'); 87 assert(*i2 == 'a'); 88 89 iter_swap(i1, i2); 90 assert(*i1 == 'a'); 91 assert(*i2 == 'b'); 92 // Note that `iter_swap` swaps characters in the actual underlying range. 93 assert(*v.base().begin() == 'b'); 94 } 95 96 // Const iterator. 97 { 98 SplitViewDiff v("abc def", " "); 99 auto segment = *v.begin(); 100 101 auto i1 = segment.begin(); 102 const auto i2 = i1++; 103 static_assert(std::is_void_v<decltype(iter_swap(i1, i2))>); 104 static_assert(std::is_void_v<decltype(iter_swap(i2, i2))>); 105 assert(*i1 == 'b'); 106 assert(*i2 == 'a'); 107 108 iter_swap(i1, i2); 109 assert(*i1 == 'a'); 110 assert(*i2 == 'b'); 111 assert(*v.base().begin() == 'b'); 112 } 113 } 114 115 // Can use `iter_swap` with `inner-iterator`; `View` is an input range. 116 { 117 118 // Non-const iterator. 119 { 120 // Iterators belong to the same view. 121 { 122 SplitViewInput v("abc def", ' '); 123 auto segment = *v.begin(); 124 125 auto i1 = segment.begin(); 126 auto i2 = i1; 127 ++i1; 128 static_assert(std::is_void_v<decltype(iter_swap(i1, i2))>); 129 assert(*i1 == 'b'); 130 // For an input view, all inner iterators are essentially thin proxies to the same underlying iterator. 131 assert(*i2 == 'b'); 132 133 iter_swap(i1, i2); 134 assert(*i1 == 'b'); 135 assert(*i2 == 'b'); 136 } 137 138 // Iterators belong to different views. 139 { 140 SplitViewInput v1("abc def", ' '); 141 auto val1 = *v1.begin(); 142 SplitViewInput v2 = v1; 143 auto val2 = *v2.begin(); 144 145 auto i1 = val1.begin(); 146 auto i2 = val2.begin(); 147 ++i1; 148 assert(*i1 == 'b'); 149 assert(*i2 == 'a'); 150 151 iter_swap(i1, i2); 152 assert(*i1 == 'a'); 153 assert(*i2 == 'b'); 154 } 155 } 156 157 // Const iterator. 158 { 159 SplitViewInput v("abc def", ' '); 160 auto segment = *v.begin(); 161 162 const auto i1 = segment.begin(); 163 const auto i2 = i1; 164 static_assert(std::is_void_v<decltype(iter_swap(i1, i2))>); 165 assert(*i1 == 'a'); 166 assert(*i2 == 'a'); 167 168 iter_swap(i1, i2); 169 assert(*i1 == 'a'); 170 assert(*i2 == 'a'); 171 } 172 } 173 174 // Ensure the `iter_swap` customization point is being used. 175 { 176 int iter_swap_invocations = 0; 177 adl::View<> input(iter_swap_invocations); 178 std::ranges::lazy_split_view<adl::View<>, adl::View<>> v(input, adl::View<>()); 179 180 auto segment = *v.begin(); 181 auto i = segment.begin(); 182 iter_swap(i, i); 183 assert(iter_swap_invocations == 1); 184 } 185 186 // Check the `noexcept` specification. 187 { 188 { 189 using ThrowingSplitView = std::ranges::lazy_split_view<adl::View<false>, adl::View<false>>; 190 using ThrowingValueType = std::ranges::iterator_t<ThrowingSplitView>::value_type; 191 using ThrowingIter = std::ranges::iterator_t<ThrowingValueType>; 192 ASSERT_NOT_NOEXCEPT( 193 std::ranges::iter_swap(std::declval<adl::Iterator<false>>(), std::declval<adl::Iterator<false>>())); 194 ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<ThrowingIter>(), std::declval<ThrowingIter>())); 195 } 196 197 { 198 using NoexceptSplitView = std::ranges::lazy_split_view<adl::View<true>, adl::View<true>>; 199 using NoexceptValueType = std::ranges::iterator_t<NoexceptSplitView>::value_type; 200 using NoexceptIter = std::ranges::iterator_t<NoexceptValueType>; 201 ASSERT_NOEXCEPT( 202 std::ranges::iter_swap(std::declval<adl::Iterator<true>>(), std::declval<adl::Iterator<true>>())); 203 ASSERT_NOEXCEPT(iter_swap(std::declval<NoexceptIter>(), std::declval<NoexceptIter>())); 204 } 205 } 206 207 return true; 208 } 209 210 int main(int, char**) { 211 test(); 212 static_assert(test()); 213 214 return 0; 215 } 216