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
50template <class Traits>
51constexpr bool has_iterator_concept_v = requires {
52 typename Traits::iterator_concept;
53};
54
55template <class Iter, class Category, class ValueType, class DiffType, class RefType, class PtrType>
56constexpr 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
72template <class Iter, class Category>
73constexpr bool testIOIterator() {
74 return test<Iter, Category, void, std::ptrdiff_t, void, void>();
75}
76
77template <class Iter, class Category, class ValueType>
78constexpr bool testConst() {
79 return test<Iter, Category, ValueType, std::ptrdiff_t, const ValueType&, const ValueType*>();
80}
81
82template <class Iter, class Category, class ValueType>
83constexpr 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//
93static_assert(testMutable<std::array<int, 10>::iterator, std::random_access_iterator_tag, int>());
94static_assert(testConst<std::array<int, 10>::const_iterator, std::random_access_iterator_tag, int>());
95static_assert(testMutable<std::string::iterator, std::random_access_iterator_tag, char>());
96static_assert(testConst<std::string::const_iterator, std::random_access_iterator_tag, char>());
97static_assert(testConst<std::string_view::iterator, std::random_access_iterator_tag, char>());
98static_assert(testConst<std::string_view::const_iterator, std::random_access_iterator_tag, char>());
99static_assert(testMutable<std::vector<int>::iterator, std::random_access_iterator_tag, int>());
100static_assert(testConst<std::vector<int>::const_iterator, std::random_access_iterator_tag, int>());
101
102static_assert(testMutable<std::deque<int>::iterator, std::random_access_iterator_tag, int>());
103static_assert(testConst<std::deque<int>::const_iterator, std::random_access_iterator_tag, int>());
104static_assert(testMutable<std::forward_list<int>::iterator, std::forward_iterator_tag, int>());
105static_assert(testConst<std::forward_list<int>::const_iterator, std::forward_iterator_tag, int>());
106static_assert(testMutable<std::list<int>::iterator, std::bidirectional_iterator_tag, int>());
107static_assert(testConst<std::list<int>::const_iterator, std::bidirectional_iterator_tag, int>());
108
109static_assert(testMutable<std::map<int, int>::iterator, std::bidirectional_iterator_tag, std::pair<const int, int>>());
110static_assert(testConst<std::map<int, int>::const_iterator, std::bidirectional_iterator_tag, std::pair<const int, int>>());
111static_assert(testMutable<std::multimap<int, int>::iterator, std::bidirectional_iterator_tag, std::pair<const int, int>>());
112static_assert(testConst<std::multimap<int, int>::const_iterator, std::bidirectional_iterator_tag, std::pair<const int, int>>());
113
114static_assert(testConst<std::set<int>::iterator, std::bidirectional_iterator_tag, int>());
115static_assert(testConst<std::set<int>::const_iterator, std::bidirectional_iterator_tag, int>());
116static_assert(testConst<std::multiset<int>::iterator, std::bidirectional_iterator_tag, int>());
117static_assert(testConst<std::multiset<int>::const_iterator, std::bidirectional_iterator_tag, int>());
118
119#ifdef _MSVC_STL_VERSION
120using unordered_iterator_category = std::bidirectional_iterator_tag;
121#else // ^^^ MSVC STL / other vvv
122using unordered_iterator_category = std::forward_iterator_tag;
123#endif // _MSVC_STL_VERSION
124
125static_assert(testMutable<std::unordered_map<int, int>::iterator, unordered_iterator_category, std::pair<const int, int>>());
126static_assert(testConst<std::unordered_map<int, int>::const_iterator, unordered_iterator_category, std::pair<const int, int>>());
127static_assert(testMutable<std::unordered_map<int, int>::local_iterator, unordered_iterator_category, std::pair<const int, int>>());
128static_assert(testConst<std::unordered_map<int, int>::const_local_iterator, unordered_iterator_category, std::pair<const int, int>>());
129static_assert(testMutable<std::unordered_multimap<int, int>::iterator, unordered_iterator_category, std::pair<const int, int>>());
130static_assert(testConst<std::unordered_multimap<int, int>::const_iterator, unordered_iterator_category, std::pair<const int, int>>());
131static_assert(testMutable<std::unordered_multimap<int, int>::local_iterator, unordered_iterator_category, std::pair<const int, int>>());
132static_assert(testConst<std::unordered_multimap<int, int>::const_local_iterator, unordered_iterator_category, std::pair<const int, int>>());
133
134static_assert(testConst<std::unordered_set<int>::iterator, unordered_iterator_category, int>());
135static_assert(testConst<std::unordered_set<int>::const_iterator, unordered_iterator_category, int>());
136static_assert(testConst<std::unordered_set<int>::local_iterator, unordered_iterator_category, int>());
137static_assert(testConst<std::unordered_set<int>::const_local_iterator, unordered_iterator_category, int>());
138static_assert(testConst<std::unordered_multiset<int>::iterator, unordered_iterator_category, int>());
139static_assert(testConst<std::unordered_multiset<int>::const_iterator, unordered_iterator_category, int>());
140static_assert(testConst<std::unordered_multiset<int>::local_iterator, unordered_iterator_category, int>());
141static_assert(testConst<std::unordered_multiset<int>::const_local_iterator, unordered_iterator_category, int>());
142
143static_assert(testMutable<std::reverse_iterator<int*>, std::random_access_iterator_tag, int>());
144static_assert(testIOIterator<std::back_insert_iterator<std::vector<int>>, std::output_iterator_tag>());
145static_assert(testIOIterator<std::front_insert_iterator<std::vector<int>>, std::output_iterator_tag>());
146static_assert(testIOIterator<std::insert_iterator<std::vector<int>>, std::output_iterator_tag>());
147static_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*
151static_assert(test<std::istreambuf_iterator<char>,
152 std::input_iterator_tag,
153 char,
154 std::streamoff,
155 char,
156 std::istreambuf_iterator<char>::pointer>());
157static_assert(test<std::move_iterator<int*>, std::random_access_iterator_tag, int, std::ptrdiff_t, int&&, int*>());
158static_assert(testIOIterator<std::ostream_iterator<int, char>, std::output_iterator_tag>());
159static_assert(testIOIterator<std::ostreambuf_iterator<int, char>, std::output_iterator_tag>());
160static_assert(testConst<std::cregex_iterator, std::forward_iterator_tag, std::cmatch>());
161static_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
165static_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*>());
167static_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
174struct AllMembers {
175 struct iterator_category {};
176 struct value_type {};
177 struct difference_type {};
178 struct reference {};
179 struct pointer {};
180};
181using AllMembersTraits = std::iterator_traits<AllMembers>;
182static_assert(std::same_as<AllMembersTraits::iterator_category, AllMembers::iterator_category>);
183static_assert(std::same_as<AllMembersTraits::value_type, AllMembers::value_type>);
184static_assert(std::same_as<AllMembersTraits::difference_type, AllMembers::difference_type>);
185static_assert(std::same_as<AllMembersTraits::reference, AllMembers::reference>);
186static_assert(std::same_as<AllMembersTraits::pointer, AllMembers::pointer>);
187static_assert(!has_iterator_concept_v<AllMembersTraits>);
188
189struct 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};
197using NoPointerMemberTraits = std::iterator_traits<NoPointerMember>;
198static_assert(std::same_as<NoPointerMemberTraits::iterator_category, NoPointerMember::iterator_category>);
199static_assert(std::same_as<NoPointerMemberTraits::value_type, NoPointerMember::value_type>);
200static_assert(std::same_as<NoPointerMemberTraits::difference_type, NoPointerMember::difference_type>);
201static_assert(std::same_as<NoPointerMemberTraits::reference, NoPointerMember::reference>);
202static_assert(std::same_as<NoPointerMemberTraits::pointer, void>);
203static_assert(!has_iterator_concept_v<NoPointerMemberTraits>);
204
205struct 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};
214using IterConceptTraits = std::iterator_traits<IterConcept>;
215static_assert(std::same_as<IterConceptTraits::iterator_category, IterConcept::iterator_category>);
216static_assert(std::same_as<IterConceptTraits::value_type, IterConcept::value_type>);
217static_assert(std::same_as<IterConceptTraits::difference_type, IterConcept::difference_type>);
218static_assert(std::same_as<IterConceptTraits::reference, IterConcept::reference>);
219static_assert(std::same_as<IterConceptTraits::pointer, IterConcept::pointer>);
220static_assert(!has_iterator_concept_v<IterConceptTraits>);
221
222struct 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};
232template <>
233struct std::incrementable_traits<LegacyInput> {
234 using difference_type = short;
235};
236using LegacyInputTraits = std::iterator_traits<LegacyInput>;
237static_assert(std::same_as<LegacyInputTraits::iterator_category, LegacyInput::iterator_category>);
238static_assert(std::same_as<LegacyInputTraits::value_type, LegacyInput::value_type>);
239static_assert(std::same_as<LegacyInputTraits::difference_type, short>);
240static_assert(std::same_as<LegacyInputTraits::reference, LegacyInput::reference>);
241static_assert(std::same_as<LegacyInputTraits::pointer, void>);
242static_assert(!has_iterator_concept_v<LegacyInputTraits>);
243
244struct 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};
254template <>
255struct std::indirectly_readable_traits<LegacyInputNoValueType> {
256 using value_type = LegacyInputNoValueType::not_value_type;
257};
258using LegacyInputNoValueTypeTraits = std::iterator_traits<LegacyInputNoValueType>;
259static_assert(std::same_as<LegacyInputNoValueTypeTraits::iterator_category, std::input_iterator_tag>);
260static_assert(std::same_as<LegacyInputNoValueTypeTraits::value_type, LegacyInputNoValueType::not_value_type>);
261static_assert(std::same_as<LegacyInputNoValueTypeTraits::difference_type, int>);
262static_assert(std::same_as<LegacyInputNoValueTypeTraits::reference, LegacyInputNoValueType::reference>);
263static_assert(std::same_as<LegacyInputNoValueTypeTraits::pointer, void>);
264static_assert(!has_iterator_concept_v<LegacyInputNoValueTypeTraits>);
265
266struct 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};
274template <>
275struct std::indirectly_readable_traits<LegacyForward> {
276 using value_type = LegacyForward::not_value_type;
277};
278template <>
279struct std::incrementable_traits<LegacyForward> {
280 using difference_type = short; // or any signed integral type
281};
282using LegacyForwardTraits = std::iterator_traits<LegacyForward>;
283static_assert(std::same_as<LegacyForwardTraits::iterator_category, std::forward_iterator_tag>);
284static_assert(std::same_as<LegacyForwardTraits::value_type, LegacyForward::not_value_type>);
285static_assert(std::same_as<LegacyForwardTraits::difference_type, short>);
286static_assert(std::same_as<LegacyForwardTraits::reference, const LegacyForward::not_value_type&>);
287static_assert(std::same_as<LegacyForwardTraits::pointer, void>);
288static_assert(!has_iterator_concept_v<LegacyForwardTraits>);
289
290struct 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};
301using LegacyBidirectionalTraits = std::iterator_traits<LegacyBidirectional>;
302static_assert(std::same_as<LegacyBidirectionalTraits::iterator_category, std::bidirectional_iterator_tag>);
303static_assert(std::same_as<LegacyBidirectionalTraits::value_type, LegacyBidirectional::value_type>);
304static_assert(std::same_as<LegacyBidirectionalTraits::difference_type, short>);
305static_assert(std::same_as<LegacyBidirectionalTraits::reference, const LegacyBidirectional::value_type&>);
306static_assert(std::same_as<LegacyBidirectionalTraits::pointer, void>);
307static_assert(!has_iterator_concept_v<LegacyBidirectionalTraits>);
308
309// Almost a random access iterator except it is missing operator-(It, It).
310struct 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};
328template <>
329struct std::incrementable_traits<MinusNotDeclaredIter> {
330 using difference_type = short;
331};
332using MinusNotDeclaredIterTraits = std::iterator_traits<MinusNotDeclaredIter>;
333static_assert(std::same_as<MinusNotDeclaredIterTraits::iterator_category, std::bidirectional_iterator_tag>);
334static_assert(std::same_as<MinusNotDeclaredIterTraits::value_type, MinusNotDeclaredIter::value_type>);
335static_assert(std::same_as<MinusNotDeclaredIterTraits::difference_type, short>);
336static_assert(std::same_as<MinusNotDeclaredIterTraits::reference, const MinusNotDeclaredIter::value_type&>);
337static_assert(std::same_as<MinusNotDeclaredIterTraits::pointer, void>);
338static_assert(!has_iterator_concept_v<MinusNotDeclaredIterTraits>);
339
340struct 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};
359using WrongSubscriptReturnTypeTraits = std::iterator_traits<WrongSubscriptReturnType>;
360static_assert(std::same_as<WrongSubscriptReturnTypeTraits::iterator_category, std::bidirectional_iterator_tag>);
361static_assert(std::same_as<WrongSubscriptReturnTypeTraits::value_type, WrongSubscriptReturnType::value_type>);
362static_assert(std::same_as<WrongSubscriptReturnTypeTraits::difference_type, short>);
363static_assert(std::same_as<WrongSubscriptReturnTypeTraits::reference, WrongSubscriptReturnType::value_type&>);
364static_assert(std::same_as<WrongSubscriptReturnTypeTraits::pointer, void>);
365static_assert(!has_iterator_concept_v<WrongSubscriptReturnTypeTraits>);
366
367struct 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};
388using LegacyRandomAccessTraits = std::iterator_traits<LegacyRandomAccess>;
389static_assert(std::same_as<LegacyRandomAccessTraits::iterator_category, std::random_access_iterator_tag>);
390static_assert(std::same_as<LegacyRandomAccessTraits::value_type, LegacyRandomAccess::value_type>);
391static_assert(std::same_as<LegacyRandomAccessTraits::difference_type, short>);
392static_assert(std::same_as<LegacyRandomAccessTraits::reference, const LegacyRandomAccess::value_type&>);
393static_assert(std::same_as<LegacyRandomAccessTraits::pointer, void>);
394static_assert(!has_iterator_concept_v<LegacyRandomAccessTraits>);
395
396struct 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};
414template <>
415struct std::indirectly_readable_traits<LegacyRandomAccessSpaceship> {
416 using value_type = LegacyRandomAccessSpaceship::not_value_type;
417};
418template <>
419struct std::incrementable_traits<LegacyRandomAccessSpaceship> {
420 using difference_type = short; // or any signed integral type
421};
422using LegacyRandomAccessSpaceshipTraits = std::iterator_traits<LegacyRandomAccessSpaceship>;
423static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::iterator_category, std::random_access_iterator_tag>);
424static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::value_type, LegacyRandomAccessSpaceship::not_value_type>);
425static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::difference_type, short>);
426static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::reference, LegacyRandomAccessSpaceship::not_value_type&>);
427static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::pointer, void>);
428static_assert(!has_iterator_concept_v<LegacyRandomAccessSpaceshipTraits>);
429
430// For output iterators, value_type, difference_type, and reference may be void.
431struct BareLegacyOutput {
432 struct Empty {};
433 Empty operator*() const;
434 BareLegacyOutput& operator++();
435 BareLegacyOutput operator++(int);
436};
437using BareLegacyOutputTraits = std::iterator_traits<BareLegacyOutput>;
438static_assert(std::same_as<BareLegacyOutputTraits::iterator_category, std::output_iterator_tag>);
439static_assert(std::same_as<BareLegacyOutputTraits::value_type, void>);
440static_assert(std::same_as<BareLegacyOutputTraits::difference_type, void>);
441static_assert(std::same_as<BareLegacyOutputTraits::reference, void>);
442static_assert(std::same_as<BareLegacyOutputTraits::pointer, void>);
443static_assert(!has_iterator_concept_v<BareLegacyOutputTraits>);
444
445// The operator- means we get difference_type.
446struct 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};
454using LegacyOutputWithMinusTraits = std::iterator_traits<LegacyOutputWithMinus>;
455static_assert(std::same_as<LegacyOutputWithMinusTraits::iterator_category, std::output_iterator_tag>);
456static_assert(std::same_as<LegacyOutputWithMinusTraits::value_type, void>);
457static_assert(std::same_as<LegacyOutputWithMinusTraits::difference_type, short>);
458static_assert(std::same_as<LegacyOutputWithMinusTraits::reference, void>);
459static_assert(std::same_as<LegacyOutputWithMinusTraits::pointer, void>);
460static_assert(!has_iterator_concept_v<LegacyOutputWithMinusTraits>);
461
462struct 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};
474using LegacyOutputWithMemberTypesTraits = std::iterator_traits<LegacyOutputWithMemberTypes>;
475static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::iterator_category, std::output_iterator_tag>);
476static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::value_type, void>);
477static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::difference_type, long>);
478static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::reference, void>);
479static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::pointer, void>);
480static_assert(!has_iterator_concept_v<LegacyOutputWithMemberTypesTraits>);
481
482struct 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};
499template <class I>
500 requires std::same_as<I, LegacyRandomAccessSpecialized>
501struct 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};
509using LegacyRandomAccessSpecializedTraits = std::iterator_traits<LegacyRandomAccessSpecialized>;
510static_assert(std::same_as<LegacyRandomAccessSpecializedTraits::iterator_category, std::output_iterator_tag>);
511static_assert(std::same_as<LegacyRandomAccessSpecializedTraits::value_type, short>);
512static_assert(std::same_as<LegacyRandomAccessSpecializedTraits::difference_type, short>);
513static_assert(std::same_as<LegacyRandomAccessSpecializedTraits::reference, short&>);
514static_assert(std::same_as<LegacyRandomAccessSpecializedTraits::pointer, short*>);
515static_assert(!has_iterator_concept_v<LegacyRandomAccessSpecializedTraits>);
516
517// Other test iterators.
518
519using InputTestIteratorTraits = std::iterator_traits<cpp17_input_iterator<int*>>;
520static_assert(std::same_as<InputTestIteratorTraits::iterator_category, std::input_iterator_tag>);
521static_assert(std::same_as<InputTestIteratorTraits::value_type, int>);
522static_assert(std::same_as<InputTestIteratorTraits::difference_type, std::ptrdiff_t>);
523static_assert(std::same_as<InputTestIteratorTraits::reference, int&>);
524static_assert(std::same_as<InputTestIteratorTraits::pointer, int*>);
525static_assert(!has_iterator_concept_v<InputTestIteratorTraits>);
526
527using OutputTestIteratorTraits = std::iterator_traits<cpp17_output_iterator<int*>>;
528static_assert(std::same_as<OutputTestIteratorTraits::iterator_category, std::output_iterator_tag>);
529static_assert(std::same_as<OutputTestIteratorTraits::value_type, void>);
530static_assert(std::same_as<OutputTestIteratorTraits::difference_type, std::ptrdiff_t>);
531static_assert(std::same_as<OutputTestIteratorTraits::reference, int&>);
532static_assert(std::same_as<OutputTestIteratorTraits::pointer, int*>);
533static_assert(!has_iterator_concept_v<OutputTestIteratorTraits>);
534
535using ForwardTestIteratorTraits = std::iterator_traits<forward_iterator<int*>>;
536static_assert(std::same_as<ForwardTestIteratorTraits::iterator_category, std::forward_iterator_tag>);
537static_assert(std::same_as<ForwardTestIteratorTraits::value_type, int>);
538static_assert(std::same_as<ForwardTestIteratorTraits::difference_type, std::ptrdiff_t>);
539static_assert(std::same_as<ForwardTestIteratorTraits::reference, int&>);
540static_assert(std::same_as<ForwardTestIteratorTraits::pointer, int*>);
541static_assert(!has_iterator_concept_v<ForwardTestIteratorTraits>);
542
543using BidirectionalTestIteratorTraits = std::iterator_traits<bidirectional_iterator<int*>>;
544static_assert(std::same_as<BidirectionalTestIteratorTraits::iterator_category, std::bidirectional_iterator_tag>);
545static_assert(std::same_as<BidirectionalTestIteratorTraits::value_type, int>);
546static_assert(std::same_as<BidirectionalTestIteratorTraits::difference_type, std::ptrdiff_t>);
547static_assert(std::same_as<BidirectionalTestIteratorTraits::reference, int&>);
548static_assert(std::same_as<BidirectionalTestIteratorTraits::pointer, int*>);
549static_assert(!has_iterator_concept_v<BidirectionalTestIteratorTraits>);
550
551using RandomAccessTestIteratorTraits = std::iterator_traits<random_access_iterator<int*>>;
552static_assert(std::same_as<RandomAccessTestIteratorTraits::iterator_category, std::random_access_iterator_tag>);
553static_assert(std::same_as<RandomAccessTestIteratorTraits::value_type, int>);
554static_assert(std::same_as<RandomAccessTestIteratorTraits::difference_type, std::ptrdiff_t>);
555static_assert(std::same_as<RandomAccessTestIteratorTraits::reference, int&>);
556static_assert(std::same_as<RandomAccessTestIteratorTraits::pointer, int*>);
557static_assert(!has_iterator_concept_v<RandomAccessTestIteratorTraits>);
558
559using ContiguousTestIteratorTraits = std::iterator_traits<contiguous_iterator<int*>>;
560static_assert(std::same_as<ContiguousTestIteratorTraits::iterator_category, std::contiguous_iterator_tag>);
561static_assert(std::same_as<ContiguousTestIteratorTraits::value_type, int>);
562static_assert(std::same_as<ContiguousTestIteratorTraits::difference_type, std::ptrdiff_t>);
563static_assert(std::same_as<ContiguousTestIteratorTraits::reference, int&>);
564static_assert(std::same_as<ContiguousTestIteratorTraits::pointer, int*>);
565static_assert(!has_iterator_concept_v<ContiguousTestIteratorTraits>);
566
567using Cpp17BasicIteratorTraits = std::iterator_traits<iterator_traits_cpp17_iterator>;
568static_assert(std::same_as<Cpp17BasicIteratorTraits::iterator_category, std::output_iterator_tag>);
569static_assert(std::same_as<Cpp17BasicIteratorTraits::value_type, void>);
570static_assert(std::same_as<Cpp17BasicIteratorTraits::difference_type, void>);
571static_assert(std::same_as<Cpp17BasicIteratorTraits::reference, void>);
572static_assert(std::same_as<Cpp17BasicIteratorTraits::pointer, void>);
573static_assert(!has_iterator_concept_v<Cpp17BasicIteratorTraits>);
574
575using Cpp17InputIteratorTraits = std::iterator_traits<iterator_traits_cpp17_input_iterator>;
576static_assert(std::same_as<Cpp17InputIteratorTraits::iterator_category, std::input_iterator_tag>);
577static_assert(std::same_as<Cpp17InputIteratorTraits::value_type, long>);
578static_assert(std::same_as<Cpp17InputIteratorTraits::difference_type, int>);
579static_assert(std::same_as<Cpp17InputIteratorTraits::reference, int&>);
580static_assert(std::same_as<Cpp17InputIteratorTraits::pointer, void>);
581static_assert(!has_iterator_concept_v<Cpp17InputIteratorTraits>);
582
583using Cpp17ForwardIteratorTraits = std::iterator_traits<iterator_traits_cpp17_forward_iterator>;
584static_assert(std::same_as<Cpp17ForwardIteratorTraits::iterator_category, std::forward_iterator_tag>);
585static_assert(std::same_as<Cpp17ForwardIteratorTraits::value_type, int>);
586static_assert(std::same_as<Cpp17ForwardIteratorTraits::difference_type, int>);
587static_assert(std::same_as<Cpp17ForwardIteratorTraits::reference, int&>);
588static_assert(std::same_as<Cpp17ForwardIteratorTraits::pointer, void>);
589static_assert(!has_iterator_concept_v<Cpp17ForwardIteratorTraits>);
590

source code of libcxx/test/std/iterators/iterator.primitives/iterator.traits/cxx20_iterator_traits.compile.pass.cpp