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