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 | |
10 | // <iterator> |
11 | |
12 | // __libcpp_is_contiguous_iterator<_Tp> |
13 | |
14 | // __libcpp_is_contiguous_iterator determines if an iterator is contiguous, |
15 | // either because it advertises itself as such (in C++20) or because it |
16 | // is a pointer type or a known trivial wrapper around a pointer type, |
17 | // such as __wrap_iter<T*>. |
18 | // |
19 | |
20 | #include <cassert> |
21 | #include <deque> |
22 | #include <initializer_list> |
23 | #include <iterator> |
24 | #include <string> |
25 | #include <vector> |
26 | |
27 | #include "test_macros.h" |
28 | #include "test_iterators.h" |
29 | |
30 | #if TEST_STD_VER >= 17 |
31 | #include <string_view> |
32 | #endif |
33 | |
34 | #if TEST_STD_VER >= 20 |
35 | #include <span> |
36 | #endif |
37 | |
38 | class T; // incomplete |
39 | |
40 | class my_input_iterator |
41 | { |
42 | struct tag : std::input_iterator_tag {}; |
43 | typedef my_input_iterator Self; |
44 | int *state_; |
45 | public: |
46 | typedef tag iterator_category; |
47 | typedef int value_type; |
48 | typedef int difference_type; |
49 | typedef int* pointer; |
50 | typedef int& reference; |
51 | |
52 | my_input_iterator(); |
53 | reference operator*() const; |
54 | pointer operator->() const; |
55 | |
56 | Self& operator++(); |
57 | Self operator++(int); |
58 | friend bool operator==(const Self&, const Self&); |
59 | friend bool operator!=(const Self&, const Self&); |
60 | }; |
61 | |
62 | class my_random_access_iterator |
63 | { |
64 | struct tag : std::random_access_iterator_tag {}; |
65 | typedef my_random_access_iterator Self; |
66 | int *state_; |
67 | public: |
68 | typedef tag iterator_category; |
69 | typedef int value_type; |
70 | typedef int difference_type; |
71 | typedef int* pointer; |
72 | typedef int& reference; |
73 | |
74 | my_random_access_iterator(); |
75 | reference operator*() const; |
76 | pointer operator->() const; |
77 | reference operator[](difference_type) const; |
78 | |
79 | Self& operator++(); |
80 | Self operator++(int); |
81 | Self& operator--(); |
82 | Self operator--(int); |
83 | friend Self& operator+=(Self&, difference_type); |
84 | friend Self& operator-=(Self&, difference_type); |
85 | friend Self operator+(Self, difference_type); |
86 | friend Self operator+(difference_type, Self); |
87 | friend Self operator-(Self, difference_type); |
88 | friend difference_type operator-(Self, Self); |
89 | friend bool operator==(const Self&, const Self&); |
90 | friend bool operator!=(const Self&, const Self&); |
91 | friend bool operator<(const Self&, const Self&); |
92 | friend bool operator>(const Self&, const Self&); |
93 | friend bool operator<=(const Self&, const Self&); |
94 | friend bool operator>=(const Self&, const Self&); |
95 | }; |
96 | |
97 | #if TEST_STD_VER >= 20 |
98 | class my_contiguous_iterator |
99 | { |
100 | struct tag : std::contiguous_iterator_tag {}; |
101 | typedef my_contiguous_iterator Self; |
102 | int *state_; |
103 | public: |
104 | typedef tag iterator_category; |
105 | typedef int value_type; |
106 | typedef int difference_type; |
107 | typedef int* pointer; |
108 | typedef int& reference; |
109 | typedef int element_type; // enable to_address via pointer_traits |
110 | |
111 | my_contiguous_iterator(); |
112 | reference operator*() const; |
113 | pointer operator->() const; |
114 | reference operator[](difference_type) const; |
115 | |
116 | Self& operator++(); |
117 | Self operator++(int); |
118 | Self& operator--(); |
119 | Self operator--(int); |
120 | friend Self& operator+=(Self&, difference_type); |
121 | friend Self& operator-=(Self&, difference_type); |
122 | friend Self operator+(Self, difference_type); |
123 | friend Self operator+(difference_type, Self); |
124 | friend Self operator-(Self, difference_type); |
125 | friend difference_type operator-(Self, Self); |
126 | friend bool operator==(const Self&, const Self&); |
127 | friend bool operator!=(const Self&, const Self&); |
128 | friend bool operator<(const Self&, const Self&); |
129 | friend bool operator>(const Self&, const Self&); |
130 | friend bool operator<=(const Self&, const Self&); |
131 | friend bool operator>=(const Self&, const Self&); |
132 | }; |
133 | #endif |
134 | |
135 | struct fake_deque_iterator : std::deque<int>::iterator { |
136 | using element_type = int; |
137 | }; |
138 | static_assert(std::__has_random_access_iterator_category<fake_deque_iterator>::value, "" ); |
139 | static_assert(!std::__libcpp_is_contiguous_iterator<fake_deque_iterator>::value, "" ); |
140 | |
141 | #if TEST_STD_VER >= 20 |
142 | struct fake2_deque_iterator : std::deque<int>::iterator { |
143 | using iterator_concept = std::contiguous_iterator_tag; |
144 | using element_type = int; |
145 | }; |
146 | static_assert(std::__has_random_access_iterator_category<fake2_deque_iterator>::value, "" ); |
147 | static_assert(std::__libcpp_is_contiguous_iterator<fake2_deque_iterator>::value, "" ); |
148 | #endif |
149 | |
150 | int main(int, char**) |
151 | { |
152 | // basic tests |
153 | static_assert(( std::__libcpp_is_contiguous_iterator<char *>::value), "" ); |
154 | static_assert(( std::__libcpp_is_contiguous_iterator<const char *>::value), "" ); |
155 | static_assert(( std::__libcpp_is_contiguous_iterator<int *>::value), "" ); |
156 | static_assert(( std::__libcpp_is_contiguous_iterator<int **>::value), "" ); |
157 | static_assert(( std::__libcpp_is_contiguous_iterator<T *>::value), "" ); |
158 | |
159 | static_assert((!std::__libcpp_is_contiguous_iterator<my_input_iterator>::value), "" ); |
160 | static_assert((!std::__libcpp_is_contiguous_iterator<my_random_access_iterator>::value), "" ); |
161 | #if TEST_STD_VER >= 20 |
162 | static_assert(( std::__libcpp_is_contiguous_iterator<my_contiguous_iterator>::value), "" ); |
163 | #endif |
164 | |
165 | // move_iterator changes value category, which makes it pretty sketchy to use in optimized codepaths |
166 | static_assert((!std::__libcpp_is_contiguous_iterator<std::move_iterator<char *> >::value), "" ); |
167 | static_assert((!std::__libcpp_is_contiguous_iterator<std::move_iterator<const char *> >::value), "" ); |
168 | static_assert((!std::__libcpp_is_contiguous_iterator<std::move_iterator<int *> >::value), "" ); |
169 | static_assert((!std::__libcpp_is_contiguous_iterator<std::move_iterator<T *> >::value), "" ); |
170 | static_assert((!std::__libcpp_is_contiguous_iterator<std::move_iterator<my_random_access_iterator> >::value), "" ); |
171 | #if TEST_STD_VER >= 20 |
172 | static_assert((!std::__libcpp_is_contiguous_iterator<std::move_iterator<my_contiguous_iterator> >::value), "" ); |
173 | #endif |
174 | |
175 | static_assert((!std::__libcpp_is_contiguous_iterator<std::reverse_iterator<char *> >::value), "" ); |
176 | static_assert((!std::__libcpp_is_contiguous_iterator<std::reverse_iterator<const char *> >::value), "" ); |
177 | static_assert((!std::__libcpp_is_contiguous_iterator<std::reverse_iterator<int *> >::value), "" ); |
178 | static_assert((!std::__libcpp_is_contiguous_iterator<std::reverse_iterator<T *> >::value), "" ); |
179 | static_assert((!std::__libcpp_is_contiguous_iterator<std::reverse_iterator<my_random_access_iterator> >::value), "" ); |
180 | #if TEST_STD_VER >= 20 |
181 | static_assert((!std::__libcpp_is_contiguous_iterator<std::reverse_iterator<my_contiguous_iterator> >::value), "" ); |
182 | #endif |
183 | |
184 | static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<char *> >::value), "" ); |
185 | static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<const char *> >::value), "" ); |
186 | static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<int *> >::value), "" ); |
187 | |
188 | static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<T *> >::value), "" ); |
189 | static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<std::__wrap_iter<T *> > >::value), "" ); |
190 | |
191 | // Here my_random_access_iterator is standing in for some user's fancy pointer type, written pre-C++20. |
192 | static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<my_random_access_iterator> >::value), "" ); |
193 | static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<std::__wrap_iter<my_random_access_iterator> > >::value), "" ); |
194 | |
195 | #if TEST_STD_VER >= 20 |
196 | static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<my_contiguous_iterator> >::value), "" ); |
197 | static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<std::__wrap_iter<my_contiguous_iterator> > >::value), "" ); |
198 | #endif |
199 | |
200 | // iterators in the libc++ test suite |
201 | static_assert((!std::__libcpp_is_contiguous_iterator<cpp17_output_iterator <char *> >::value), "" ); |
202 | static_assert((!std::__libcpp_is_contiguous_iterator<cpp17_input_iterator <char *> >::value), "" ); |
203 | static_assert((!std::__libcpp_is_contiguous_iterator<forward_iterator <char *> >::value), "" ); |
204 | static_assert((!std::__libcpp_is_contiguous_iterator<bidirectional_iterator<char *> >::value), "" ); |
205 | static_assert((!std::__libcpp_is_contiguous_iterator<random_access_iterator<char *> >::value), "" ); |
206 | #if TEST_STD_VER >= 20 |
207 | static_assert(( std::__libcpp_is_contiguous_iterator<contiguous_iterator <char *> >::value), "" ); |
208 | #endif |
209 | static_assert((!std::__libcpp_is_contiguous_iterator<ThrowingIterator <char *> >::value), "" ); |
210 | static_assert((!std::__libcpp_is_contiguous_iterator<NonThrowingIterator <char *> >::value), "" ); |
211 | |
212 | // |
213 | // iterators from libc++'s containers |
214 | // |
215 | |
216 | // vector |
217 | static_assert(( std::__libcpp_is_contiguous_iterator<std::vector<int>::iterator> ::value), "" ); |
218 | static_assert(( std::__libcpp_is_contiguous_iterator<std::vector<int>::const_iterator> ::value), "" ); |
219 | static_assert((!std::__libcpp_is_contiguous_iterator<std::vector<int>::reverse_iterator> ::value), "" ); |
220 | static_assert((!std::__libcpp_is_contiguous_iterator<std::vector<int>::const_reverse_iterator> ::value), "" ); |
221 | static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<std::vector<int>::iterator> >::value), "" ); |
222 | |
223 | // string |
224 | static_assert(( std::__libcpp_is_contiguous_iterator<std::string::iterator> ::value), "" ); |
225 | static_assert(( std::__libcpp_is_contiguous_iterator<std::string::const_iterator> ::value), "" ); |
226 | static_assert((!std::__libcpp_is_contiguous_iterator<std::string::reverse_iterator> ::value), "" ); |
227 | static_assert((!std::__libcpp_is_contiguous_iterator<std::string::const_reverse_iterator>::value), "" ); |
228 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
229 | static_assert(( std::__libcpp_is_contiguous_iterator<std::wstring::iterator> ::value), "" ); |
230 | static_assert(( std::__libcpp_is_contiguous_iterator<std::wstring::const_iterator> ::value), "" ); |
231 | static_assert((!std::__libcpp_is_contiguous_iterator<std::wstring::reverse_iterator> ::value), "" ); |
232 | static_assert((!std::__libcpp_is_contiguous_iterator<std::wstring::const_reverse_iterator>::value), "" ); |
233 | #endif |
234 | |
235 | // deque is random-access but not contiguous |
236 | static_assert((!std::__libcpp_is_contiguous_iterator<std::deque<int>::iterator> ::value), "" ); |
237 | static_assert((!std::__libcpp_is_contiguous_iterator<std::deque<int>::const_iterator> ::value), "" ); |
238 | static_assert((!std::__libcpp_is_contiguous_iterator<std::deque<int>::reverse_iterator> ::value), "" ); |
239 | static_assert((!std::__libcpp_is_contiguous_iterator<std::deque<int>::const_reverse_iterator> ::value), "" ); |
240 | |
241 | // vector<bool> is random-access but not contiguous |
242 | static_assert((!std::__libcpp_is_contiguous_iterator<std::vector<bool>::iterator> ::value), "" ); |
243 | static_assert((!std::__libcpp_is_contiguous_iterator<std::vector<bool>::const_iterator> ::value), "" ); |
244 | static_assert((!std::__libcpp_is_contiguous_iterator<std::vector<bool>::reverse_iterator> ::value), "" ); |
245 | static_assert((!std::__libcpp_is_contiguous_iterator<std::vector<bool>::const_reverse_iterator> ::value), "" ); |
246 | |
247 | #if TEST_STD_VER >= 11 |
248 | static_assert(( std::__libcpp_is_contiguous_iterator<std::initializer_list<int>::iterator> ::value), "" ); |
249 | static_assert(( std::__libcpp_is_contiguous_iterator<std::initializer_list<int>::const_iterator>::value), "" ); |
250 | #endif |
251 | |
252 | #if TEST_STD_VER >= 17 |
253 | static_assert(( std::__libcpp_is_contiguous_iterator<std::string_view::iterator> ::value), "" ); |
254 | static_assert(( std::__libcpp_is_contiguous_iterator<std::string_view::const_iterator>::value), "" ); |
255 | #endif |
256 | |
257 | #if TEST_STD_VER >= 20 |
258 | static_assert(( std::__libcpp_is_contiguous_iterator<std::span< int>::iterator> ::value), "" ); |
259 | static_assert((!std::__libcpp_is_contiguous_iterator<std::span< int>::reverse_iterator>::value), "" ); |
260 | static_assert(( std::__libcpp_is_contiguous_iterator<std::span<const int>::iterator> ::value), "" ); |
261 | static_assert((!std::__libcpp_is_contiguous_iterator<std::span<const int>::reverse_iterator>::value), "" ); |
262 | #endif |
263 | |
264 | return 0; |
265 | } |
266 | |