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 | |
11 | // This test uses iterator types from std::filesystem |
12 | // XFAIL: availability-filesystem-missing |
13 | |
14 | // template<class T> |
15 | // struct iterator_traits; |
16 | |
17 | #include <iterator> |
18 | |
19 | #include <array> |
20 | #include <concepts> |
21 | #include <cstddef> |
22 | #include <deque> |
23 | #include <forward_list> |
24 | #include <list> |
25 | #include <map> |
26 | #include <memory> |
27 | #include <optional> |
28 | #include <set> |
29 | #include <string> |
30 | #include <string_view> |
31 | #include <unordered_map> |
32 | #include <unordered_set> |
33 | #include <vector> |
34 | |
35 | #include "test_macros.h" |
36 | |
37 | #ifndef TEST_HAS_NO_LOCALIZATION |
38 | # include <regex> |
39 | # include <ostream> |
40 | # include <istream> |
41 | #endif |
42 | |
43 | #ifndef TEST_HAS_NO_FILESYSTEM |
44 | # include <filesystem> |
45 | #endif |
46 | |
47 | #include "test_iterators.h" |
48 | #include "iterator_traits_cpp17_iterators.h" |
49 | |
50 | template <class Traits> |
51 | constexpr bool has_iterator_concept_v = requires { |
52 | typename Traits::iterator_concept; |
53 | }; |
54 | |
55 | template <class Iter, class Category, class ValueType, class DiffType, class RefType, class PtrType> |
56 | constexpr bool test() { |
57 | using Traits = std::iterator_traits<Iter>; |
58 | static_assert(std::same_as<typename Traits::iterator_category, Category>); |
59 | static_assert(std::same_as<typename Traits::value_type, ValueType>); |
60 | static_assert(std::same_as<typename Traits::difference_type, DiffType>); |
61 | static_assert(std::same_as<typename Traits::reference, RefType>); |
62 | static_assert(std::same_as<typename Traits::pointer, PtrType>); |
63 | if constexpr (std::is_pointer_v<Iter>) { |
64 | static_assert(std::same_as<typename Traits::iterator_concept, std::contiguous_iterator_tag>); |
65 | } else { |
66 | static_assert(!has_iterator_concept_v<Traits>); |
67 | } |
68 | |
69 | return true; |
70 | } |
71 | |
72 | template <class Iter, class Category> |
73 | constexpr bool testIOIterator() { |
74 | return test<Iter, Category, void, std::ptrdiff_t, void, void>(); |
75 | } |
76 | |
77 | template <class Iter, class Category, class ValueType> |
78 | constexpr bool testConst() { |
79 | return test<Iter, Category, ValueType, std::ptrdiff_t, const ValueType&, const ValueType*>(); |
80 | } |
81 | |
82 | template <class Iter, class Category, class ValueType> |
83 | constexpr bool testMutable() { |
84 | return test<Iter, Category, ValueType, std::ptrdiff_t, ValueType&, ValueType*>(); |
85 | } |
86 | |
87 | // Standard types. |
88 | |
89 | // The Standard does not specify whether iterator_traits<It>::iterator_concept |
90 | // exists for any particular non-pointer type, we assume it is present |
91 | // only for pointers. |
92 | // |
93 | static_assert(testMutable<std::array<int, 10>::iterator, std::random_access_iterator_tag, int>()); |
94 | static_assert(testConst<std::array<int, 10>::const_iterator, std::random_access_iterator_tag, int>()); |
95 | static_assert(testMutable<std::string::iterator, std::random_access_iterator_tag, char>()); |
96 | static_assert(testConst<std::string::const_iterator, std::random_access_iterator_tag, char>()); |
97 | static_assert(testConst<std::string_view::iterator, std::random_access_iterator_tag, char>()); |
98 | static_assert(testConst<std::string_view::const_iterator, std::random_access_iterator_tag, char>()); |
99 | static_assert(testMutable<std::vector<int>::iterator, std::random_access_iterator_tag, int>()); |
100 | static_assert(testConst<std::vector<int>::const_iterator, std::random_access_iterator_tag, int>()); |
101 | |
102 | static_assert(testMutable<std::deque<int>::iterator, std::random_access_iterator_tag, int>()); |
103 | static_assert(testConst<std::deque<int>::const_iterator, std::random_access_iterator_tag, int>()); |
104 | static_assert(testMutable<std::forward_list<int>::iterator, std::forward_iterator_tag, int>()); |
105 | static_assert(testConst<std::forward_list<int>::const_iterator, std::forward_iterator_tag, int>()); |
106 | static_assert(testMutable<std::list<int>::iterator, std::bidirectional_iterator_tag, int>()); |
107 | static_assert(testConst<std::list<int>::const_iterator, std::bidirectional_iterator_tag, int>()); |
108 | |
109 | static_assert(testMutable<std::map<int, int>::iterator, std::bidirectional_iterator_tag, std::pair<const int, int>>()); |
110 | static_assert(testConst<std::map<int, int>::const_iterator, std::bidirectional_iterator_tag, std::pair<const int, int>>()); |
111 | static_assert(testMutable<std::multimap<int, int>::iterator, std::bidirectional_iterator_tag, std::pair<const int, int>>()); |
112 | static_assert(testConst<std::multimap<int, int>::const_iterator, std::bidirectional_iterator_tag, std::pair<const int, int>>()); |
113 | |
114 | static_assert(testConst<std::set<int>::iterator, std::bidirectional_iterator_tag, int>()); |
115 | static_assert(testConst<std::set<int>::const_iterator, std::bidirectional_iterator_tag, int>()); |
116 | static_assert(testConst<std::multiset<int>::iterator, std::bidirectional_iterator_tag, int>()); |
117 | static_assert(testConst<std::multiset<int>::const_iterator, std::bidirectional_iterator_tag, int>()); |
118 | |
119 | #ifdef _MSVC_STL_VERSION |
120 | using unordered_iterator_category = std::bidirectional_iterator_tag; |
121 | #else // ^^^ MSVC STL / other vvv |
122 | using unordered_iterator_category = std::forward_iterator_tag; |
123 | #endif // _MSVC_STL_VERSION |
124 | |
125 | static_assert(testMutable<std::unordered_map<int, int>::iterator, unordered_iterator_category, std::pair<const int, int>>()); |
126 | static_assert(testConst<std::unordered_map<int, int>::const_iterator, unordered_iterator_category, std::pair<const int, int>>()); |
127 | static_assert(testMutable<std::unordered_map<int, int>::local_iterator, unordered_iterator_category, std::pair<const int, int>>()); |
128 | static_assert(testConst<std::unordered_map<int, int>::const_local_iterator, unordered_iterator_category, std::pair<const int, int>>()); |
129 | static_assert(testMutable<std::unordered_multimap<int, int>::iterator, unordered_iterator_category, std::pair<const int, int>>()); |
130 | static_assert(testConst<std::unordered_multimap<int, int>::const_iterator, unordered_iterator_category, std::pair<const int, int>>()); |
131 | static_assert(testMutable<std::unordered_multimap<int, int>::local_iterator, unordered_iterator_category, std::pair<const int, int>>()); |
132 | static_assert(testConst<std::unordered_multimap<int, int>::const_local_iterator, unordered_iterator_category, std::pair<const int, int>>()); |
133 | |
134 | static_assert(testConst<std::unordered_set<int>::iterator, unordered_iterator_category, int>()); |
135 | static_assert(testConst<std::unordered_set<int>::const_iterator, unordered_iterator_category, int>()); |
136 | static_assert(testConst<std::unordered_set<int>::local_iterator, unordered_iterator_category, int>()); |
137 | static_assert(testConst<std::unordered_set<int>::const_local_iterator, unordered_iterator_category, int>()); |
138 | static_assert(testConst<std::unordered_multiset<int>::iterator, unordered_iterator_category, int>()); |
139 | static_assert(testConst<std::unordered_multiset<int>::const_iterator, unordered_iterator_category, int>()); |
140 | static_assert(testConst<std::unordered_multiset<int>::local_iterator, unordered_iterator_category, int>()); |
141 | static_assert(testConst<std::unordered_multiset<int>::const_local_iterator, unordered_iterator_category, int>()); |
142 | |
143 | static_assert(testMutable<std::reverse_iterator<int*>, std::random_access_iterator_tag, int>()); |
144 | static_assert(testIOIterator<std::back_insert_iterator<std::vector<int>>, std::output_iterator_tag>()); |
145 | static_assert(testIOIterator<std::front_insert_iterator<std::vector<int>>, std::output_iterator_tag>()); |
146 | static_assert(testIOIterator<std::insert_iterator<std::vector<int>>, std::output_iterator_tag>()); |
147 | static_assert(testConst<std::istream_iterator<int, char>, std::input_iterator_tag, int>()); |
148 | |
149 | #if !defined(TEST_HAS_NO_LOCALIZATION) |
150 | // We use std::istreambuf_iterator<char>::pointer because it's unspecified, it doesn't have to be char* |
151 | static_assert(test<std::istreambuf_iterator<char>, |
152 | std::input_iterator_tag, |
153 | char, |
154 | std::streamoff, |
155 | char, |
156 | std::istreambuf_iterator<char>::pointer>()); |
157 | static_assert(test<std::move_iterator<int*>, std::random_access_iterator_tag, int, std::ptrdiff_t, int&&, int*>()); |
158 | static_assert(testIOIterator<std::ostream_iterator<int, char>, std::output_iterator_tag>()); |
159 | static_assert(testIOIterator<std::ostreambuf_iterator<int, char>, std::output_iterator_tag>()); |
160 | static_assert(testConst<std::cregex_iterator, std::forward_iterator_tag, std::cmatch>()); |
161 | static_assert(testConst<std::cregex_token_iterator, std::forward_iterator_tag, std::csub_match>()); |
162 | #endif // !TEST_HAS_NO_LOCALIZATION |
163 | |
164 | #ifndef TEST_HAS_NO_FILESYSTEM |
165 | static_assert(test<std::filesystem::directory_iterator, std::input_iterator_tag, std::filesystem::directory_entry, |
166 | std::ptrdiff_t, const std::filesystem::directory_entry&, const std::filesystem::directory_entry*>()); |
167 | static_assert(test<std::filesystem::recursive_directory_iterator, std::input_iterator_tag, |
168 | std::filesystem::directory_entry, std::ptrdiff_t, const std::filesystem::directory_entry&, |
169 | const std::filesystem::directory_entry*>()); |
170 | #endif |
171 | |
172 | // Local test iterators. |
173 | |
174 | struct AllMembers { |
175 | struct iterator_category {}; |
176 | struct value_type {}; |
177 | struct difference_type {}; |
178 | struct reference {}; |
179 | struct pointer {}; |
180 | }; |
181 | using AllMembersTraits = std::iterator_traits<AllMembers>; |
182 | static_assert(std::same_as<AllMembersTraits::iterator_category, AllMembers::iterator_category>); |
183 | static_assert(std::same_as<AllMembersTraits::value_type, AllMembers::value_type>); |
184 | static_assert(std::same_as<AllMembersTraits::difference_type, AllMembers::difference_type>); |
185 | static_assert(std::same_as<AllMembersTraits::reference, AllMembers::reference>); |
186 | static_assert(std::same_as<AllMembersTraits::pointer, AllMembers::pointer>); |
187 | static_assert(!has_iterator_concept_v<AllMembersTraits>); |
188 | |
189 | struct NoPointerMember { |
190 | struct iterator_category {}; |
191 | struct value_type {}; |
192 | struct difference_type {}; |
193 | struct reference {}; |
194 | // ignored, because NoPointerMember is not a LegacyInputIterator: |
195 | value_type* operator->() const; |
196 | }; |
197 | using NoPointerMemberTraits = std::iterator_traits<NoPointerMember>; |
198 | static_assert(std::same_as<NoPointerMemberTraits::iterator_category, NoPointerMember::iterator_category>); |
199 | static_assert(std::same_as<NoPointerMemberTraits::value_type, NoPointerMember::value_type>); |
200 | static_assert(std::same_as<NoPointerMemberTraits::difference_type, NoPointerMember::difference_type>); |
201 | static_assert(std::same_as<NoPointerMemberTraits::reference, NoPointerMember::reference>); |
202 | static_assert(std::same_as<NoPointerMemberTraits::pointer, void>); |
203 | static_assert(!has_iterator_concept_v<NoPointerMemberTraits>); |
204 | |
205 | struct IterConcept { |
206 | struct iterator_category {}; |
207 | struct value_type {}; |
208 | struct difference_type {}; |
209 | struct reference {}; |
210 | struct pointer {}; |
211 | // iterator_traits does NOT pass through the iterator_concept of the type itself. |
212 | struct iterator_concept {}; |
213 | }; |
214 | using IterConceptTraits = std::iterator_traits<IterConcept>; |
215 | static_assert(std::same_as<IterConceptTraits::iterator_category, IterConcept::iterator_category>); |
216 | static_assert(std::same_as<IterConceptTraits::value_type, IterConcept::value_type>); |
217 | static_assert(std::same_as<IterConceptTraits::difference_type, IterConcept::difference_type>); |
218 | static_assert(std::same_as<IterConceptTraits::reference, IterConcept::reference>); |
219 | static_assert(std::same_as<IterConceptTraits::pointer, IterConcept::pointer>); |
220 | static_assert(!has_iterator_concept_v<IterConceptTraits>); |
221 | |
222 | struct LegacyInput { |
223 | struct iterator_category {}; |
224 | struct value_type {}; |
225 | struct reference { operator value_type() const; }; |
226 | |
227 | friend bool operator==(LegacyInput, LegacyInput); |
228 | reference operator*() const; |
229 | LegacyInput& operator++(); |
230 | LegacyInput operator++(int); |
231 | }; |
232 | template <> |
233 | struct std::incrementable_traits<LegacyInput> { |
234 | using difference_type = short; |
235 | }; |
236 | using LegacyInputTraits = std::iterator_traits<LegacyInput>; |
237 | static_assert(std::same_as<LegacyInputTraits::iterator_category, LegacyInput::iterator_category>); |
238 | static_assert(std::same_as<LegacyInputTraits::value_type, LegacyInput::value_type>); |
239 | static_assert(std::same_as<LegacyInputTraits::difference_type, short>); |
240 | static_assert(std::same_as<LegacyInputTraits::reference, LegacyInput::reference>); |
241 | static_assert(std::same_as<LegacyInputTraits::pointer, void>); |
242 | static_assert(!has_iterator_concept_v<LegacyInputTraits>); |
243 | |
244 | struct LegacyInputNoValueType { |
245 | struct not_value_type {}; |
246 | using difference_type = int; // or any signed integral type |
247 | struct reference { operator not_value_type&() const; }; |
248 | |
249 | friend bool operator==(LegacyInputNoValueType, LegacyInputNoValueType); |
250 | reference operator*() const; |
251 | LegacyInputNoValueType& operator++(); |
252 | LegacyInputNoValueType operator++(int); |
253 | }; |
254 | template <> |
255 | struct std::indirectly_readable_traits<LegacyInputNoValueType> { |
256 | using value_type = LegacyInputNoValueType::not_value_type; |
257 | }; |
258 | using LegacyInputNoValueTypeTraits = std::iterator_traits<LegacyInputNoValueType>; |
259 | static_assert(std::same_as<LegacyInputNoValueTypeTraits::iterator_category, std::input_iterator_tag>); |
260 | static_assert(std::same_as<LegacyInputNoValueTypeTraits::value_type, LegacyInputNoValueType::not_value_type>); |
261 | static_assert(std::same_as<LegacyInputNoValueTypeTraits::difference_type, int>); |
262 | static_assert(std::same_as<LegacyInputNoValueTypeTraits::reference, LegacyInputNoValueType::reference>); |
263 | static_assert(std::same_as<LegacyInputNoValueTypeTraits::pointer, void>); |
264 | static_assert(!has_iterator_concept_v<LegacyInputNoValueTypeTraits>); |
265 | |
266 | struct LegacyForward { |
267 | struct not_value_type {}; |
268 | |
269 | friend bool operator==(LegacyForward, LegacyForward); |
270 | const not_value_type& operator*() const; |
271 | LegacyForward& operator++(); |
272 | LegacyForward operator++(int); |
273 | }; |
274 | template <> |
275 | struct std::indirectly_readable_traits<LegacyForward> { |
276 | using value_type = LegacyForward::not_value_type; |
277 | }; |
278 | template <> |
279 | struct std::incrementable_traits<LegacyForward> { |
280 | using difference_type = short; // or any signed integral type |
281 | }; |
282 | using LegacyForwardTraits = std::iterator_traits<LegacyForward>; |
283 | static_assert(std::same_as<LegacyForwardTraits::iterator_category, std::forward_iterator_tag>); |
284 | static_assert(std::same_as<LegacyForwardTraits::value_type, LegacyForward::not_value_type>); |
285 | static_assert(std::same_as<LegacyForwardTraits::difference_type, short>); |
286 | static_assert(std::same_as<LegacyForwardTraits::reference, const LegacyForward::not_value_type&>); |
287 | static_assert(std::same_as<LegacyForwardTraits::pointer, void>); |
288 | static_assert(!has_iterator_concept_v<LegacyForwardTraits>); |
289 | |
290 | struct LegacyBidirectional { |
291 | struct value_type {}; |
292 | |
293 | friend bool operator==(LegacyBidirectional, LegacyBidirectional); |
294 | const value_type& operator*() const; |
295 | LegacyBidirectional& operator++(); |
296 | LegacyBidirectional operator++(int); |
297 | LegacyBidirectional& operator--(); |
298 | LegacyBidirectional operator--(int); |
299 | friend short operator-(LegacyBidirectional, LegacyBidirectional); |
300 | }; |
301 | using LegacyBidirectionalTraits = std::iterator_traits<LegacyBidirectional>; |
302 | static_assert(std::same_as<LegacyBidirectionalTraits::iterator_category, std::bidirectional_iterator_tag>); |
303 | static_assert(std::same_as<LegacyBidirectionalTraits::value_type, LegacyBidirectional::value_type>); |
304 | static_assert(std::same_as<LegacyBidirectionalTraits::difference_type, short>); |
305 | static_assert(std::same_as<LegacyBidirectionalTraits::reference, const LegacyBidirectional::value_type&>); |
306 | static_assert(std::same_as<LegacyBidirectionalTraits::pointer, void>); |
307 | static_assert(!has_iterator_concept_v<LegacyBidirectionalTraits>); |
308 | |
309 | // Almost a random access iterator except it is missing operator-(It, It). |
310 | struct MinusNotDeclaredIter { |
311 | struct value_type {}; |
312 | |
313 | friend auto operator<=>(MinusNotDeclaredIter, MinusNotDeclaredIter) = default; |
314 | const value_type& operator*() const; |
315 | const value_type& operator[](long) const; |
316 | MinusNotDeclaredIter& operator++(); |
317 | MinusNotDeclaredIter operator++(int); |
318 | MinusNotDeclaredIter& operator--(); |
319 | MinusNotDeclaredIter operator--(int); |
320 | MinusNotDeclaredIter& operator+=(long); |
321 | MinusNotDeclaredIter& operator-=(long); |
322 | |
323 | // Providing difference_type does not fully compensate for missing operator-(It, It). |
324 | friend MinusNotDeclaredIter operator-(MinusNotDeclaredIter, int); |
325 | friend MinusNotDeclaredIter operator+(MinusNotDeclaredIter, int); |
326 | friend MinusNotDeclaredIter operator+(int, MinusNotDeclaredIter); |
327 | }; |
328 | template <> |
329 | struct std::incrementable_traits<MinusNotDeclaredIter> { |
330 | using difference_type = short; |
331 | }; |
332 | using MinusNotDeclaredIterTraits = std::iterator_traits<MinusNotDeclaredIter>; |
333 | static_assert(std::same_as<MinusNotDeclaredIterTraits::iterator_category, std::bidirectional_iterator_tag>); |
334 | static_assert(std::same_as<MinusNotDeclaredIterTraits::value_type, MinusNotDeclaredIter::value_type>); |
335 | static_assert(std::same_as<MinusNotDeclaredIterTraits::difference_type, short>); |
336 | static_assert(std::same_as<MinusNotDeclaredIterTraits::reference, const MinusNotDeclaredIter::value_type&>); |
337 | static_assert(std::same_as<MinusNotDeclaredIterTraits::pointer, void>); |
338 | static_assert(!has_iterator_concept_v<MinusNotDeclaredIterTraits>); |
339 | |
340 | struct WrongSubscriptReturnType { |
341 | struct value_type {}; |
342 | |
343 | friend auto operator<=>(WrongSubscriptReturnType, WrongSubscriptReturnType) = default; |
344 | |
345 | // The type of it[n] is not convertible to the type of *it; therefore, this is not random-access. |
346 | value_type& operator*() const; |
347 | const value_type& operator[](long) const; |
348 | WrongSubscriptReturnType& operator++(); |
349 | WrongSubscriptReturnType operator++(int); |
350 | WrongSubscriptReturnType& operator--(); |
351 | WrongSubscriptReturnType operator--(int); |
352 | WrongSubscriptReturnType& operator+=(long); |
353 | WrongSubscriptReturnType& operator-=(long); |
354 | friend short operator-(WrongSubscriptReturnType, WrongSubscriptReturnType); |
355 | friend WrongSubscriptReturnType operator-(WrongSubscriptReturnType, int); |
356 | friend WrongSubscriptReturnType operator+(WrongSubscriptReturnType, int); |
357 | friend WrongSubscriptReturnType operator+(int, WrongSubscriptReturnType); |
358 | }; |
359 | using WrongSubscriptReturnTypeTraits = std::iterator_traits<WrongSubscriptReturnType>; |
360 | static_assert(std::same_as<WrongSubscriptReturnTypeTraits::iterator_category, std::bidirectional_iterator_tag>); |
361 | static_assert(std::same_as<WrongSubscriptReturnTypeTraits::value_type, WrongSubscriptReturnType::value_type>); |
362 | static_assert(std::same_as<WrongSubscriptReturnTypeTraits::difference_type, short>); |
363 | static_assert(std::same_as<WrongSubscriptReturnTypeTraits::reference, WrongSubscriptReturnType::value_type&>); |
364 | static_assert(std::same_as<WrongSubscriptReturnTypeTraits::pointer, void>); |
365 | static_assert(!has_iterator_concept_v<WrongSubscriptReturnTypeTraits>); |
366 | |
367 | struct LegacyRandomAccess { |
368 | struct value_type {}; |
369 | |
370 | friend bool operator==(LegacyRandomAccess, LegacyRandomAccess); |
371 | friend bool operator<(LegacyRandomAccess, LegacyRandomAccess); |
372 | friend bool operator<=(LegacyRandomAccess, LegacyRandomAccess); |
373 | friend bool operator>(LegacyRandomAccess, LegacyRandomAccess); |
374 | friend bool operator>=(LegacyRandomAccess, LegacyRandomAccess); |
375 | const value_type& operator*() const; |
376 | const value_type& operator[](long) const; |
377 | LegacyRandomAccess& operator++(); |
378 | LegacyRandomAccess operator++(int); |
379 | LegacyRandomAccess& operator--(); |
380 | LegacyRandomAccess operator--(int); |
381 | LegacyRandomAccess& operator+=(long); |
382 | LegacyRandomAccess& operator-=(long); |
383 | friend short operator-(LegacyRandomAccess, LegacyRandomAccess); |
384 | friend LegacyRandomAccess operator-(LegacyRandomAccess, int); |
385 | friend LegacyRandomAccess operator+(LegacyRandomAccess, int); |
386 | friend LegacyRandomAccess operator+(int, LegacyRandomAccess); |
387 | }; |
388 | using LegacyRandomAccessTraits = std::iterator_traits<LegacyRandomAccess>; |
389 | static_assert(std::same_as<LegacyRandomAccessTraits::iterator_category, std::random_access_iterator_tag>); |
390 | static_assert(std::same_as<LegacyRandomAccessTraits::value_type, LegacyRandomAccess::value_type>); |
391 | static_assert(std::same_as<LegacyRandomAccessTraits::difference_type, short>); |
392 | static_assert(std::same_as<LegacyRandomAccessTraits::reference, const LegacyRandomAccess::value_type&>); |
393 | static_assert(std::same_as<LegacyRandomAccessTraits::pointer, void>); |
394 | static_assert(!has_iterator_concept_v<LegacyRandomAccessTraits>); |
395 | |
396 | struct LegacyRandomAccessSpaceship { |
397 | struct not_value_type {}; |
398 | struct ReferenceConvertible { operator not_value_type&() const; }; |
399 | |
400 | friend auto operator<=>(LegacyRandomAccessSpaceship, LegacyRandomAccessSpaceship) = default; |
401 | not_value_type& operator*() const; |
402 | ReferenceConvertible operator[](long) const; |
403 | LegacyRandomAccessSpaceship& operator++(); |
404 | LegacyRandomAccessSpaceship operator++(int); |
405 | LegacyRandomAccessSpaceship& operator--(); |
406 | LegacyRandomAccessSpaceship operator--(int); |
407 | LegacyRandomAccessSpaceship& operator+=(long); |
408 | LegacyRandomAccessSpaceship& operator-=(long); |
409 | friend short operator-(LegacyRandomAccessSpaceship, LegacyRandomAccessSpaceship); |
410 | friend LegacyRandomAccessSpaceship operator-(LegacyRandomAccessSpaceship, int); |
411 | friend LegacyRandomAccessSpaceship operator+(LegacyRandomAccessSpaceship, int); |
412 | friend LegacyRandomAccessSpaceship operator+(int, LegacyRandomAccessSpaceship); |
413 | }; |
414 | template <> |
415 | struct std::indirectly_readable_traits<LegacyRandomAccessSpaceship> { |
416 | using value_type = LegacyRandomAccessSpaceship::not_value_type; |
417 | }; |
418 | template <> |
419 | struct std::incrementable_traits<LegacyRandomAccessSpaceship> { |
420 | using difference_type = short; // or any signed integral type |
421 | }; |
422 | using LegacyRandomAccessSpaceshipTraits = std::iterator_traits<LegacyRandomAccessSpaceship>; |
423 | static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::iterator_category, std::random_access_iterator_tag>); |
424 | static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::value_type, LegacyRandomAccessSpaceship::not_value_type>); |
425 | static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::difference_type, short>); |
426 | static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::reference, LegacyRandomAccessSpaceship::not_value_type&>); |
427 | static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::pointer, void>); |
428 | static_assert(!has_iterator_concept_v<LegacyRandomAccessSpaceshipTraits>); |
429 | |
430 | // For output iterators, value_type, difference_type, and reference may be void. |
431 | struct BareLegacyOutput { |
432 | struct Empty {}; |
433 | Empty operator*() const; |
434 | BareLegacyOutput& operator++(); |
435 | BareLegacyOutput operator++(int); |
436 | }; |
437 | using BareLegacyOutputTraits = std::iterator_traits<BareLegacyOutput>; |
438 | static_assert(std::same_as<BareLegacyOutputTraits::iterator_category, std::output_iterator_tag>); |
439 | static_assert(std::same_as<BareLegacyOutputTraits::value_type, void>); |
440 | static_assert(std::same_as<BareLegacyOutputTraits::difference_type, void>); |
441 | static_assert(std::same_as<BareLegacyOutputTraits::reference, void>); |
442 | static_assert(std::same_as<BareLegacyOutputTraits::pointer, void>); |
443 | static_assert(!has_iterator_concept_v<BareLegacyOutputTraits>); |
444 | |
445 | // The operator- means we get difference_type. |
446 | struct LegacyOutputWithMinus { |
447 | struct Empty {}; |
448 | Empty operator*() const; |
449 | LegacyOutputWithMinus& operator++(); |
450 | LegacyOutputWithMinus operator++(int); |
451 | friend short operator-(LegacyOutputWithMinus, LegacyOutputWithMinus); |
452 | // Lacking operator==, this is a LegacyIterator but not a LegacyInputIterator. |
453 | }; |
454 | using LegacyOutputWithMinusTraits = std::iterator_traits<LegacyOutputWithMinus>; |
455 | static_assert(std::same_as<LegacyOutputWithMinusTraits::iterator_category, std::output_iterator_tag>); |
456 | static_assert(std::same_as<LegacyOutputWithMinusTraits::value_type, void>); |
457 | static_assert(std::same_as<LegacyOutputWithMinusTraits::difference_type, short>); |
458 | static_assert(std::same_as<LegacyOutputWithMinusTraits::reference, void>); |
459 | static_assert(std::same_as<LegacyOutputWithMinusTraits::pointer, void>); |
460 | static_assert(!has_iterator_concept_v<LegacyOutputWithMinusTraits>); |
461 | |
462 | struct LegacyOutputWithMemberTypes { |
463 | struct value_type {}; // ignored |
464 | struct reference {}; // ignored |
465 | using difference_type = long; |
466 | |
467 | friend bool operator==(LegacyOutputWithMemberTypes, LegacyOutputWithMemberTypes); |
468 | reference operator*() const; |
469 | LegacyOutputWithMemberTypes& operator++(); |
470 | LegacyOutputWithMemberTypes operator++(int); |
471 | friend short operator-(LegacyOutputWithMemberTypes, LegacyOutputWithMemberTypes); // ignored |
472 | // Since (*it) is not convertible to value_type, this is not a LegacyInputIterator. |
473 | }; |
474 | using LegacyOutputWithMemberTypesTraits = std::iterator_traits<LegacyOutputWithMemberTypes>; |
475 | static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::iterator_category, std::output_iterator_tag>); |
476 | static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::value_type, void>); |
477 | static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::difference_type, long>); |
478 | static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::reference, void>); |
479 | static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::pointer, void>); |
480 | static_assert(!has_iterator_concept_v<LegacyOutputWithMemberTypesTraits>); |
481 | |
482 | struct LegacyRandomAccessSpecialized { |
483 | struct not_value_type {}; |
484 | |
485 | friend auto operator<=>(LegacyRandomAccessSpecialized, LegacyRandomAccessSpecialized) = default; |
486 | not_value_type& operator*() const; |
487 | not_value_type& operator[](long) const; |
488 | LegacyRandomAccessSpecialized& operator++(); |
489 | LegacyRandomAccessSpecialized operator++(int); |
490 | LegacyRandomAccessSpecialized& operator--(); |
491 | LegacyRandomAccessSpecialized operator--(int); |
492 | LegacyRandomAccessSpecialized& operator+=(long); |
493 | LegacyRandomAccessSpecialized& operator-=(long); |
494 | friend long operator-(LegacyRandomAccessSpecialized, LegacyRandomAccessSpecialized); |
495 | friend LegacyRandomAccessSpecialized operator-(LegacyRandomAccessSpecialized, int); |
496 | friend LegacyRandomAccessSpecialized operator+(LegacyRandomAccessSpecialized, int); |
497 | friend LegacyRandomAccessSpecialized operator+(int, LegacyRandomAccessSpecialized); |
498 | }; |
499 | template <class I> |
500 | requires std::same_as<I, LegacyRandomAccessSpecialized> |
501 | struct std::iterator_traits<I> |
502 | { |
503 | using iterator_category = std::output_iterator_tag; |
504 | using value_type = short; |
505 | using difference_type = short; |
506 | using reference = short&; |
507 | using pointer = short*; |
508 | }; |
509 | using LegacyRandomAccessSpecializedTraits = std::iterator_traits<LegacyRandomAccessSpecialized>; |
510 | static_assert(std::same_as<LegacyRandomAccessSpecializedTraits::iterator_category, std::output_iterator_tag>); |
511 | static_assert(std::same_as<LegacyRandomAccessSpecializedTraits::value_type, short>); |
512 | static_assert(std::same_as<LegacyRandomAccessSpecializedTraits::difference_type, short>); |
513 | static_assert(std::same_as<LegacyRandomAccessSpecializedTraits::reference, short&>); |
514 | static_assert(std::same_as<LegacyRandomAccessSpecializedTraits::pointer, short*>); |
515 | static_assert(!has_iterator_concept_v<LegacyRandomAccessSpecializedTraits>); |
516 | |
517 | // Other test iterators. |
518 | |
519 | using InputTestIteratorTraits = std::iterator_traits<cpp17_input_iterator<int*>>; |
520 | static_assert(std::same_as<InputTestIteratorTraits::iterator_category, std::input_iterator_tag>); |
521 | static_assert(std::same_as<InputTestIteratorTraits::value_type, int>); |
522 | static_assert(std::same_as<InputTestIteratorTraits::difference_type, std::ptrdiff_t>); |
523 | static_assert(std::same_as<InputTestIteratorTraits::reference, int&>); |
524 | static_assert(std::same_as<InputTestIteratorTraits::pointer, int*>); |
525 | static_assert(!has_iterator_concept_v<InputTestIteratorTraits>); |
526 | |
527 | using OutputTestIteratorTraits = std::iterator_traits<cpp17_output_iterator<int*>>; |
528 | static_assert(std::same_as<OutputTestIteratorTraits::iterator_category, std::output_iterator_tag>); |
529 | static_assert(std::same_as<OutputTestIteratorTraits::value_type, void>); |
530 | static_assert(std::same_as<OutputTestIteratorTraits::difference_type, std::ptrdiff_t>); |
531 | static_assert(std::same_as<OutputTestIteratorTraits::reference, int&>); |
532 | static_assert(std::same_as<OutputTestIteratorTraits::pointer, int*>); |
533 | static_assert(!has_iterator_concept_v<OutputTestIteratorTraits>); |
534 | |
535 | using ForwardTestIteratorTraits = std::iterator_traits<forward_iterator<int*>>; |
536 | static_assert(std::same_as<ForwardTestIteratorTraits::iterator_category, std::forward_iterator_tag>); |
537 | static_assert(std::same_as<ForwardTestIteratorTraits::value_type, int>); |
538 | static_assert(std::same_as<ForwardTestIteratorTraits::difference_type, std::ptrdiff_t>); |
539 | static_assert(std::same_as<ForwardTestIteratorTraits::reference, int&>); |
540 | static_assert(std::same_as<ForwardTestIteratorTraits::pointer, int*>); |
541 | static_assert(!has_iterator_concept_v<ForwardTestIteratorTraits>); |
542 | |
543 | using BidirectionalTestIteratorTraits = std::iterator_traits<bidirectional_iterator<int*>>; |
544 | static_assert(std::same_as<BidirectionalTestIteratorTraits::iterator_category, std::bidirectional_iterator_tag>); |
545 | static_assert(std::same_as<BidirectionalTestIteratorTraits::value_type, int>); |
546 | static_assert(std::same_as<BidirectionalTestIteratorTraits::difference_type, std::ptrdiff_t>); |
547 | static_assert(std::same_as<BidirectionalTestIteratorTraits::reference, int&>); |
548 | static_assert(std::same_as<BidirectionalTestIteratorTraits::pointer, int*>); |
549 | static_assert(!has_iterator_concept_v<BidirectionalTestIteratorTraits>); |
550 | |
551 | using RandomAccessTestIteratorTraits = std::iterator_traits<random_access_iterator<int*>>; |
552 | static_assert(std::same_as<RandomAccessTestIteratorTraits::iterator_category, std::random_access_iterator_tag>); |
553 | static_assert(std::same_as<RandomAccessTestIteratorTraits::value_type, int>); |
554 | static_assert(std::same_as<RandomAccessTestIteratorTraits::difference_type, std::ptrdiff_t>); |
555 | static_assert(std::same_as<RandomAccessTestIteratorTraits::reference, int&>); |
556 | static_assert(std::same_as<RandomAccessTestIteratorTraits::pointer, int*>); |
557 | static_assert(!has_iterator_concept_v<RandomAccessTestIteratorTraits>); |
558 | |
559 | using ContiguousTestIteratorTraits = std::iterator_traits<contiguous_iterator<int*>>; |
560 | static_assert(std::same_as<ContiguousTestIteratorTraits::iterator_category, std::contiguous_iterator_tag>); |
561 | static_assert(std::same_as<ContiguousTestIteratorTraits::value_type, int>); |
562 | static_assert(std::same_as<ContiguousTestIteratorTraits::difference_type, std::ptrdiff_t>); |
563 | static_assert(std::same_as<ContiguousTestIteratorTraits::reference, int&>); |
564 | static_assert(std::same_as<ContiguousTestIteratorTraits::pointer, int*>); |
565 | static_assert(!has_iterator_concept_v<ContiguousTestIteratorTraits>); |
566 | |
567 | using Cpp17BasicIteratorTraits = std::iterator_traits<iterator_traits_cpp17_iterator>; |
568 | static_assert(std::same_as<Cpp17BasicIteratorTraits::iterator_category, std::output_iterator_tag>); |
569 | static_assert(std::same_as<Cpp17BasicIteratorTraits::value_type, void>); |
570 | static_assert(std::same_as<Cpp17BasicIteratorTraits::difference_type, void>); |
571 | static_assert(std::same_as<Cpp17BasicIteratorTraits::reference, void>); |
572 | static_assert(std::same_as<Cpp17BasicIteratorTraits::pointer, void>); |
573 | static_assert(!has_iterator_concept_v<Cpp17BasicIteratorTraits>); |
574 | |
575 | using Cpp17InputIteratorTraits = std::iterator_traits<iterator_traits_cpp17_input_iterator>; |
576 | static_assert(std::same_as<Cpp17InputIteratorTraits::iterator_category, std::input_iterator_tag>); |
577 | static_assert(std::same_as<Cpp17InputIteratorTraits::value_type, long>); |
578 | static_assert(std::same_as<Cpp17InputIteratorTraits::difference_type, int>); |
579 | static_assert(std::same_as<Cpp17InputIteratorTraits::reference, int&>); |
580 | static_assert(std::same_as<Cpp17InputIteratorTraits::pointer, void>); |
581 | static_assert(!has_iterator_concept_v<Cpp17InputIteratorTraits>); |
582 | |
583 | using Cpp17ForwardIteratorTraits = std::iterator_traits<iterator_traits_cpp17_forward_iterator>; |
584 | static_assert(std::same_as<Cpp17ForwardIteratorTraits::iterator_category, std::forward_iterator_tag>); |
585 | static_assert(std::same_as<Cpp17ForwardIteratorTraits::value_type, int>); |
586 | static_assert(std::same_as<Cpp17ForwardIteratorTraits::difference_type, int>); |
587 | static_assert(std::same_as<Cpp17ForwardIteratorTraits::reference, int&>); |
588 | static_assert(std::same_as<Cpp17ForwardIteratorTraits::pointer, void>); |
589 | static_assert(!has_iterator_concept_v<Cpp17ForwardIteratorTraits>); |
590 | |