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 // <algorithm> 10 11 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 12 13 // template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2, 14 // class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> 15 // requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2> 16 // constexpr bool ranges::ends_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, 17 // Proj1 proj1 = {}, Proj2 proj2 = {}); 18 // template<input_range R1, input_range R2, class Pred = ranges::equal_to, class Proj1 = identity, 19 // class Proj2 = identity> 20 // requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2> 21 // constexpr bool ranges::ends_with(R1&& r1, R2&& r2, Pred pred = {}, 22 // Proj1 proj1 = {}, Proj2 proj2 = {}); 23 24 #include <algorithm> 25 #include <array> 26 #include <chrono> 27 #include <ranges> 28 #include "almost_satisfies_types.h" 29 #include "test_iterators.h" 30 31 using namespace std::chrono; 32 33 template <class Iter1, class Sent1 = Iter1, class Iter2 = int*, class Sent2 = Iter2> 34 concept HasEndsWithIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { 35 std::ranges::ends_with(first1, last1, first2, last2); 36 }; 37 38 static_assert(HasEndsWithIt<int*>); 39 static_assert(!HasEndsWithIt<ForwardIteratorNotDerivedFrom>); 40 static_assert(!HasEndsWithIt<ForwardIteratorNotIncrementable>); 41 static_assert(HasEndsWithIt<int*, int*>); 42 static_assert(!HasEndsWithIt<int*, SentinelForNotSemiregular>); 43 static_assert(!HasEndsWithIt<int*, int*, int**>); // not indirectly comparable 44 static_assert(!HasEndsWithIt<int*, SentinelForNotWeaklyEqualityComparableWith>); 45 static_assert(!HasEndsWithIt<int*, int*, ForwardIteratorNotDerivedFrom>); 46 static_assert(!HasEndsWithIt<int*, int*, ForwardIteratorNotIncrementable>); 47 static_assert(!HasEndsWithIt<int*, int*, int*, SentinelForNotSemiregular>); 48 static_assert(!HasEndsWithIt<int*, int*, int*, SentinelForNotWeaklyEqualityComparableWith>); 49 50 template <class Range1, class Range2 = UncheckedRange<int*>> 51 concept HasEndsWithR = requires(Range1&& range1, Range2&& range2) { 52 std::ranges::ends_with(std::forward<Range1>(range1), std::forward<Range2>(range2)); 53 }; 54 55 static_assert(HasEndsWithR<UncheckedRange<int*>>); 56 static_assert(!HasEndsWithR<ForwardRangeNotDerivedFrom>); 57 static_assert(!HasEndsWithR<ForwardIteratorNotIncrementable>); 58 static_assert(!HasEndsWithR<ForwardRangeNotSentinelSemiregular>); 59 static_assert(!HasEndsWithR<ForwardRangeNotSentinelEqualityComparableWith>); 60 static_assert(HasEndsWithR<UncheckedRange<int*>, UncheckedRange<int*>>); 61 static_assert(!HasEndsWithR<UncheckedRange<int*>, UncheckedRange<int**>>); // not indirectly comparable 62 static_assert(!HasEndsWithR<UncheckedRange<int*>, ForwardRangeNotDerivedFrom>); 63 static_assert(!HasEndsWithR<UncheckedRange<int*>, ForwardRangeNotSentinelSemiregular>); 64 65 template <class Iter1, class Sent1 = Iter1, class Iter2, class Sent2 = Iter2> 66 constexpr void test_iterators() { 67 { // simple tests 68 int a[] = {1, 2, 3, 4, 5, 6}; 69 int p[] = {4, 5, 6}; 70 { 71 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 72 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 73 [[maybe_unused]] std::same_as<bool> decltype(auto) ret = 74 std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 75 assert(ret); 76 } 77 { 78 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 79 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 80 [[maybe_unused]] std::same_as<bool> decltype(auto) ret = std::ranges::ends_with(whole, suffix); 81 assert(ret); 82 } 83 } 84 85 { // suffix doesn't match 86 int a[] = {1, 2, 3, 4, 5, 6}; 87 int p[] = {1, 2, 3}; 88 { 89 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 90 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 91 bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 92 assert(!ret); 93 } 94 { 95 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 96 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 97 bool ret = std::ranges::ends_with(whole, suffix); 98 assert(!ret); 99 } 100 } 101 102 { // range consists of just one element 103 int a[] = {1}; 104 int p[] = {1}; 105 { 106 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1))); 107 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); 108 bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 109 assert(ret); 110 } 111 { 112 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1))); 113 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); 114 bool ret = std::ranges::ends_with(whole, suffix); 115 assert(ret); 116 } 117 } 118 119 { // suffix consists of just one element 120 int a[] = {5, 1, 2, 4, 3}; 121 int p[] = {3}; 122 { 123 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); 124 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); 125 bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 126 assert(ret); 127 } 128 { 129 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); 130 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); 131 bool ret = std::ranges::ends_with(whole, suffix); 132 assert(ret); 133 } 134 } 135 136 { // range and suffix are identical 137 int a[] = {1, 2, 3, 4, 5, 6}; 138 int p[] = {1, 2, 3, 4, 5, 6}; 139 { 140 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 141 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 6))); 142 bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 143 assert(ret); 144 } 145 { 146 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 147 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 6))); 148 bool ret = std::ranges::ends_with(whole, suffix); 149 assert(ret); 150 } 151 } 152 153 { // suffix is longer than range 154 int a[] = {3, 4, 5, 6, 7, 8}; 155 int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; 156 { 157 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 158 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); 159 bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 160 assert(!ret); 161 } 162 { 163 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 164 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); 165 bool ret = std::ranges::ends_with(whole, suffix); 166 assert(!ret); 167 } 168 } 169 170 { // suffix has zero length 171 int a[] = {1, 2, 3, 4, 5, 6}; 172 std::array<int, 0> p = {}; 173 { 174 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 175 auto suffix = std::ranges::subrange(Iter2(p.data()), Sent2(Iter2(p.data()))); 176 bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 177 assert(ret); 178 } 179 { 180 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 181 auto suffix = std::ranges::subrange(Iter2(p.data()), Sent2(Iter2(p.data()))); 182 bool ret = std::ranges::ends_with(whole, suffix); 183 assert(ret); 184 } 185 } 186 187 { // range has zero length 188 std::array<int, 0> a = {}; 189 int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; 190 { 191 auto whole = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data()))); 192 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); 193 bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 194 assert(!ret); 195 } 196 { 197 auto whole = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data()))); 198 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); 199 bool ret = std::ranges::ends_with(whole, suffix); 200 assert(!ret); 201 } 202 } 203 204 { // subarray 205 int a[] = {0, 3, 5, 10, 7, 3, 5, 89, 3, 5, 2, 1, 8, 6}; 206 int p[] = {3, 5}; 207 { 208 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 13))); 209 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); 210 bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 211 assert(!ret); 212 } 213 { 214 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 13))); 215 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); 216 bool ret = std::ranges::ends_with(whole, suffix); 217 assert(!ret); 218 } 219 } 220 221 { // repeated suffix 222 int a[] = {8, 6, 3, 5, 1, 2}; 223 int p[] = {1, 2, 1, 2}; 224 { 225 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 226 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 4))); 227 bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 228 assert(!ret); 229 } 230 { 231 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 232 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 4))); 233 bool ret = std::ranges::ends_with(whole, suffix); 234 assert(!ret); 235 } 236 } 237 238 { // check that the predicate is used 239 int a[] = {5, 1, 3, 2, 7}; 240 int p[] = {-2, -7}; 241 auto pred = [](int l, int r) { return l * -1 == r; }; 242 { 243 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); 244 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); 245 bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end(), pred); 246 assert(ret); 247 } 248 { 249 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); 250 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); 251 bool ret = std::ranges::ends_with(whole, suffix, pred); 252 assert(ret); 253 } 254 } 255 256 { // check that the projections are used 257 int a[] = {1, 3, 15, 1, 2, 1}; 258 int p[] = {2, 1, 2}; 259 { 260 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 261 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 262 bool ret = std::ranges::ends_with( 263 whole.begin(), 264 whole.end(), 265 suffix.begin(), 266 suffix.end(), 267 {}, 268 [](int i) { return i - 3; }, 269 [](int i) { return i * -1; }); 270 assert(ret); 271 } 272 { 273 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 274 auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 275 bool ret = std::ranges::ends_with(whole, suffix, {}, [](int i) { return i - 3; }, [](int i) { return i * -1; }); 276 assert(ret); 277 } 278 } 279 } 280 281 constexpr bool test() { 282 // This is to test (forward_iterator<_Iter1> || sized_sentinel_for<_Sent1, _Iter1>) condition. 283 types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iter2>() { 284 types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iter1>() { 285 if constexpr (std::forward_iterator<Iter1> && std::forward_iterator<Iter2>) 286 test_iterators<Iter1, Iter1, Iter2, Iter2>(); 287 if constexpr (std::forward_iterator<Iter2>) 288 test_iterators<Iter1, sized_sentinel<Iter1>, Iter2, Iter2>(); 289 if constexpr (std::forward_iterator<Iter1>) 290 test_iterators<Iter1, Iter1, Iter2, sized_sentinel<Iter2>>(); 291 test_iterators<Iter1, sized_sentinel<Iter1>, Iter2, sized_sentinel<Iter2>>(); 292 }); 293 }); 294 295 return true; 296 } 297 298 int main(int, char**) { 299 test(); 300 static_assert(test()); 301 302 return 0; 303 } 304