| //===----------------------------------------------------------------------===// |
| // |
| // 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::data |
| |
| #include <ranges> |
| |
| #include <cassert> |
| #include <type_traits> |
| #include "test_macros.h" |
| #include "test_iterators.h" |
| |
| using RangeDataT = decltype(std::ranges::data); |
| using RangeCDataT = decltype(std::ranges::cdata); |
| |
| static int globalBuff[2]; |
| |
| struct Incomplete; |
| |
| static_assert(!std::is_invocable_v<RangeDataT, Incomplete[]>); |
| static_assert(!std::is_invocable_v<RangeDataT, Incomplete(&&)[2]>); |
| static_assert(!std::is_invocable_v<RangeDataT, Incomplete(&&)[2][2]>); |
| static_assert(!std::is_invocable_v<RangeDataT, int [1]>); |
| static_assert(!std::is_invocable_v<RangeDataT, int (&&)[1]>); |
| static_assert( std::is_invocable_v<RangeDataT, int (&)[1]>); |
| |
| static_assert(!std::is_invocable_v<RangeCDataT, Incomplete[]>); |
| static_assert(!std::is_invocable_v<RangeCDataT, Incomplete(&&)[2]>); |
| static_assert(!std::is_invocable_v<RangeCDataT, Incomplete(&&)[2][2]>); |
| static_assert(!std::is_invocable_v<RangeCDataT, int [1]>); |
| static_assert(!std::is_invocable_v<RangeCDataT, int (&&)[1]>); |
| static_assert( std::is_invocable_v<RangeCDataT, int (&)[1]>); |
| |
| struct DataMember { |
| int x; |
| constexpr const int *data() const { return &x; } |
| }; |
| static_assert( std::is_invocable_v<RangeDataT, DataMember &>); |
| static_assert(!std::is_invocable_v<RangeDataT, DataMember &&>); |
| static_assert( std::is_invocable_v<RangeDataT, DataMember const&>); |
| static_assert(!std::is_invocable_v<RangeDataT, DataMember const&&>); |
| static_assert( std::is_invocable_v<RangeCDataT, DataMember &>); |
| static_assert(!std::is_invocable_v<RangeCDataT, DataMember &&>); |
| static_assert( std::is_invocable_v<RangeCDataT, DataMember const&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, DataMember const&&>); |
| |
| constexpr bool testReturnTypes() { |
| { |
| int *x[2]; |
| ASSERT_SAME_TYPE(decltype(std::ranges::data(x)), int**); |
| ASSERT_SAME_TYPE(decltype(std::ranges::cdata(x)), int* const*); |
| } |
| { |
| int x[2][2]; |
| ASSERT_SAME_TYPE(decltype(std::ranges::data(x)), int(*)[2]); |
| ASSERT_SAME_TYPE(decltype(std::ranges::cdata(x)), const int(*)[2]); |
| } |
| { |
| struct D { |
| char*& data(); |
| short*& data() const; |
| }; |
| ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<D&>())), char*); |
| static_assert(!std::is_invocable_v<RangeDataT, D&&>); |
| ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<const D&>())), short*); |
| static_assert(!std::is_invocable_v<RangeDataT, const D&&>); |
| ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval<D&>())), short*); |
| static_assert(!std::is_invocable_v<RangeCDataT, D&&>); |
| ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval<const D&>())), short*); |
| static_assert(!std::is_invocable_v<RangeCDataT, const D&&>); |
| } |
| { |
| struct NC { |
| char *begin() const; |
| char *end() const; |
| int *data(); |
| }; |
| static_assert(!std::ranges::contiguous_range<NC>); |
| static_assert( std::ranges::contiguous_range<const NC>); |
| ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<NC&>())), int*); |
| static_assert(!std::is_invocable_v<RangeDataT, NC&&>); |
| ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<const NC&>())), char*); |
| static_assert(!std::is_invocable_v<RangeDataT, const NC&&>); |
| ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval<NC&>())), char*); |
| static_assert(!std::is_invocable_v<RangeCDataT, NC&&>); |
| ASSERT_SAME_TYPE(decltype(std::ranges::cdata(std::declval<const NC&>())), char*); |
| static_assert(!std::is_invocable_v<RangeCDataT, const NC&&>); |
| } |
| return true; |
| } |
| |
| struct VoidDataMember { |
| void *data() const; |
| }; |
| static_assert(!std::is_invocable_v<RangeDataT, VoidDataMember const&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, VoidDataMember const&>); |
| |
| struct Empty { }; |
| struct EmptyDataMember { |
| Empty data() const; |
| }; |
| static_assert(!std::is_invocable_v<RangeDataT, EmptyDataMember const&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, EmptyDataMember const&>); |
| |
| struct PtrConvertibleDataMember { |
| struct Ptr { |
| operator int*() const; |
| }; |
| Ptr data() const; |
| }; |
| static_assert(!std::is_invocable_v<RangeDataT, PtrConvertibleDataMember const&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, PtrConvertibleDataMember const&>); |
| |
| struct NonConstDataMember { |
| int x; |
| constexpr int *data() { return &x; } |
| }; |
| |
| struct EnabledBorrowingDataMember { |
| constexpr int *data() { return &globalBuff[0]; } |
| }; |
| template<> |
| inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingDataMember> = true; |
| |
| struct DataMemberAndBegin { |
| int x; |
| constexpr const int *data() const { return &x; } |
| const int *begin() const; |
| }; |
| |
| constexpr bool testDataMember() { |
| DataMember a; |
| assert(std::ranges::data(a) == &a.x); |
| assert(std::ranges::cdata(a) == &a.x); |
| |
| NonConstDataMember b; |
| assert(std::ranges::data(b) == &b.x); |
| static_assert(!std::is_invocable_v<RangeCDataT, decltype((b))>); |
| |
| EnabledBorrowingDataMember c; |
| assert(std::ranges::data(std::move(c)) == &globalBuff[0]); |
| static_assert(!std::is_invocable_v<RangeCDataT, decltype(std::move(c))>); |
| |
| DataMemberAndBegin d; |
| assert(std::ranges::data(d) == &d.x); |
| assert(std::ranges::cdata(d) == &d.x); |
| |
| return true; |
| } |
| |
| using ContiguousIter = contiguous_iterator<const int*>; |
| |
| struct BeginMemberContiguousIterator { |
| int buff[8]; |
| |
| constexpr ContiguousIter begin() const { return ContiguousIter(buff); } |
| }; |
| static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &>); |
| static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &&>); |
| static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&>); |
| static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&&>); |
| static_assert( std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator &>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator &&>); |
| static_assert( std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator const&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator const&&>); |
| |
| struct BeginMemberRandomAccess { |
| int buff[8]; |
| |
| random_access_iterator<const int*> begin() const; |
| }; |
| static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRandomAccess&>); |
| static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRandomAccess&&>); |
| static_assert(!std::is_invocable_v<RangeDataT, const BeginMemberRandomAccess&>); |
| static_assert(!std::is_invocable_v<RangeDataT, const BeginMemberRandomAccess&&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRandomAccess&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRandomAccess&&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, const BeginMemberRandomAccess&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, const BeginMemberRandomAccess&&>); |
| |
| struct BeginFriendContiguousIterator { |
| int buff[8]; |
| |
| friend constexpr ContiguousIter begin(const BeginFriendContiguousIterator &iter) { |
| return ContiguousIter(iter.buff); |
| } |
| }; |
| static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &>); |
| static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &&>); |
| static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&>); |
| static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&&>); |
| static_assert( std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator &>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator &&>); |
| static_assert( std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator const&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberContiguousIterator const&&>); |
| |
| struct BeginFriendRandomAccess { |
| friend random_access_iterator<const int*> begin(const BeginFriendRandomAccess iter); |
| }; |
| static_assert(!std::is_invocable_v<RangeDataT, BeginFriendRandomAccess&>); |
| static_assert(!std::is_invocable_v<RangeDataT, BeginFriendRandomAccess&&>); |
| static_assert(!std::is_invocable_v<RangeDataT, const BeginFriendRandomAccess&>); |
| static_assert(!std::is_invocable_v<RangeDataT, const BeginFriendRandomAccess&&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginFriendRandomAccess&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginFriendRandomAccess&&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, const BeginFriendRandomAccess&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, const BeginFriendRandomAccess&&>); |
| |
| struct BeginMemberRvalue { |
| int buff[8]; |
| |
| ContiguousIter begin() &&; |
| }; |
| static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&>); |
| static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&&>); |
| static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&>); |
| static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRvalue&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRvalue&&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRvalue const&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberRvalue const&&>); |
| |
| struct BeginMemberBorrowingEnabled { |
| constexpr contiguous_iterator<int*> begin() { return contiguous_iterator<int*>{&globalBuff[1]}; } |
| }; |
| template<> |
| inline constexpr bool std::ranges::enable_borrowed_range<BeginMemberBorrowingEnabled> = true; |
| static_assert( std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled &>); |
| static_assert( std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled &&>); |
| static_assert(!std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled const&>); |
| static_assert(!std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled const&&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberBorrowingEnabled &>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberBorrowingEnabled &&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberBorrowingEnabled const&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, BeginMemberBorrowingEnabled const&&>); |
| |
| constexpr bool testViaRangesBegin() { |
| int arr[2]; |
| assert(std::ranges::data(arr) == arr + 0); |
| assert(std::ranges::cdata(arr) == arr + 0); |
| |
| BeginMemberContiguousIterator a; |
| assert(std::ranges::data(a) == a.buff); |
| assert(std::ranges::cdata(a) == a.buff); |
| |
| const BeginFriendContiguousIterator b {}; |
| assert(std::ranges::data(b) == b.buff); |
| assert(std::ranges::cdata(b) == b.buff); |
| |
| BeginMemberBorrowingEnabled c; |
| assert(std::ranges::data(std::move(c)) == &globalBuff[1]); |
| static_assert(!std::is_invocable_v<RangeCDataT, decltype(std::move(c))>); |
| |
| return true; |
| } |
| |
| // Test ADL-proofing. |
| struct Incomplete; |
| template<class T> struct Holder { T t; }; |
| static_assert(!std::is_invocable_v<RangeDataT, Holder<Incomplete>*>); |
| static_assert(!std::is_invocable_v<RangeDataT, Holder<Incomplete>*&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, Holder<Incomplete>*>); |
| static_assert(!std::is_invocable_v<RangeCDataT, Holder<Incomplete>*&>); |
| |
| struct RandomButNotContiguous { |
| random_access_iterator<int*> begin() const; |
| random_access_iterator<int*> end() const; |
| }; |
| static_assert(!std::is_invocable_v<RangeDataT, RandomButNotContiguous>); |
| static_assert(!std::is_invocable_v<RangeDataT, RandomButNotContiguous&>); |
| static_assert(!std::is_invocable_v<RangeCDataT, RandomButNotContiguous>); |
| static_assert(!std::is_invocable_v<RangeCDataT, RandomButNotContiguous&>); |
| |
| int main(int, char**) { |
| static_assert(testReturnTypes()); |
| |
| testDataMember(); |
| static_assert(testDataMember()); |
| |
| testViaRangesBegin(); |
| static_assert(testViaRangesBegin()); |
| |
| return 0; |
| } |