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-no-concepts 11 12 // std::ranges::end 13 // std::ranges::cend 14 15 #include <ranges> 16 17 #include <cassert> 18 #include <utility> 19 #include "test_macros.h" 20 #include "test_iterators.h" 21 22 using RangeEndT = decltype(std::ranges::end); 23 using RangeCEndT = decltype(std::ranges::cend); 24 25 static int globalBuff[8]; 26 27 static_assert(!std::is_invocable_v<RangeEndT, int (&&)[]>); 28 static_assert(!std::is_invocable_v<RangeEndT, int (&)[]>); 29 static_assert(!std::is_invocable_v<RangeEndT, int (&&)[10]>); 30 static_assert( std::is_invocable_v<RangeEndT, int (&)[10]>); 31 static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[]>); 32 static_assert(!std::is_invocable_v<RangeCEndT, int (&)[]>); 33 static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[10]>); 34 static_assert( std::is_invocable_v<RangeCEndT, int (&)[10]>); 35 36 struct Incomplete; 37 static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[]>); 38 static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[42]>); 39 static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[]>); 40 static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[42]>); 41 42 struct EndMember { 43 int x; 44 const int *begin() const; 45 constexpr const int *end() const { return &x; } 46 }; 47 48 // Ensure that we can't call with rvalues with borrowing disabled. 49 static_assert( std::is_invocable_v<RangeEndT, EndMember &>); 50 static_assert(!std::is_invocable_v<RangeEndT, EndMember &&>); 51 static_assert( std::is_invocable_v<RangeEndT, EndMember const&>); 52 static_assert(!std::is_invocable_v<RangeEndT, EndMember const&&>); 53 static_assert( std::is_invocable_v<RangeCEndT, EndMember &>); 54 static_assert(!std::is_invocable_v<RangeCEndT, EndMember &&>); 55 static_assert( std::is_invocable_v<RangeCEndT, EndMember const&>); 56 static_assert(!std::is_invocable_v<RangeCEndT, EndMember const&&>); 57 58 constexpr bool testReturnTypes() { 59 { 60 int *x[2]; 61 ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int**); 62 ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), int* const*); 63 } 64 { 65 int x[2][2]; 66 ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int(*)[2]); 67 ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), const int(*)[2]); 68 } 69 { 70 struct Different { 71 char *begin(); 72 sentinel_wrapper<char*>& end(); 73 short *begin() const; 74 sentinel_wrapper<short*>& end() const; 75 } x; 76 ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), sentinel_wrapper<char*>); 77 ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), sentinel_wrapper<short*>); 78 } 79 return true; 80 } 81 82 constexpr bool testArray() { 83 int a[2]; 84 assert(std::ranges::end(a) == a + 2); 85 assert(std::ranges::cend(a) == a + 2); 86 87 int b[2][2]; 88 assert(std::ranges::end(b) == b + 2); 89 assert(std::ranges::cend(b) == b + 2); 90 91 EndMember c[2]; 92 assert(std::ranges::end(c) == c + 2); 93 assert(std::ranges::cend(c) == c + 2); 94 95 return true; 96 } 97 98 struct EndMemberReturnsInt { 99 int begin() const; 100 int end() const; 101 }; 102 static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsInt const&>); 103 104 struct EndMemberReturnsVoidPtr { 105 const void *begin() const; 106 const void *end() const; 107 }; 108 static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsVoidPtr const&>); 109 110 struct PtrConvertible { 111 operator int*() const; 112 }; 113 struct PtrConvertibleEndMember { 114 PtrConvertible begin() const; 115 PtrConvertible end() const; 116 }; 117 static_assert(!std::is_invocable_v<RangeEndT, PtrConvertibleEndMember const&>); 118 119 struct NoBeginMember { 120 constexpr const int *end(); 121 }; 122 static_assert(!std::is_invocable_v<RangeEndT, NoBeginMember const&>); 123 124 struct NonConstEndMember { 125 int x; 126 constexpr int *begin() { return nullptr; } 127 constexpr int *end() { return &x; } 128 }; 129 static_assert( std::is_invocable_v<RangeEndT, NonConstEndMember &>); 130 static_assert(!std::is_invocable_v<RangeEndT, NonConstEndMember const&>); 131 static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember &>); 132 static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember const&>); 133 134 struct EnabledBorrowingEndMember { 135 constexpr int *begin() const { return nullptr; } 136 constexpr int *end() const { return &globalBuff[0]; } 137 }; 138 139 template<> 140 inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingEndMember> = true; 141 142 struct EndMemberFunction { 143 int x; 144 constexpr const int *begin() const { return nullptr; } 145 constexpr const int *end() const { return &x; } 146 friend constexpr int *end(EndMemberFunction const&); 147 }; 148 149 struct Empty { }; 150 struct EmptyEndMember { 151 Empty begin() const; 152 Empty end() const; 153 }; 154 static_assert(!std::is_invocable_v<RangeEndT, EmptyEndMember const&>); 155 156 struct EmptyPtrEndMember { 157 Empty x; 158 constexpr const Empty *begin() const { return nullptr; } 159 constexpr const Empty *end() const { return &x; } 160 }; 161 162 constexpr bool testEndMember() { 163 EndMember a; 164 assert(std::ranges::end(a) == &a.x); 165 assert(std::ranges::cend(a) == &a.x); 166 167 NonConstEndMember b; 168 assert(std::ranges::end(b) == &b.x); 169 static_assert(!std::is_invocable_v<RangeCEndT, decltype((b))>); 170 171 EnabledBorrowingEndMember c; 172 assert(std::ranges::end(std::move(c)) == &globalBuff[0]); 173 assert(std::ranges::cend(std::move(c)) == &globalBuff[0]); 174 175 EndMemberFunction d; 176 assert(std::ranges::end(d) == &d.x); 177 assert(std::ranges::cend(d) == &d.x); 178 179 EmptyPtrEndMember e; 180 assert(std::ranges::end(e) == &e.x); 181 assert(std::ranges::cend(e) == &e.x); 182 183 return true; 184 } 185 186 struct EndFunction { 187 int x; 188 friend constexpr const int *begin(EndFunction const&) { return nullptr; } 189 friend constexpr const int *end(EndFunction const& bf) { return &bf.x; } 190 }; 191 192 static_assert( std::is_invocable_v<RangeEndT, EndFunction const&>); 193 static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>); 194 195 static_assert( std::is_invocable_v<RangeEndT, EndFunction const&>); 196 static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>); 197 static_assert(!std::is_invocable_v<RangeEndT, EndFunction &>); 198 static_assert( std::is_invocable_v<RangeCEndT, EndFunction const&>); 199 static_assert( std::is_invocable_v<RangeCEndT, EndFunction &>); 200 201 struct EndFunctionReturnsInt { 202 friend constexpr int begin(EndFunctionReturnsInt const&); 203 friend constexpr int end(EndFunctionReturnsInt const&); 204 }; 205 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsInt const&>); 206 207 struct EndFunctionReturnsVoidPtr { 208 friend constexpr void *begin(EndFunctionReturnsVoidPtr const&); 209 friend constexpr void *end(EndFunctionReturnsVoidPtr const&); 210 }; 211 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsVoidPtr const&>); 212 213 struct EndFunctionReturnsEmpty { 214 friend constexpr Empty begin(EndFunctionReturnsEmpty const&); 215 friend constexpr Empty end(EndFunctionReturnsEmpty const&); 216 }; 217 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsEmpty const&>); 218 219 struct EndFunctionReturnsPtrConvertible { 220 friend constexpr PtrConvertible begin(EndFunctionReturnsPtrConvertible const&); 221 friend constexpr PtrConvertible end(EndFunctionReturnsPtrConvertible const&); 222 }; 223 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsPtrConvertible const&>); 224 225 struct NoBeginFunction { 226 friend constexpr const int *end(NoBeginFunction const&); 227 }; 228 static_assert(!std::is_invocable_v<RangeEndT, NoBeginFunction const&>); 229 230 struct EndFunctionByValue { 231 friend constexpr int *begin(EndFunctionByValue) { return nullptr; } 232 friend constexpr int *end(EndFunctionByValue) { return &globalBuff[1]; } 233 }; 234 static_assert(!std::is_invocable_v<RangeCEndT, EndFunctionByValue>); 235 236 struct EndFunctionEnabledBorrowing { 237 friend constexpr int *begin(EndFunctionEnabledBorrowing) { return nullptr; } 238 friend constexpr int *end(EndFunctionEnabledBorrowing) { return &globalBuff[2]; } 239 }; 240 template<> 241 inline constexpr bool std::ranges::enable_borrowed_range<EndFunctionEnabledBorrowing> = true; 242 243 struct EndFunctionReturnsEmptyPtr { 244 Empty x; 245 friend constexpr const Empty *begin(EndFunctionReturnsEmptyPtr const&) { return nullptr; } 246 friend constexpr const Empty *end(EndFunctionReturnsEmptyPtr const& bf) { return &bf.x; } 247 }; 248 249 struct EndFunctionWithDataMember { 250 int x; 251 int end; 252 friend constexpr const int *begin(EndFunctionWithDataMember const&) { return nullptr; } 253 friend constexpr const int *end(EndFunctionWithDataMember const& bf) { return &bf.x; } 254 }; 255 256 struct EndFunctionWithPrivateEndMember { 257 int y; 258 friend constexpr const int *begin(EndFunctionWithPrivateEndMember const&) { return nullptr; } 259 friend constexpr const int *end(EndFunctionWithPrivateEndMember const& bf) { return &bf.y; } 260 private: 261 const int *end() const; 262 }; 263 264 struct BeginMemberEndFunction { 265 int x; 266 constexpr const int *begin() const { return nullptr; } 267 friend constexpr const int *end(BeginMemberEndFunction const& bf) { return &bf.x; } 268 }; 269 270 constexpr bool testEndFunction() { 271 const EndFunction a{}; 272 assert(std::ranges::end(a) == &a.x); 273 assert(std::ranges::cend(a) == &a.x); 274 EndFunction aa{}; 275 static_assert(!std::is_invocable_v<RangeEndT, decltype((aa))>); 276 assert(std::ranges::cend(aa) == &aa.x); 277 278 EndFunctionByValue b; 279 assert(std::ranges::end(b) == &globalBuff[1]); 280 assert(std::ranges::cend(b) == &globalBuff[1]); 281 282 EndFunctionEnabledBorrowing c; 283 assert(std::ranges::end(std::move(c)) == &globalBuff[2]); 284 assert(std::ranges::cend(std::move(c)) == &globalBuff[2]); 285 286 const EndFunctionReturnsEmptyPtr d{}; 287 assert(std::ranges::end(d) == &d.x); 288 assert(std::ranges::cend(d) == &d.x); 289 EndFunctionReturnsEmptyPtr dd{}; 290 static_assert(!std::is_invocable_v<RangeEndT, decltype((dd))>); 291 assert(std::ranges::cend(dd) == &dd.x); 292 293 const EndFunctionWithDataMember e{}; 294 assert(std::ranges::end(e) == &e.x); 295 assert(std::ranges::cend(e) == &e.x); 296 EndFunctionWithDataMember ee{}; 297 static_assert(!std::is_invocable_v<RangeEndT, decltype((ee))>); 298 assert(std::ranges::cend(ee) == &ee.x); 299 300 const EndFunctionWithPrivateEndMember f{}; 301 assert(std::ranges::end(f) == &f.y); 302 assert(std::ranges::cend(f) == &f.y); 303 EndFunctionWithPrivateEndMember ff{}; 304 static_assert(!std::is_invocable_v<RangeEndT, decltype((ff))>); 305 assert(std::ranges::cend(ff) == &ff.y); 306 307 const BeginMemberEndFunction g{}; 308 assert(std::ranges::end(g) == &g.x); 309 assert(std::ranges::cend(g) == &g.x); 310 BeginMemberEndFunction gg{}; 311 static_assert(!std::is_invocable_v<RangeEndT, decltype((gg))>); 312 assert(std::ranges::cend(gg) == &gg.x); 313 314 return true; 315 } 316 317 318 ASSERT_NOEXCEPT(std::ranges::end(std::declval<int (&)[10]>())); 319 ASSERT_NOEXCEPT(std::ranges::cend(std::declval<int (&)[10]>())); 320 321 struct NoThrowMemberEnd { 322 ThrowingIterator<int> begin() const; 323 ThrowingIterator<int> end() const noexcept; // auto(t.end()) doesn't throw 324 } ntme; 325 static_assert(noexcept(std::ranges::end(ntme))); 326 static_assert(noexcept(std::ranges::cend(ntme))); 327 328 struct NoThrowADLEnd { 329 ThrowingIterator<int> begin() const; 330 friend ThrowingIterator<int> end(NoThrowADLEnd&) noexcept; // auto(end(t)) doesn't throw 331 friend ThrowingIterator<int> end(const NoThrowADLEnd&) noexcept; 332 } ntae; 333 static_assert(noexcept(std::ranges::end(ntae))); 334 static_assert(noexcept(std::ranges::cend(ntae))); 335 336 struct NoThrowMemberEndReturnsRef { 337 ThrowingIterator<int> begin() const; 338 ThrowingIterator<int>& end() const noexcept; // auto(t.end()) may throw 339 } ntmerr; 340 static_assert(!noexcept(std::ranges::end(ntmerr))); 341 static_assert(!noexcept(std::ranges::cend(ntmerr))); 342 343 struct EndReturnsArrayRef { 344 auto begin() const noexcept -> int(&)[10]; 345 auto end() const noexcept -> int(&)[10]; 346 } erar; 347 static_assert(noexcept(std::ranges::end(erar))); 348 static_assert(noexcept(std::ranges::cend(erar))); 349 350 // Test ADL-proofing. 351 struct Incomplete; 352 template<class T> struct Holder { T t; }; 353 static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*>); 354 static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*&>); 355 static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*>); 356 static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*&>); 357 358 int main(int, char**) { 359 static_assert(testReturnTypes()); 360 361 testArray(); 362 static_assert(testArray()); 363 364 testEndMember(); 365 static_assert(testEndMember()); 366 367 testEndFunction(); 368 static_assert(testEndFunction()); 369 370 return 0; 371 } 372