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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
12 
13 // std::ranges::data
14 
15 #include <ranges>
16 
17 #include <cassert>
18 #include "test_macros.h"
19 #include "test_iterators.h"
20 
21 using RangeDataT = decltype(std::ranges::data);
22 
23 static int globalBuff[2];
24 
25 struct Incomplete;
26 
27 static_assert(!std::is_invocable_v<RangeDataT, Incomplete[]>);
28 static_assert(!std::is_invocable_v<RangeDataT, Incomplete[2]>);
29 static_assert(!std::is_invocable_v<RangeDataT, Incomplete[2][2]>);
30 static_assert(!std::is_invocable_v<RangeDataT, int [1]>);
31 static_assert(!std::is_invocable_v<RangeDataT, int (&&)[1]>);
32 static_assert( std::is_invocable_v<RangeDataT, int (&)[1]>);
33 
34 struct DataMember {
35   int x;
36   constexpr const int *data() const { return &x; }
37 };
38 
39 static_assert( std::is_invocable_v<RangeDataT, DataMember &>);
40 static_assert(!std::is_invocable_v<RangeDataT, DataMember &&>);
41 
42 struct VoidDataMember {
43   void *data() const;
44 };
45 static_assert(!std::is_invocable_v<RangeDataT, VoidDataMember const&>);
46 
47 struct Empty { };
48 struct EmptyDataMember {
49   Empty data() const;
50 };
51 
52 static_assert(!std::is_invocable_v<RangeDataT, EmptyDataMember const&>);
53 
54 struct EmptyPtrDataMember {
55   Empty x;
56   constexpr const Empty *data() const { return &x; }
57 };
58 
59 struct PtrConvertible {
60   operator int*() const;
61 };
62 struct PtrConvertibleDataMember {
63   PtrConvertible data() const;
64 };
65 
66 static_assert(!std::is_invocable_v<RangeDataT, PtrConvertibleDataMember const&>);
67 
68 struct NonConstDataMember {
69   int x;
70   constexpr int *data() { return &x; }
71 };
72 
73 struct EnabledBorrowingDataMember {
74   constexpr int *data() { return &globalBuff[0]; }
75 };
76 
77 template<>
78 inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingDataMember> = true;
79 
80 struct DataMemberAndBegin {
81   int x;
82   constexpr const int *data() const { return &x; }
83   constexpr const int *begin() const { return &x; }
84 };
85 
86 constexpr bool testDataMember() {
87   DataMember a;
88   assert(std::ranges::data(a) == &a.x);
89 
90   NonConstDataMember b;
91   assert(std::ranges::data(b) == &b.x);
92 
93   EnabledBorrowingDataMember c;
94   assert(std::ranges::data(std::move(c)) == &globalBuff[0]);
95 
96   DataMemberAndBegin d;
97   assert(std::ranges::data(d) == &d.x);
98 
99   return true;
100 }
101 
102 using ContiguousIter = contiguous_iterator<const int*>;
103 
104 struct BeginMemberContiguousIterator {
105   int buff[8];
106 
107   constexpr ContiguousIter begin() const { return ContiguousIter(buff); }
108 };
109 static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &>);
110 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &&>);
111 static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&>);
112 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&&>);
113 
114 struct BeginMemberRandomAccess {
115   int buff[8];
116 
117   random_access_iterator<const int*> begin() const;
118 };
119 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRandomAccess>);
120 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRandomAccess const>);
121 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRandomAccess const&>);
122 
123 struct BeginFriendContiguousIterator {
124   int buff[8];
125 
126   friend constexpr ContiguousIter begin(const BeginFriendContiguousIterator &iter) {
127     return ContiguousIter(iter.buff);
128   }
129 };
130 static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &>);
131 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator &&>);
132 static_assert( std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&>);
133 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberContiguousIterator const&&>);
134 
135 struct BeginFriendRandomAccess {
136   friend random_access_iterator<const int*> begin(const BeginFriendRandomAccess iter);
137 };
138 static_assert(!std::is_invocable_v<RangeDataT, BeginFriendRandomAccess>);
139 static_assert(!std::is_invocable_v<RangeDataT, BeginFriendRandomAccess const>);
140 static_assert(!std::is_invocable_v<RangeDataT, BeginFriendRandomAccess const&>);
141 
142 struct BeginMemberRvalue {
143   int buff[8];
144 
145   ContiguousIter begin() &&;
146 };
147 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&&>);
148 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&>);
149 
150 struct BeginMemberBorrowingEnabled {
151   constexpr contiguous_iterator<int*> begin() { return contiguous_iterator<int*>{&globalBuff[1]}; }
152 };
153 template<>
154 inline constexpr bool std::ranges::enable_borrowed_range<BeginMemberBorrowingEnabled> = true;
155 static_assert( std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled &>);
156 static_assert( std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled &&>);
157 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled const&>);
158 static_assert(!std::is_invocable_v<RangeDataT, BeginMemberBorrowingEnabled const&&>);
159 
160 constexpr bool testViaRangesBegin() {
161   int arr[2];
162   assert(std::ranges::data(arr) == arr + 0);
163 
164   BeginMemberContiguousIterator a;
165   assert(std::ranges::data(a) == a.buff);
166 
167   const BeginFriendContiguousIterator b {};
168   assert(std::ranges::data(b) == b.buff);
169 
170   BeginMemberBorrowingEnabled c;
171   assert(std::ranges::data(std::move(c)) == &globalBuff[1]);
172 
173   return true;
174 }
175 
176 int main(int, char**) {
177   testDataMember();
178   static_assert(testDataMember());
179 
180   testViaRangesBegin();
181   static_assert(testViaRangesBegin());
182 
183   return 0;
184 }
185