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 TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_JOIN_TYPES_H
10 #define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_JOIN_TYPES_H
11 
12 #include <concepts>
13 #include <cstdint>
14 #include <tuple>
15 
16 #include "test_macros.h"
17 #include "test_iterators.h"
18 
19 inline int globalBuffer[4][4] = {
20     {1111, 2222, 3333, 4444},
21     {555, 666, 777, 888},
22     {99, 1010, 1111, 1212},
23     {13, 14, 15, 16},
24 };
25 
26 struct ChildView : std::ranges::view_base {
27   int* ptr_;
28 
29   using iterator = cpp20_input_iterator<int*>;
30   using const_iterator = cpp20_input_iterator<const int*>;
31   using sentinel = sentinel_wrapper<iterator>;
32   using const_sentinel = sentinel_wrapper<const_iterator>;
33 
ptr_ChildView34   constexpr ChildView(int* ptr = globalBuffer[0]) : ptr_(ptr) {}
35   ChildView(const ChildView&) = delete;
36   ChildView(ChildView&&) = default;
37   ChildView& operator=(const ChildView&) = delete;
38   ChildView& operator=(ChildView&&) = default;
39 
beginChildView40   constexpr iterator begin() { return iterator(ptr_); }
beginChildView41   constexpr const_iterator begin() const { return const_iterator(ptr_); }
endChildView42   constexpr sentinel end() { return sentinel(iterator(ptr_ + 4)); }
endChildView43   constexpr const_sentinel end() const { return const_sentinel(const_iterator(ptr_ + 4)); }
44 };
45 
46 inline ChildView globalChildren[4] = {
47     ChildView(globalBuffer[0]),
48     ChildView(globalBuffer[1]),
49     ChildView(globalBuffer[2]),
50     ChildView(globalBuffer[3]),
51 };
52 
53 template <class T>
54 struct ParentView : std::ranges::view_base {
55   T* ptr_;
56   unsigned size_;
57 
58   using iterator = cpp20_input_iterator<T*>;
59   using const_iterator = cpp20_input_iterator<const T*>;
60   using sentinel = sentinel_wrapper<iterator>;
61   using const_sentinel = sentinel_wrapper<const_iterator>;
62 
ptr_ParentView63   constexpr ParentView(T* ptr, unsigned size = 4) : ptr_(ptr), size_(size) {}
64   constexpr ParentView(ChildView* ptr = globalChildren, unsigned size = 4)
65     requires std::same_as<ChildView, T>
ptr_ParentView66   : ptr_(ptr), size_(size) {}
67   ParentView(const ParentView&) = delete;
68   ParentView(ParentView&&) = default;
69   ParentView& operator=(const ParentView&) = delete;
70   ParentView& operator=(ParentView&&) = default;
71 
beginParentView72   constexpr iterator begin() { return iterator(ptr_); }
beginParentView73   constexpr const_iterator begin() const { return const_iterator(ptr_); }
endParentView74   constexpr sentinel end() { return sentinel(iterator(ptr_ + size_)); }
endParentView75   constexpr const_sentinel end() const { return const_sentinel(const_iterator(ptr_ + size_)); }
76 };
77 
78 struct CopyableChild : std::ranges::view_base {
79   int* ptr_;
80   unsigned size_;
81 
82   using iterator = cpp17_input_iterator<int*>;
83   using const_iterator = cpp17_input_iterator<const int*>;
84   using sentinel = sentinel_wrapper<iterator>;
85   using const_sentinel = sentinel_wrapper<const_iterator>;
86 
ptr_CopyableChild87   constexpr CopyableChild(int* ptr = globalBuffer[0], unsigned size = 4) : ptr_(ptr), size_(size) {}
88 
beginCopyableChild89   constexpr iterator begin() { return iterator(ptr_); }
beginCopyableChild90   constexpr const_iterator begin() const { return const_iterator(ptr_); }
endCopyableChild91   constexpr sentinel end() { return sentinel(iterator(ptr_ + size_)); }
endCopyableChild92   constexpr const_sentinel end() const { return const_sentinel(const_iterator(ptr_ + size_)); }
93 };
94 
95 struct CopyableParent : std::ranges::view_base {
96   CopyableChild* ptr_;
97 
98   using iterator = cpp17_input_iterator<CopyableChild*>;
99   using const_iterator = cpp17_input_iterator<const CopyableChild*>;
100   using sentinel = sentinel_wrapper<iterator>;
101   using const_sentinel = sentinel_wrapper<const_iterator>;
102 
CopyableParentCopyableParent103   constexpr CopyableParent(CopyableChild* ptr) : ptr_(ptr) {}
104 
beginCopyableParent105   constexpr iterator begin() { return iterator(ptr_); }
beginCopyableParent106   constexpr const_iterator begin() const { return const_iterator(ptr_); }
endCopyableParent107   constexpr sentinel end() { return sentinel(iterator(ptr_ + 4)); }
endCopyableParent108   constexpr const_sentinel end() const { return const_sentinel(const_iterator(ptr_ + 4)); }
109 };
110 
111 struct Box {
112   int x;
113 };
114 
115 template <class T>
116 struct InputValueIter {
117   typedef std::input_iterator_tag iterator_category;
118   typedef T value_type;
119   typedef int difference_type;
120   typedef T reference;
121 
122   T* ptr_ = nullptr;
123   constexpr InputValueIter() = default;
InputValueIterInputValueIter124   constexpr InputValueIter(T* ptr) : ptr_(ptr) {}
125 
126   constexpr T operator*() const { return std::move(*ptr_); }
127   constexpr void operator++(int) { ++ptr_; }
128   constexpr InputValueIter& operator++() {
129     ++ptr_;
130     return *this;
131   }
132 
133   constexpr T* operator->() { return ptr_; }
134 
135   constexpr friend bool operator==(const InputValueIter&, const InputValueIter&) = default;
136 };
137 
138 template <class T>
139 struct ValueView : std::ranges::view_base {
140   InputValueIter<T> ptr_;
141 
142   using sentinel = sentinel_wrapper<InputValueIter<T>>;
143 
ValueViewValueView144   constexpr ValueView(T* ptr) : ptr_(ptr) {}
145 
ValueViewValueView146   constexpr ValueView(ValueView&& other) : ptr_(other.ptr_) { other.ptr_.ptr_ = nullptr; }
147 
148   constexpr ValueView& operator=(ValueView&& other) {
149     ptr_ = other.ptr_;
150     other.ptr_ = InputValueIter<T>(nullptr);
151     return *this;
152   }
153 
154   ValueView(const ValueView&) = delete;
155   ValueView& operator=(const ValueView&) = delete;
156 
beginValueView157   constexpr InputValueIter<T> begin() const { return ptr_; }
endValueView158   constexpr sentinel end() const { return sentinel(InputValueIter<T>(ptr_.ptr_ + 4)); }
159 };
160 
161 template <class Iter, class Sent = Iter, class NonConstIter = Iter, class NonConstSent = Sent>
162 struct BufferView : std::ranges::view_base {
163 
164   using T = std::iter_value_t<Iter>;
165   T* data_;
166   std::size_t size_;
167 
168   template <std::size_t N>
BufferViewBufferView169   constexpr BufferView(T (&b)[N]) : data_(b), size_(N) {}
BufferViewBufferView170   constexpr BufferView(T* p, std::size_t s) : data_(p), size_(s) {}
171 
beginBufferView172   constexpr NonConstIter begin()
173     requires(!std::is_same_v<Iter, NonConstIter>) {
174     return NonConstIter(this->data_);
175   }
beginBufferView176   constexpr Iter begin() const { return Iter(this->data_); }
177 
endBufferView178   constexpr NonConstSent end()
179     requires(!std::is_same_v<Sent, NonConstSent>) {
180     if constexpr (std::is_same_v<NonConstIter, NonConstSent>) {
181       return NonConstIter(this->data_ + this->size_);
182     } else {
183       return NonConstSent(NonConstIter(this->data_ + this->size_));
184     }
185   }
186 
endBufferView187   constexpr Sent end() const {
188     if constexpr (std::is_same_v<Iter, Sent>) {
189       return Iter(this->data_ + this->size_);
190     } else {
191       return Sent(Iter(this->data_ + this->size_));
192     }
193   }
194 };
195 
196 // an `input_iterator` that can be used in a `common_range`
197 template <class Base>
198 struct common_input_iterator {
199   Base it_;
200 
201   using value_type = std::iter_value_t<Base>;
202   using difference_type = std::intptr_t;
203   using iterator_concept = std::input_iterator_tag;
204 
205   constexpr common_input_iterator() = default;
common_input_iteratorcommon_input_iterator206   constexpr explicit common_input_iterator(Base it) : it_(it) {}
207 
208   constexpr common_input_iterator& operator++() {
209     ++it_;
210     return *this;
211   }
212   constexpr void operator++(int) { ++it_; }
213 
214   constexpr std::iter_reference_t<Base> operator*() const { return *it_; }
215 
216   friend constexpr bool operator==(common_input_iterator const&, common_input_iterator const&) = default;
217 };
218 
219 using InputCommonInner = BufferView<common_input_iterator<int*>>;
220 static_assert(std::ranges::input_range<InputCommonInner>);
221 static_assert(!std::ranges::forward_range<InputCommonInner>);
222 static_assert(std::ranges::common_range<InputCommonInner>);
223 
224 using InputNonCommonInner = BufferView<common_input_iterator<int*>, sentinel_wrapper<common_input_iterator<int*>>>;
225 static_assert(std::ranges::input_range<InputNonCommonInner>);
226 static_assert(!std::ranges::forward_range<InputNonCommonInner>);
227 static_assert(!std::ranges::common_range<InputNonCommonInner>);
228 
229 using ForwardCommonInner = BufferView<forward_iterator<int*>>;
230 static_assert(std::ranges::forward_range<ForwardCommonInner>);
231 static_assert(!std::ranges::bidirectional_range<ForwardCommonInner>);
232 static_assert(std::ranges::common_range<ForwardCommonInner>);
233 
234 using ForwardNonCommonInner = BufferView<forward_iterator<int*>, sentinel_wrapper<forward_iterator<int*>>>;
235 static_assert(std::ranges::forward_range<ForwardNonCommonInner>);
236 static_assert(!std::ranges::bidirectional_range<ForwardNonCommonInner>);
237 static_assert(!std::ranges::common_range<ForwardNonCommonInner>);
238 
239 using BidiCommonInner = BufferView<bidirectional_iterator<int*>>;
240 static_assert(std::ranges::bidirectional_range<BidiCommonInner>);
241 static_assert(std::ranges::common_range<BidiCommonInner>);
242 
243 using BidiNonCommonInner = BufferView<bidirectional_iterator<int*>, sentinel_wrapper<bidirectional_iterator<int*>>>;
244 static_assert(std::ranges::bidirectional_range<BidiNonCommonInner>);
245 static_assert(!std::ranges::common_range<BidiNonCommonInner>);
246 
247 template <class Inner = BufferView<int*>>
248 using SimpleInputCommonOuter = BufferView<common_input_iterator<Inner*>>;
249 static_assert(!std::ranges::forward_range<SimpleInputCommonOuter<>>);
250 static_assert(!std::ranges::bidirectional_range<SimpleInputCommonOuter<>>);
251 static_assert(std::ranges::common_range<SimpleInputCommonOuter<>>);
252 LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<SimpleInputCommonOuter<>>);
253 
254 template <class Inner = BufferView<int*>>
255 using NonSimpleInputCommonOuter = BufferView<common_input_iterator<const Inner*>, common_input_iterator<const Inner*>,
256                                              common_input_iterator< Inner*>, common_input_iterator< Inner*>>;
257 static_assert(!std::ranges::forward_range<NonSimpleInputCommonOuter<>>);
258 static_assert(!std::ranges::bidirectional_range<NonSimpleInputCommonOuter<>>);
259 static_assert(std::ranges::common_range<NonSimpleInputCommonOuter<>>);
260 LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<NonSimpleInputCommonOuter<>>);
261 
262 template <class Inner = BufferView<int*>>
263 using SimpleForwardCommonOuter = BufferView<forward_iterator<Inner*>>;
264 static_assert(std::ranges::forward_range<SimpleForwardCommonOuter<>>);
265 static_assert(!std::ranges::bidirectional_range<SimpleForwardCommonOuter<>>);
266 static_assert(std::ranges::common_range<SimpleForwardCommonOuter<>>);
267 LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<SimpleForwardCommonOuter<>>);
268 
269 template <class Inner = BufferView<int*>>
270 using NonSimpleForwardCommonOuter = BufferView<forward_iterator<const Inner*>, forward_iterator<const Inner*>,
271                                                forward_iterator<Inner*>, forward_iterator<Inner*>>;
272 static_assert(std::ranges::forward_range<NonSimpleForwardCommonOuter<>>);
273 static_assert(!std::ranges::bidirectional_range<NonSimpleForwardCommonOuter<>>);
274 static_assert(std::ranges::common_range<NonSimpleForwardCommonOuter<>>);
275 LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<NonSimpleForwardCommonOuter<>>);
276 
277 template <class Inner = BufferView<int*>>
278 using SimpleForwardNonCommonOuter = BufferView<forward_iterator<Inner*>, sentinel_wrapper<forward_iterator<Inner*>>>;
279 static_assert(std::ranges::forward_range<SimpleForwardNonCommonOuter<>>);
280 static_assert(!std::ranges::bidirectional_range<SimpleForwardNonCommonOuter<>>);
281 static_assert(!std::ranges::common_range<SimpleForwardNonCommonOuter<>>);
282 LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<SimpleForwardNonCommonOuter<>>);
283 
284 template <class Inner = BufferView<int*>>
285 using NonSimpleForwardNonCommonOuter =
286     BufferView<forward_iterator<const Inner*>, sentinel_wrapper<forward_iterator<const Inner*>>,
287                forward_iterator<Inner*>, sentinel_wrapper<forward_iterator<Inner*>>>;
288 static_assert(std::ranges::forward_range<NonSimpleForwardNonCommonOuter<>>);
289 static_assert(!std::ranges::bidirectional_range<NonSimpleForwardNonCommonOuter<>>);
290 static_assert(!std::ranges::common_range<NonSimpleForwardNonCommonOuter<>>);
291 LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<NonSimpleForwardNonCommonOuter<>>);
292 
293 template <class Inner = BufferView<int*>>
294 using BidiCommonOuter = BufferView<bidirectional_iterator<Inner*>>;
295 static_assert(std::ranges::bidirectional_range<BidiCommonOuter<>>);
296 static_assert(std::ranges::common_range<BidiCommonOuter<>>);
297 LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<BidiCommonOuter<>>);
298 
299 // an iterator where its operator* makes a copy of underlying operator*
300 template <class It>
301 struct copying_iterator {
302   It it_ = It();
303 
304   using value_type = typename std::iterator_traits<It>::value_type;
305   using difference_type = typename std::iterator_traits<It>::difference_type;
306   using pointer = typename std::iterator_traits<It>::pointer;
307 
308   copying_iterator() requires std::default_initializable<It> = default;
copying_iteratorcopying_iterator309   constexpr copying_iterator(It it) : it_(std::move(it)) {}
310 
311   // makes a copy of underlying operator* to create a PRValue
312   constexpr value_type operator*() const { return *it_; }
313 
314   constexpr copying_iterator& operator++() {
315     ++it_;
316     return *this;
317   }
318   constexpr copying_iterator& operator--()
319     requires std::bidirectional_iterator<It> {
320     --it_;
321     return *this;
322   }
323   constexpr copying_iterator operator++(int)
324     requires std::forward_iterator<It> {
325     return copying_iterator(it_++);
326   }
327   constexpr void operator++(int) { return it_++; }
328   constexpr copying_iterator operator--(int)
329     requires std::bidirectional_iterator<It> {
330     return copying_iterator(it_--);
331   }
332 
333   friend constexpr bool operator==(const copying_iterator& x, const copying_iterator& y) = default;
334 };
335 
336 template <class Outer>
337 struct InnerRValue : Outer {
338 
339   using iterator = copying_iterator<std::ranges::iterator_t<Outer>>;
340   using const_iterator = copying_iterator<std::ranges::iterator_t<const Outer>>;
341   using sentinel = copying_iterator<std::ranges::sentinel_t<Outer>>;
342   using const_sentinel = copying_iterator<std::ranges::sentinel_t<const Outer>>;
343 
344   using Outer::Outer;
345   static_assert(std::ranges::common_range<Outer>, "non-common range is not supported yet");
346 
beginInnerRValue347   constexpr iterator begin() { return Outer::begin(); }
beginInnerRValue348   constexpr const_iterator begin() const
349     requires std::ranges::range<const Outer> {
350     return Outer::begin();
351   }
352 
endInnerRValue353   constexpr auto end() { return iterator{Outer::end()}; }
endInnerRValue354   constexpr auto end() const
355     requires std::ranges::range<const Outer> {
356     return const_iterator{Outer::end()};
357   }
358 };
359 static_assert(std::ranges::forward_range<InnerRValue<SimpleForwardCommonOuter<>>>);
360 static_assert(!std::ranges::bidirectional_range<InnerRValue<SimpleForwardCommonOuter<>>>);
361 static_assert(std::ranges::common_range<InnerRValue<SimpleForwardCommonOuter<>>>);
362 LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<InnerRValue<SimpleForwardCommonOuter<>>>);
363 static_assert(!std::is_lvalue_reference_v<std::ranges::range_reference_t<InnerRValue<SimpleForwardCommonOuter<>>>>);
364 
365 struct move_swap_aware_iter {
366 
367   // This is a proxy-like iterator where `reference` is a prvalue, and
368   // `reference` and `value_type` are distinct types (similar to `zip_view::iterator`).
369   using value_type = std::pair<int, int>;
370   using reference = std::pair<int&, int&>;
371   using rvalue_reference = std::pair<int&&, int&&>;
372 
373   using difference_type = std::intptr_t;
374   using iterator_concept = std::input_iterator_tag;
375 
376   int* iter_move_called = nullptr;
377   int* iter_swap_called = nullptr;
378   int* i_ = nullptr;
379 
380   constexpr move_swap_aware_iter& operator++() {
381     ++i_;
382     return *this;
383   }
384   constexpr void operator++(int) { ++i_; }
385 
386   constexpr reference operator*() const { return reference(*i_, *i_); }
387   constexpr friend bool operator==(const move_swap_aware_iter& x, const move_swap_aware_iter& y) {
388     return x.i_ == y.i_;
389   }
390 
iter_movemove_swap_aware_iter391   constexpr friend rvalue_reference iter_move(const move_swap_aware_iter& x) noexcept {
392     ++(*x.iter_move_called);
393     return rvalue_reference{std::move(*x.i_), std::move(*x.i_)};
394   }
395 
iter_swapmove_swap_aware_iter396   constexpr friend void iter_swap(const move_swap_aware_iter& x, const move_swap_aware_iter& y) noexcept {
397     ++(*x.iter_swap_called);
398     std::swap(*x.i_, *y.i_);
399   }
400 };
401 
402 struct IterMoveSwapAwareView : BufferView<int*> {
403   int iter_move_called = 0;
404   int iter_swap_called = 0;
405   using BufferView<int*>::BufferView;
406 
beginIterMoveSwapAwareView407   constexpr auto begin() { return move_swap_aware_iter{&iter_move_called, &iter_swap_called, data_}; }
408 
endIterMoveSwapAwareView409   constexpr auto end() { return move_swap_aware_iter{&iter_move_called, &iter_swap_called, data_ + size_}; }
410 };
411 static_assert(std::ranges::input_range<IterMoveSwapAwareView>);
412 
413 #endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_JOIN_TYPES_H
414