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
38class T; // incomplete
39
40class my_input_iterator
41{
42 struct tag : std::input_iterator_tag {};
43 typedef my_input_iterator Self;
44 int *state_;
45public:
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
62class my_random_access_iterator
63{
64 struct tag : std::random_access_iterator_tag {};
65 typedef my_random_access_iterator Self;
66 int *state_;
67public:
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
98class my_contiguous_iterator
99{
100 struct tag : std::contiguous_iterator_tag {};
101 typedef my_contiguous_iterator Self;
102 int *state_;
103public:
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
135struct fake_deque_iterator : std::deque<int>::iterator {
136 using element_type = int;
137};
138static_assert(std::__has_random_access_iterator_category<fake_deque_iterator>::value, "");
139static_assert(!std::__libcpp_is_contiguous_iterator<fake_deque_iterator>::value, "");
140
141#if TEST_STD_VER >= 20
142struct fake2_deque_iterator : std::deque<int>::iterator {
143 using iterator_concept = std::contiguous_iterator_tag;
144 using element_type = int;
145};
146static_assert(std::__has_random_access_iterator_category<fake2_deque_iterator>::value, "");
147static_assert(std::__libcpp_is_contiguous_iterator<fake2_deque_iterator>::value, "");
148#endif
149
150int 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

source code of libcxx/test/libcxx/iterators/contiguous_iterators.pass.cpp