//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 // std::ranges::end // std::ranges::cend #include #include #include #include "test_macros.h" #include "test_iterators.h" using RangeEndT = decltype(std::ranges::end); using RangeCEndT = decltype(std::ranges::cend); static int globalBuff[8]; static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); struct Incomplete; static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); struct EndMember { int x; const int *begin() const; constexpr const int *end() const { return &x; } }; // Ensure that we can't call with rvalues with borrowing disabled. static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); constexpr bool testReturnTypes() { { int *x[2]; ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int**); ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), int* const*); } { int x[2][2]; ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int(*)[2]); ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), const int(*)[2]); } { struct Different { char *begin(); sentinel_wrapper& end(); short *begin() const; sentinel_wrapper& end() const; } x; ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), sentinel_wrapper); ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), sentinel_wrapper); } return true; } constexpr bool testArray() { int a[2]; assert(std::ranges::end(a) == a + 2); assert(std::ranges::cend(a) == a + 2); int b[2][2]; assert(std::ranges::end(b) == b + 2); assert(std::ranges::cend(b) == b + 2); EndMember c[2]; assert(std::ranges::end(c) == c + 2); assert(std::ranges::cend(c) == c + 2); return true; } struct EndMemberReturnsInt { int begin() const; int end() const; }; static_assert(!std::is_invocable_v); struct EndMemberReturnsVoidPtr { const void *begin() const; const void *end() const; }; static_assert(!std::is_invocable_v); struct PtrConvertible { operator int*() const; }; struct PtrConvertibleEndMember { PtrConvertible begin() const; PtrConvertible end() const; }; static_assert(!std::is_invocable_v); struct NoBeginMember { constexpr const int *end(); }; static_assert(!std::is_invocable_v); struct NonConstEndMember { int x; constexpr int *begin() { return nullptr; } constexpr int *end() { return &x; } }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); struct EnabledBorrowingEndMember { constexpr int *begin() const { return nullptr; } constexpr int *end() const { return &globalBuff[0]; } }; template<> inline constexpr bool std::ranges::enable_borrowed_range = true; struct EndMemberFunction { int x; constexpr const int *begin() const { return nullptr; } constexpr const int *end() const { return &x; } friend constexpr int *end(EndMemberFunction const&); }; struct Empty { }; struct EmptyEndMember { Empty begin() const; Empty end() const; }; static_assert(!std::is_invocable_v); struct EmptyPtrEndMember { Empty x; constexpr const Empty *begin() const { return nullptr; } constexpr const Empty *end() const { return &x; } }; constexpr bool testEndMember() { EndMember a; assert(std::ranges::end(a) == &a.x); assert(std::ranges::cend(a) == &a.x); NonConstEndMember b; assert(std::ranges::end(b) == &b.x); static_assert(!std::is_invocable_v); EnabledBorrowingEndMember c; assert(std::ranges::end(std::move(c)) == &globalBuff[0]); assert(std::ranges::cend(std::move(c)) == &globalBuff[0]); EndMemberFunction d; assert(std::ranges::end(d) == &d.x); assert(std::ranges::cend(d) == &d.x); EmptyPtrEndMember e; assert(std::ranges::end(e) == &e.x); assert(std::ranges::cend(e) == &e.x); return true; } struct EndFunction { int x; friend constexpr const int *begin(EndFunction const&) { return nullptr; } friend constexpr const int *end(EndFunction const& bf) { return &bf.x; } }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); struct EndFunctionReturnsInt { friend constexpr int begin(EndFunctionReturnsInt const&); friend constexpr int end(EndFunctionReturnsInt const&); }; static_assert(!std::is_invocable_v); struct EndFunctionReturnsVoidPtr { friend constexpr void *begin(EndFunctionReturnsVoidPtr const&); friend constexpr void *end(EndFunctionReturnsVoidPtr const&); }; static_assert(!std::is_invocable_v); struct EndFunctionReturnsEmpty { friend constexpr Empty begin(EndFunctionReturnsEmpty const&); friend constexpr Empty end(EndFunctionReturnsEmpty const&); }; static_assert(!std::is_invocable_v); struct EndFunctionReturnsPtrConvertible { friend constexpr PtrConvertible begin(EndFunctionReturnsPtrConvertible const&); friend constexpr PtrConvertible end(EndFunctionReturnsPtrConvertible const&); }; static_assert(!std::is_invocable_v); struct NoBeginFunction { friend constexpr const int *end(NoBeginFunction const&); }; static_assert(!std::is_invocable_v); struct EndFunctionByValue { friend constexpr int *begin(EndFunctionByValue) { return nullptr; } friend constexpr int *end(EndFunctionByValue) { return &globalBuff[1]; } }; static_assert(!std::is_invocable_v); struct EndFunctionEnabledBorrowing { friend constexpr int *begin(EndFunctionEnabledBorrowing) { return nullptr; } friend constexpr int *end(EndFunctionEnabledBorrowing) { return &globalBuff[2]; } }; template<> inline constexpr bool std::ranges::enable_borrowed_range = true; struct EndFunctionReturnsEmptyPtr { Empty x; friend constexpr const Empty *begin(EndFunctionReturnsEmptyPtr const&) { return nullptr; } friend constexpr const Empty *end(EndFunctionReturnsEmptyPtr const& bf) { return &bf.x; } }; struct EndFunctionWithDataMember { int x; int end; friend constexpr const int *begin(EndFunctionWithDataMember const&) { return nullptr; } friend constexpr const int *end(EndFunctionWithDataMember const& bf) { return &bf.x; } }; struct EndFunctionWithPrivateEndMember { int y; friend constexpr const int *begin(EndFunctionWithPrivateEndMember const&) { return nullptr; } friend constexpr const int *end(EndFunctionWithPrivateEndMember const& bf) { return &bf.y; } private: const int *end() const; }; struct BeginMemberEndFunction { int x; constexpr const int *begin() const { return nullptr; } friend constexpr const int *end(BeginMemberEndFunction const& bf) { return &bf.x; } }; constexpr bool testEndFunction() { const EndFunction a{}; assert(std::ranges::end(a) == &a.x); assert(std::ranges::cend(a) == &a.x); EndFunction aa{}; static_assert(!std::is_invocable_v); assert(std::ranges::cend(aa) == &aa.x); EndFunctionByValue b; assert(std::ranges::end(b) == &globalBuff[1]); assert(std::ranges::cend(b) == &globalBuff[1]); EndFunctionEnabledBorrowing c; assert(std::ranges::end(std::move(c)) == &globalBuff[2]); assert(std::ranges::cend(std::move(c)) == &globalBuff[2]); const EndFunctionReturnsEmptyPtr d{}; assert(std::ranges::end(d) == &d.x); assert(std::ranges::cend(d) == &d.x); EndFunctionReturnsEmptyPtr dd{}; static_assert(!std::is_invocable_v); assert(std::ranges::cend(dd) == &dd.x); const EndFunctionWithDataMember e{}; assert(std::ranges::end(e) == &e.x); assert(std::ranges::cend(e) == &e.x); EndFunctionWithDataMember ee{}; static_assert(!std::is_invocable_v); assert(std::ranges::cend(ee) == &ee.x); const EndFunctionWithPrivateEndMember f{}; assert(std::ranges::end(f) == &f.y); assert(std::ranges::cend(f) == &f.y); EndFunctionWithPrivateEndMember ff{}; static_assert(!std::is_invocable_v); assert(std::ranges::cend(ff) == &ff.y); const BeginMemberEndFunction g{}; assert(std::ranges::end(g) == &g.x); assert(std::ranges::cend(g) == &g.x); BeginMemberEndFunction gg{}; static_assert(!std::is_invocable_v); assert(std::ranges::cend(gg) == &gg.x); return true; } ASSERT_NOEXCEPT(std::ranges::end(std::declval())); ASSERT_NOEXCEPT(std::ranges::cend(std::declval())); struct NoThrowMemberEnd { ThrowingIterator begin() const; ThrowingIterator end() const noexcept; // auto(t.end()) doesn't throw } ntme; static_assert(noexcept(std::ranges::end(ntme))); static_assert(noexcept(std::ranges::cend(ntme))); struct NoThrowADLEnd { ThrowingIterator begin() const; friend ThrowingIterator end(NoThrowADLEnd&) noexcept; // auto(end(t)) doesn't throw friend ThrowingIterator end(const NoThrowADLEnd&) noexcept; } ntae; static_assert(noexcept(std::ranges::end(ntae))); static_assert(noexcept(std::ranges::cend(ntae))); struct NoThrowMemberEndReturnsRef { ThrowingIterator begin() const; ThrowingIterator& end() const noexcept; // auto(t.end()) may throw } ntmerr; static_assert(!noexcept(std::ranges::end(ntmerr))); static_assert(!noexcept(std::ranges::cend(ntmerr))); struct EndReturnsArrayRef { auto begin() const noexcept -> int(&)[10]; auto end() const noexcept -> int(&)[10]; } erar; static_assert(noexcept(std::ranges::end(erar))); static_assert(noexcept(std::ranges::cend(erar))); // Test ADL-proofing. struct Incomplete; template struct Holder { T t; }; static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); int main(int, char**) { static_assert(testReturnTypes()); testArray(); static_assert(testArray()); testEndMember(); static_assert(testEndMember()); testEndFunction(); static_assert(testEndFunction()); return 0; }