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::starts_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::starts_with(R1&& r1, R2&& r2, Pred pred = {}, 22 // Proj1 proj1 = {}, Proj2 proj2 = {}); 23 24 #include <algorithm> 25 #include <array> 26 #include <ranges> 27 28 #include "almost_satisfies_types.h" 29 #include "test_iterators.h" 30 31 template <class Iter1, class Sent1 = Iter1, class Iter2 = int*, class Sent2 = Iter2> 32 concept HasStartsWithIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { 33 std::ranges::starts_with(first1, last1, first2, last2); 34 }; 35 36 static_assert(HasStartsWithIt<int*>); 37 static_assert(HasStartsWithIt<ForwardIteratorNotDerivedFrom>); 38 static_assert(HasStartsWithIt<ForwardIteratorNotIncrementable>); 39 static_assert(!HasStartsWithIt<int*, SentinelForNotSemiregular>); 40 static_assert(!HasStartsWithIt<int*, int*, int**>); // not indirectly comparable 41 static_assert(!HasStartsWithIt<int*, SentinelForNotWeaklyEqualityComparableWith>); 42 static_assert(HasStartsWithIt<int*, int*, ForwardIteratorNotDerivedFrom>); 43 static_assert(HasStartsWithIt<int*, int*, ForwardIteratorNotIncrementable>); 44 static_assert(!HasStartsWithIt<int*, int*, int*, SentinelForNotSemiregular>); 45 static_assert(!HasStartsWithIt<int*, int*, int*, SentinelForNotWeaklyEqualityComparableWith>); 46 47 template <class Range1, class Range2 = UncheckedRange<int*>> 48 concept HasStartsWithR = requires(Range1 range1, Range2 range2) { std::ranges::starts_with(range1, range2); }; 49 50 static_assert(HasStartsWithR<UncheckedRange<int*>>); 51 static_assert(HasStartsWithR<ForwardRangeNotDerivedFrom>); 52 static_assert(!HasStartsWithR<ForwardIteratorNotIncrementable>); 53 static_assert(!HasStartsWithR<ForwardRangeNotSentinelSemiregular>); 54 static_assert(!HasStartsWithR<ForwardRangeNotSentinelEqualityComparableWith>); 55 static_assert(!HasStartsWithR<UncheckedRange<int*>, UncheckedRange<int**>>); // not indirectly comparable 56 static_assert(HasStartsWithR<UncheckedRange<int*>, ForwardRangeNotDerivedFrom>); 57 static_assert(HasStartsWithR<UncheckedRange<int*>, ForwardRangeNotIncrementable>); 58 static_assert(!HasStartsWithR<UncheckedRange<int*>, ForwardRangeNotSentinelSemiregular>); 59 static_assert(!HasStartsWithR<UncheckedRange<int*>, ForwardRangeNotSentinelEqualityComparableWith>); 60 61 // clang-format off 62 template <class Iter1, class Sent1 = Iter1, class Iter2, class Sent2 = Iter2> 63 constexpr void test_iterators() { 64 { // simple tests 65 { 66 int a[] = {1, 2, 3, 4, 5, 6}; 67 int p[] = {1, 2}; 68 std::same_as<bool> decltype(auto) ret = 69 std::ranges::starts_with(Iter1(a), Sent1(Iter1(a + 6)), Iter2(p), Sent2(Iter2(p + 2))); 70 assert(ret); 71 } 72 { 73 int a[] = {1, 2, 3, 4, 5, 6}; 74 int p[] = {1, 2}; 75 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 76 auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); 77 std::same_as<bool> decltype(auto) ret = std::ranges::starts_with(whole, prefix); 78 assert(ret); 79 } 80 } 81 82 { // prefix doesn't match 83 { 84 int a[] = {1, 2, 3, 4, 5, 6}; 85 int p[] = {4, 5, 6}; 86 std::same_as<bool> decltype(auto) ret = 87 std::ranges::starts_with(Iter1(a), Sent1(Iter1(a + 6)), Iter2(p), Sent2(Iter2(p + 3))); 88 assert(!ret); 89 } 90 { 91 int a[] = {1, 2, 3, 4, 5, 6}; 92 int p[] = {4, 5, 6}; 93 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 94 auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 95 std::same_as<bool> decltype(auto) ret = std::ranges::starts_with(whole, prefix); 96 assert(!ret); 97 } 98 } 99 100 { // range and prefix are identical 101 { 102 int a[] = {1, 2, 3, 4, 5, 6}; 103 int p[] = {1, 2, 3, 4, 5, 6}; 104 std::same_as<bool> decltype(auto) ret = 105 std::ranges::starts_with(Iter1(a), Sent1(Iter1(a + 6)), Iter2(p), Sent2(Iter2(p + 6))); 106 assert(ret); 107 } 108 { 109 int a[] = {1, 2, 3, 4, 5, 6}; 110 int p[] = {1, 2, 3, 4, 5, 6}; 111 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 112 auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 6))); 113 std::same_as<bool> decltype(auto) ret = std::ranges::starts_with(whole, prefix); 114 assert(ret); 115 } 116 } 117 118 { // prefix is longer than range 119 { 120 int a[] = {1, 2, 3, 4, 5, 6}; 121 int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; 122 std::same_as<bool> decltype(auto) ret = 123 std::ranges::starts_with(Iter1(a), Sent1(Iter1(a + 6)), Iter2(p), Sent2(Iter2(p + 8))); 124 assert(!ret); 125 } 126 { 127 int a[] = {1, 2, 3, 4, 5, 6}; 128 int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; 129 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 130 auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); 131 std::same_as<bool> decltype(auto) ret = std::ranges::starts_with(whole, prefix); 132 assert(!ret); 133 } 134 } 135 136 { // prefix has zero length 137 { 138 int a[] = {1, 2, 3, 4, 5, 6}; 139 int p[] = {}; 140 std::same_as<bool> decltype(auto) ret = 141 std::ranges::starts_with(Iter1(a), Sent1(Iter1(a + 6)), Iter2(p), Sent2(Iter2(p))); 142 assert(ret); 143 } 144 { 145 int a[] = {1, 2, 3, 4, 5, 6}; 146 int p[] = {}; 147 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 148 auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p))); 149 std::same_as<bool> decltype(auto) ret = std::ranges::starts_with(whole, prefix); 150 assert(ret); 151 } 152 } 153 154 { // range has zero length 155 { 156 int a[] = {}; 157 int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; 158 std::same_as<bool> decltype(auto) ret = 159 std::ranges::starts_with(Iter1(a), Sent1(Iter1(a)), Iter2(p), Sent2(Iter2(p + 8))); 160 assert(!ret); 161 } 162 { 163 int a[] = {}; 164 int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; 165 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a))); 166 auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); 167 std::same_as<bool> decltype(auto) ret = std::ranges::starts_with(whole, prefix); 168 assert(!ret); 169 } 170 } 171 172 { // check that the predicate is used 173 { 174 int a[] = {11, 8, 3, 4, 0, 6}; 175 int p[] = {1, 12}; 176 std::same_as<bool> decltype(auto) ret = std::ranges::starts_with( 177 Iter1(a), Sent1(Iter1(a + 6)), Iter2(p), Sent2(Iter2(p + 2)), [](int l, int r) { return l > r; }); 178 assert(!ret); 179 } 180 { 181 int a[] = {11, 8, 3, 4, 0, 6}; 182 int p[] = {1, 12}; 183 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 184 auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); 185 std::same_as<bool> decltype(auto) ret = std::ranges::starts_with(whole, prefix, [](int l, int r) { return l > r; }); 186 assert(!ret); 187 } 188 } 189 190 { // check that the projections are used 191 { 192 int a[] = {1, 3, 5, 1, 5, 6}; 193 int p[] = {2, 3, 4}; 194 std::same_as<bool> decltype(auto) ret = std::ranges::starts_with( 195 Iter1(a), 196 Sent1(Iter1(a + 6)), 197 Iter2(p), 198 Sent2(Iter2(p + 3)), 199 {}, 200 [](int i) { return i + 3; }, 201 [](int i) { return i * 2; }); 202 assert(ret); 203 } 204 { 205 int a[] = {1, 3, 5, 1, 5, 6}; 206 int p[] = {2, 3, 4}; 207 auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 208 auto prefix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 209 std::same_as<bool> decltype(auto) ret = std::ranges::starts_with( 210 whole, prefix, {}, [](int i) { return i + 3; }, [](int i) { return i * 2; }); 211 assert(ret); 212 } 213 } 214 } 215 216 constexpr bool test() { 217 types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iter2>() { 218 types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iter1>() { 219 if constexpr (std::forward_iterator<Iter1> && std::forward_iterator<Iter2>) 220 test_iterators<Iter1, Iter1, Iter2, Iter2>(); 221 if constexpr (std::forward_iterator<Iter2>) 222 test_iterators<Iter1, sized_sentinel<Iter1>, Iter2, Iter2>(); 223 if constexpr (std::forward_iterator<Iter1>) 224 test_iterators<Iter1, Iter1, Iter2, sized_sentinel<Iter2>>(); 225 test_iterators<Iter1, sized_sentinel<Iter1>, Iter2, sized_sentinel<Iter2>>(); 226 }); 227 }); 228 229 { // check that std::invoke is used 230 struct S { 231 int i; 232 233 constexpr S identity() { return *this; } 234 235 constexpr bool compare(const S& s) { return i == s.i; } 236 }; 237 { 238 S a[] = {{1}, {2}, {3}, {4}}; 239 S p[] = {{1}, {2}}; 240 auto ret = std::ranges::starts_with(a, a + 4, p, p + 2, &S::compare, &S::identity, &S::identity); 241 assert(ret); 242 } 243 { 244 S a[] = {{1}, {2}, {3}, {4}}; 245 S p[] = {{1}, {2}}; 246 auto ret = std::ranges::starts_with(a, p, &S::compare, &S::identity, &S::identity); 247 assert(ret); 248 } 249 } 250 251 return true; 252 } 253 254 int main(int, char**) { 255 test(); 256 static_assert(test()); 257 258 return 0; 259 } 260