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 #ifndef ALMOST_SATISFIES_TYPES_H
10 #define ALMOST_SATISFIES_TYPES_H
11 
12 #include <functional>
13 #include <iterator>
14 #include <ranges>
15 
16 #include "test_iterators.h"
17 
18 template <class T, class U = sentinel_wrapper<T>>
19 class UncheckedRange {
20 public:
21   T begin();
22   U end();
23 };
24 
25 static_assert(std::ranges::contiguous_range<UncheckedRange<int*, int*>>);
26 
27 // almost an input_iterator
28 class InputIteratorNotDerivedFrom {
29 public:
30   using difference_type = long;
31   using value_type = int;
32   using iterator_category = void;
33 
34   InputIteratorNotDerivedFrom& operator++();
35   void operator++(int);
36   const int& operator*() const;
37 };
38 
39 using InputRangeNotDerivedFrom = UncheckedRange<InputIteratorNotDerivedFrom>;
40 
41 static_assert(std::input_or_output_iterator<InputIteratorNotDerivedFrom>);
42 static_assert(std::indirectly_readable<InputIteratorNotDerivedFrom>);
43 static_assert(!std::input_iterator<InputIteratorNotDerivedFrom>);
44 static_assert(!std::ranges::input_range<InputRangeNotDerivedFrom>);
45 
46 class InputIteratorNotIndirectlyReadable {
47 public:
48   using difference_type = long;
49   using iterator_category = std::input_iterator_tag;
50 
51   InputIteratorNotIndirectlyReadable& operator++();
52   void operator++(int);
53   const int& operator*() const;
54 };
55 
56 using InputRangeNotIndirectlyReadable = UncheckedRange<InputIteratorNotIndirectlyReadable>;
57 
58 static_assert(std::input_or_output_iterator<InputIteratorNotIndirectlyReadable>);
59 static_assert(!std::indirectly_readable<InputIteratorNotIndirectlyReadable>);
60 static_assert(!std::input_iterator<InputIteratorNotIndirectlyReadable>);
61 static_assert(!std::ranges::input_range<InputIteratorNotIndirectlyReadable>);
62 
63 class InputIteratorNotInputOrOutputIterator {
64 public:
65   using difference_type = long;
66   using value_type = int;
67   using iterator_category = std::input_iterator_tag;
68 
69   int& operator++();
70   void operator++(int);
71   const int& operator*() const;
72 };
73 
74 using InputRangeNotInputOrOutputIterator = UncheckedRange<InputIteratorNotInputOrOutputIterator>;
75 
76 static_assert(!std::input_or_output_iterator<InputIteratorNotInputOrOutputIterator>);
77 static_assert(std::indirectly_readable<InputIteratorNotInputOrOutputIterator>);
78 static_assert(!std::input_iterator<InputIteratorNotInputOrOutputIterator>);
79 static_assert(!std::ranges::input_range<InputRangeNotInputOrOutputIterator>);
80 
81 // almost an indirect_unary_predicate
82 class IndirectUnaryPredicateNotCopyConstructible {
83 public:
84   IndirectUnaryPredicateNotCopyConstructible(const IndirectUnaryPredicateNotCopyConstructible&) = delete;
85   bool operator()(int) const;
86 };
87 
88 static_assert(std::predicate<IndirectUnaryPredicateNotCopyConstructible, int&>);
89 static_assert(!std::indirect_unary_predicate<IndirectUnaryPredicateNotCopyConstructible, int*>);
90 
91 class IndirectUnaryPredicateNotPredicate {
92 public:
93   bool operator()(int&&) const;
94 };
95 
96 static_assert(!std::predicate<IndirectUnaryPredicateNotPredicate, int&>);
97 static_assert(!std::indirect_unary_predicate<IndirectUnaryPredicateNotPredicate, int*>);
98 
99 // almost a sentinel_for cpp20_input_iterator
100 class SentinelForNotSemiregular {
101 public:
102   SentinelForNotSemiregular() = delete;
103   using difference_type = long;
104   SentinelForNotSemiregular& operator++();
105   void operator++(int);
106   const int& operator*() const;
107   friend bool operator==(const SentinelForNotSemiregular&, const cpp20_input_iterator<int*>&);
108 };
109 
110 using InputRangeNotSentinelSemiregular = UncheckedRange<cpp20_input_iterator<int*>, SentinelForNotSemiregular>;
111 using OutputRangeNotSentinelSemiregular = UncheckedRange<cpp20_output_iterator<int*>, SentinelForNotSemiregular>;
112 
113 static_assert(std::input_or_output_iterator<SentinelForNotSemiregular>);
114 static_assert(!std::semiregular<SentinelForNotSemiregular>);
115 static_assert(!std::sentinel_for<SentinelForNotSemiregular, cpp20_input_iterator<int*>>);
116 
117 // almost a sentinel_for cpp20_input_iterator
118 class SentinelForNotWeaklyEqualityComparableWith {
119 public:
120   using difference_type = long;
121   SentinelForNotWeaklyEqualityComparableWith& operator++();
122   void operator++(int);
123   const int& operator*() const;
124 };
125 
126 using InputRangeNotSentinelEqualityComparableWith =
127   UncheckedRange<cpp20_input_iterator<int*>, SentinelForNotWeaklyEqualityComparableWith>;
128 using OutputRangeNotSentinelEqualityComparableWith =
129   UncheckedRange<cpp20_output_iterator<int*>, SentinelForNotWeaklyEqualityComparableWith>;
130 
131 static_assert(std::input_or_output_iterator<SentinelForNotWeaklyEqualityComparableWith>);
132 static_assert(std::semiregular<SentinelForNotWeaklyEqualityComparableWith>);
133 static_assert(!std::sentinel_for<SentinelForNotWeaklyEqualityComparableWith, cpp20_input_iterator<int*>>);
134 
135 class WeaklyIncrementableNotMovable {
136 public:
137   using difference_type = long;
138   WeaklyIncrementableNotMovable& operator++();
139   void operator++(int);
140   WeaklyIncrementableNotMovable(const WeaklyIncrementableNotMovable&) = delete;
141 };
142 
143 static_assert(!std::movable<WeaklyIncrementableNotMovable>);
144 static_assert(!std::weakly_incrementable<WeaklyIncrementableNotMovable>);
145 
146 // almost a forward_iterator
147 class ForwardIteratorNotDerivedFrom {
148 public:
149   using difference_type = long;
150   using value_type = int;
151   using iterator_category = std::input_iterator_tag;
152 
153   ForwardIteratorNotDerivedFrom& operator++();
154   ForwardIteratorNotDerivedFrom operator++(int);
155   const int& operator*() const;
156   bool operator==(const ForwardIteratorNotDerivedFrom&) const = default;
157 };
158 
159 using ForwardRangeNotDerivedFrom = UncheckedRange<ForwardIteratorNotDerivedFrom>;
160 
161 static_assert(std::input_iterator<ForwardIteratorNotDerivedFrom>);
162 static_assert(std::incrementable<ForwardIteratorNotDerivedFrom>);
163 static_assert(std::sentinel_for<ForwardIteratorNotDerivedFrom, ForwardIteratorNotDerivedFrom>);
164 static_assert(!std::forward_iterator<ForwardIteratorNotDerivedFrom>);
165 
166 class ForwardIteratorNotIncrementable {
167 public:
168   using difference_type = long;
169   using value_type = int;
170   using iterator_category = std::forward_iterator_tag;
171 
172   ForwardIteratorNotIncrementable& operator++();
173   int operator++(int);
174   const int& operator*() const;
175   bool operator==(const ForwardIteratorNotIncrementable&) const = default;
176 };
177 
178 using ForwardRangeNotIncrementable = UncheckedRange<ForwardIteratorNotIncrementable>;
179 
180 static_assert(std::input_iterator<ForwardIteratorNotIncrementable>);
181 static_assert(!std::incrementable<ForwardIteratorNotIncrementable>);
182 static_assert(std::sentinel_for<ForwardIteratorNotIncrementable, ForwardIteratorNotIncrementable>);
183 static_assert(!std::forward_iterator<ForwardIteratorNotIncrementable>);
184 
185 using ForwardRangeNotSentinelSemiregular = UncheckedRange<forward_iterator<int*>, SentinelForNotSemiregular>;
186 using ForwardRangeNotSentinelEqualityComparableWith =
187     UncheckedRange<forward_iterator<int*>, SentinelForNotWeaklyEqualityComparableWith>;
188 
189 class BidirectionalIteratorNotDerivedFrom {
190 public:
191   using difference_type = long;
192   using value_type = int;
193   using iterator_category = std::forward_iterator_tag;
194 
195   BidirectionalIteratorNotDerivedFrom& operator++();
196   BidirectionalIteratorNotDerivedFrom operator++(int);
197   BidirectionalIteratorNotDerivedFrom& operator--();
198   BidirectionalIteratorNotDerivedFrom operator--(int);
199   int& operator*() const;
200 
201   bool operator==(const BidirectionalIteratorNotDerivedFrom&) const = default;
202 };
203 
204 using BidirectionalRangeNotDerivedFrom = UncheckedRange<BidirectionalIteratorNotDerivedFrom>;
205 using BidirectionalRangeNotSentinelSemiregular =
206     UncheckedRange<bidirectional_iterator<int*>, SentinelForNotSemiregular>;
207 using BidirectionalRangeNotSentinelWeaklyEqualityComparableWith =
208     UncheckedRange<bidirectional_iterator<int*>, SentinelForNotWeaklyEqualityComparableWith>;
209 
210 static_assert(std::forward_iterator<BidirectionalIteratorNotDerivedFrom>);
211 static_assert(!std::bidirectional_iterator<BidirectionalIteratorNotDerivedFrom>);
212 static_assert(!std::ranges::bidirectional_range<BidirectionalRangeNotDerivedFrom>);
213 
214 class BidirectionalIteratorNotDecrementable {
215 public:
216   using difference_type = long;
217   using value_type = int;
218   using iterator_category = std::bidirectional_iterator_tag;
219 
220   BidirectionalIteratorNotDecrementable& operator++();
221   BidirectionalIteratorNotDecrementable operator++(int);
222   int& operator*() const;
223 
224   bool operator==(const BidirectionalIteratorNotDecrementable&) const = default;
225 };
226 
227 using BidirectionalRangeNotDecrementable = UncheckedRange<BidirectionalIteratorNotDecrementable>;
228 
229 static_assert(std::forward_iterator<BidirectionalIteratorNotDecrementable>);
230 static_assert(!std::bidirectional_iterator<BidirectionalIteratorNotDecrementable>);
231 static_assert(!std::ranges::bidirectional_range<BidirectionalRangeNotDecrementable>);
232 
233 class PermutableNotForwardIterator {
234 public:
235   using difference_type = long;
236   using value_type = int;
237   using iterator_category = std::input_iterator_tag;
238 
239   PermutableNotForwardIterator& operator++();
240   void operator++(int);
241   int& operator*() const;
242 };
243 
244 using PermutableRangeNotForwardIterator = UncheckedRange<PermutableNotForwardIterator>;
245 
246 static_assert(std::input_iterator<PermutableNotForwardIterator>);
247 static_assert(!std::forward_iterator<PermutableNotForwardIterator>);
248 static_assert(!std::permutable<PermutableNotForwardIterator>);
249 
250 class PermutableNotSwappable {
251 public:
252   class NotSwappable {
253     NotSwappable(NotSwappable&&) = delete;
254   };
255 
256   using difference_type = long;
257   using value_type = NotSwappable;
258   using iterator_category = std::contiguous_iterator_tag;
259 
260   PermutableNotSwappable& operator++();
261   PermutableNotSwappable operator++(int);
262   NotSwappable& operator*() const;
263 
264   bool operator==(const PermutableNotSwappable&) const = default;
265 };
266 
267 using PermutableRangeNotSwappable = UncheckedRange<PermutableNotSwappable>;
268 
269 static_assert(std::input_iterator<PermutableNotSwappable>);
270 static_assert(std::forward_iterator<PermutableNotSwappable>);
271 static_assert(!std::permutable<PermutableNotSwappable>);
272 static_assert(!std::indirectly_swappable<PermutableNotSwappable>);
273 
274 class OutputIteratorNotInputOrOutputIterator {
275 public:
276   using difference_type = long;
277   using value_type = int;
278   using iterator_category = std::input_iterator_tag;
279 
280   int& operator++();
281   void operator++(int);
282   int& operator*();
283 };
284 
285 using OutputRangeNotInputOrOutputIterator = UncheckedRange<InputIteratorNotInputOrOutputIterator>;
286 
287 static_assert(!std::input_or_output_iterator<OutputIteratorNotInputOrOutputIterator>);
288 static_assert(std::indirectly_writable<OutputIteratorNotInputOrOutputIterator, int>);
289 static_assert(!std::output_iterator<OutputIteratorNotInputOrOutputIterator, int>);
290 static_assert(!std::ranges::input_range<OutputRangeNotInputOrOutputIterator>);
291 
292 class OutputIteratorNotIndirectlyWritable {
293 public:
294   using difference_type = long;
295   using iterator_category = std::input_iterator_tag;
296 
297   OutputIteratorNotIndirectlyWritable& operator++();
298   void operator++(int);
299   const int& operator*() const;
300 };
301 
302 using OutputRangeNotIndirectlyWritable = UncheckedRange<OutputIteratorNotIndirectlyWritable>;
303 
304 static_assert(std::input_or_output_iterator<OutputIteratorNotIndirectlyWritable>);
305 static_assert(!std::indirectly_writable<OutputIteratorNotIndirectlyWritable, int>);
306 static_assert(!std::output_iterator<OutputIteratorNotIndirectlyWritable, int>);
307 static_assert(!std::ranges::output_range<OutputIteratorNotIndirectlyWritable, int>);
308 
309 class IndirectBinaryPredicateNotIndirectlyReadable {
310 public:
311   using difference_type = long;
312   using iterator_category = std::input_iterator_tag;
313 
314   int& operator++();
315   void operator++(int);
316   const int& operator*() const;
317 };
318 
319 using InputRangeIndirectBinaryPredicateNotIndirectlyReadable
320      = UncheckedRange<cpp20_input_iterator<int*>, IndirectBinaryPredicateNotIndirectlyReadable>;
321 
322 static_assert(!std::indirect_binary_predicate<std::ranges::equal_to, IndirectBinaryPredicateNotIndirectlyReadable, int*>);
323 
324 class RandomAccessIteratorNotDerivedFrom {
325   using Self = RandomAccessIteratorNotDerivedFrom;
326 
327 public:
328   using value_type = int;
329   using difference_type = long;
330   using pointer = int*;
331   using reference = int&;
332   // Deliberately not using the `std::random_access_iterator_tag` category.
333   using iterator_category = std::bidirectional_iterator_tag;
334 
335   reference operator*() const;
336   reference operator[](difference_type) const;
337 
338   Self& operator++();
339   Self& operator--();
340   Self operator++(int);
341   Self operator--(int);
342 
343   Self& operator+=(difference_type);
344   Self& operator-=(difference_type);
345   friend Self operator+(Self, difference_type);
346   friend Self operator+(difference_type, Self);
347   friend Self operator-(Self, difference_type);
348   friend difference_type operator-(Self, Self);
349 
350   auto operator<=>(const Self&) const = default;
351 };
352 
353 static_assert(std::bidirectional_iterator<RandomAccessIteratorNotDerivedFrom>);
354 static_assert(!std::random_access_iterator<RandomAccessIteratorNotDerivedFrom>);
355 
356 using RandomAccessRangeNotDerivedFrom = UncheckedRange<RandomAccessIteratorNotDerivedFrom>;
357 
358 class RandomAccessIteratorBadIndex {
359   using Self = RandomAccessIteratorBadIndex;
360 
361 public:
362   using value_type = int;
363   using difference_type = long;
364   using pointer = int*;
365   using reference = int&;
366   using iterator_category = std::random_access_iterator_tag;
367 
368   reference operator*() const;
369   // Deliberately returning a type different from `reference`.
370   const int& operator[](difference_type) const;
371 
372   Self& operator++();
373   Self& operator--();
374   Self operator++(int);
375   Self operator--(int);
376 
377   Self& operator+=(difference_type);
378   Self& operator-=(difference_type);
379   friend Self operator+(Self, difference_type);
380   friend Self operator+(difference_type, Self);
381   friend Self operator-(Self, difference_type);
382   friend difference_type operator-(Self, Self);
383 
384   auto operator<=>(const Self&) const = default;
385 };
386 
387 static_assert(std::bidirectional_iterator<RandomAccessIteratorBadIndex>);
388 static_assert(!std::random_access_iterator<RandomAccessIteratorBadIndex>);
389 
390 using RandomAccessRangeBadIndex = UncheckedRange<RandomAccessIteratorBadIndex>;
391 
392 template <class Iter>
393 class ComparatorNotCopyable {
394 public:
395   ComparatorNotCopyable(ComparatorNotCopyable&&) = default;
396   ComparatorNotCopyable& operator=(ComparatorNotCopyable&&) = default;
397   ComparatorNotCopyable(const ComparatorNotCopyable&) = delete;
398   ComparatorNotCopyable& operator=(const ComparatorNotCopyable&) = delete;
399 
400   bool operator()(Iter&, Iter&) const;
401 };
402 
403 #endif // ALMOST_SATISFIES_TYPES_H
404