1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 // UNSUPPORTED: libcpp-no-concepts
11 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
12
13 // Test iterator category and iterator concepts.
14
15 #include <ranges>
16 #include <cassert>
17
18 #include "test_macros.h"
19 #include "../types.h"
20
21 struct Decrementable {
22 using difference_type = int;
23
24 auto operator<=>(const Decrementable&) const = default;
25
26 constexpr Decrementable& operator++();
27 constexpr Decrementable operator++(int);
28 constexpr Decrementable& operator--();
29 constexpr Decrementable operator--(int);
30 };
31
32 struct Incrementable {
33 using difference_type = int;
34
35 auto operator<=>(const Incrementable&) const = default;
36
37 constexpr Incrementable& operator++();
38 constexpr Incrementable operator++(int);
39 };
40
41 struct BigType {
42 char buffer[128];
43
44 using difference_type = int;
45
46 auto operator<=>(const BigType&) const = default;
47
48 constexpr BigType& operator++();
49 constexpr BigType operator++(int);
50 };
51
52 struct CharDifferenceType {
53 using difference_type = signed char;
54
55 auto operator<=>(const CharDifferenceType&) const = default;
56
57 constexpr CharDifferenceType& operator++();
58 constexpr CharDifferenceType operator++(int);
59 };
60
61 template<class T>
62 concept HasIteratorCategory = requires { typename std::ranges::iterator_t<T>::iterator_category; };
63
test()64 void test() {
65 {
66 const std::ranges::iota_view<char> io(0);
67 using Iter = decltype(io.begin());
68 static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
69 static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
70 static_assert(std::same_as<Iter::value_type, char>);
71 static_assert(sizeof(Iter::difference_type) > sizeof(char));
72 static_assert(std::is_signed_v<Iter::difference_type>);
73 LIBCPP_STATIC_ASSERT(std::same_as<Iter::difference_type, int>);
74 }
75 {
76 const std::ranges::iota_view<short> io(0);
77 using Iter = decltype(io.begin());
78 static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
79 static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
80 static_assert(std::same_as<Iter::value_type, short>);
81 static_assert(sizeof(Iter::difference_type) > sizeof(short));
82 static_assert(std::is_signed_v<Iter::difference_type>);
83 LIBCPP_STATIC_ASSERT(std::same_as<Iter::difference_type, int>);
84 }
85 {
86 const std::ranges::iota_view<int> io(0);
87 using Iter = decltype(io.begin());
88 static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
89 static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
90 static_assert(std::same_as<Iter::value_type, int>);
91 static_assert(sizeof(Iter::difference_type) > sizeof(int));
92 static_assert(std::is_signed_v<Iter::difference_type>);
93 // If we're compiling for 32 bit or windows, int and long are the same size, so long long is the correct difference type.
94 #if INTPTR_MAX == INT32_MAX || defined(_WIN32)
95 LIBCPP_STATIC_ASSERT(std::same_as<Iter::difference_type, long long>);
96 #else
97 LIBCPP_STATIC_ASSERT(std::same_as<Iter::difference_type, long>);
98 #endif
99 }
100 {
101 const std::ranges::iota_view<long> io(0);
102 using Iter = decltype(io.begin());
103 static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
104 static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
105 static_assert(std::same_as<Iter::value_type, long>);
106 // Same as below, if there is no type larger than long, we can just use that.
107 static_assert(sizeof(Iter::difference_type) >= sizeof(long));
108 static_assert(std::is_signed_v<Iter::difference_type>);
109 LIBCPP_STATIC_ASSERT(std::same_as<Iter::difference_type, long long>);
110 }
111 {
112 const std::ranges::iota_view<long long> io(0);
113 using Iter = decltype(io.begin());
114 static_assert(std::same_as<Iter::iterator_concept, std::random_access_iterator_tag>);
115 static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
116 static_assert(std::same_as<Iter::value_type, long long>);
117 // No integer is larger than long long, so it is OK to use long long as the difference type here:
118 // https://eel.is/c++draft/range.iota.view#1.3
119 static_assert(sizeof(Iter::difference_type) >= sizeof(long long));
120 static_assert(std::is_signed_v<Iter::difference_type>);
121 LIBCPP_STATIC_ASSERT(std::same_as<Iter::difference_type, long long>);
122 }
123 {
124 const std::ranges::iota_view<Decrementable> io;
125 using Iter = decltype(io.begin());
126 static_assert(std::same_as<Iter::iterator_concept, std::bidirectional_iterator_tag>);
127 static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
128 static_assert(std::same_as<Iter::value_type, Decrementable>);
129 static_assert(std::same_as<Iter::difference_type, int>);
130 }
131 {
132 const std::ranges::iota_view<Incrementable> io;
133 using Iter = decltype(io.begin());
134 static_assert(std::same_as<Iter::iterator_concept, std::forward_iterator_tag>);
135 static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
136 static_assert(std::same_as<Iter::value_type, Incrementable>);
137 static_assert(std::same_as<Iter::difference_type, int>);
138 }
139 {
140 const std::ranges::iota_view<NotIncrementable> io(NotIncrementable(0));
141 using Iter = decltype(io.begin());
142 static_assert(std::same_as<Iter::iterator_concept, std::input_iterator_tag>);
143 static_assert(!HasIteratorCategory<std::ranges::iota_view<NotIncrementable>>);
144 static_assert(std::same_as<Iter::value_type, NotIncrementable>);
145 static_assert(std::same_as<Iter::difference_type, int>);
146 }
147 {
148 const std::ranges::iota_view<BigType> io;
149 using Iter = decltype(io.begin());
150 static_assert(std::same_as<Iter::iterator_concept, std::forward_iterator_tag>);
151 static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
152 static_assert(std::same_as<Iter::value_type, BigType>);
153 static_assert(std::same_as<Iter::difference_type, int>);
154 }
155 {
156 const std::ranges::iota_view<CharDifferenceType> io;
157 using Iter = decltype(io.begin());
158 static_assert(std::same_as<Iter::iterator_concept, std::forward_iterator_tag>);
159 static_assert(std::same_as<Iter::iterator_category, std::input_iterator_tag>);
160 static_assert(std::same_as<Iter::value_type, CharDifferenceType>);
161 static_assert(std::same_as<Iter::difference_type, signed char>);
162 }
163 }
164