| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_JOIN_TYPES_H |
| #define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_JOIN_TYPES_H |
| |
| #include <concepts> |
| #include <cstdint> |
| #include <tuple> |
| |
| #include "test_macros.h" |
| #include "test_iterators.h" |
| |
| inline int globalBuffer[4][4] = { |
| {1111, 2222, 3333, 4444}, |
| {555, 666, 777, 888}, |
| {99, 1010, 1111, 1212}, |
| {13, 14, 15, 16}, |
| }; |
| |
| template <template<class...> class Iter> |
| struct ChildViewBase : std::ranges::view_base { |
| int* ptr_; |
| |
| using iterator = Iter<int*>; |
| using const_iterator = Iter<const int*>; |
| using sentinel = sentinel_wrapper<iterator>; |
| using const_sentinel = sentinel_wrapper<const_iterator>; |
| |
| constexpr ChildViewBase(int* ptr = globalBuffer[0]) : ptr_(ptr) {} |
| ChildViewBase(const ChildViewBase&) = delete; |
| ChildViewBase(ChildViewBase&&) = default; |
| ChildViewBase& operator=(const ChildViewBase&) = delete; |
| ChildViewBase& operator=(ChildViewBase&&) = default; |
| |
| constexpr iterator begin() { return iterator(ptr_); } |
| constexpr const_iterator begin() const { return const_iterator(ptr_); } |
| constexpr sentinel end() { return sentinel(iterator(ptr_ + 4)); } |
| constexpr const_sentinel end() const { return const_sentinel(const_iterator(ptr_ + 4)); } |
| }; |
| using ChildView = ChildViewBase<cpp20_input_iterator>; |
| |
| inline ChildView globalChildren[4] = { |
| ChildView(globalBuffer[0]), |
| ChildView(globalBuffer[1]), |
| ChildView(globalBuffer[2]), |
| ChildView(globalBuffer[3]), |
| }; |
| |
| template <class T> |
| struct ParentView : std::ranges::view_base { |
| T* ptr_; |
| unsigned size_; |
| |
| using iterator = cpp20_input_iterator<T*>; |
| using const_iterator = cpp20_input_iterator<const T*>; |
| using sentinel = sentinel_wrapper<iterator>; |
| using const_sentinel = sentinel_wrapper<const_iterator>; |
| |
| constexpr ParentView(T* ptr, unsigned size = 4) : ptr_(ptr), size_(size) {} |
| constexpr ParentView(ChildView* ptr = globalChildren, unsigned size = 4) |
| requires std::same_as<ChildView, T> |
| : ptr_(ptr), size_(size) {} |
| ParentView(const ParentView&) = delete; |
| ParentView(ParentView&&) = default; |
| ParentView& operator=(const ParentView&) = delete; |
| ParentView& operator=(ParentView&&) = default; |
| |
| constexpr iterator begin() { return iterator(ptr_); } |
| constexpr const_iterator begin() const { return const_iterator(ptr_); } |
| constexpr sentinel end() { return sentinel(iterator(ptr_ + size_)); } |
| constexpr const_sentinel end() const { return const_sentinel(const_iterator(ptr_ + size_)); } |
| }; |
| |
| template <class T> |
| ParentView(T*) -> ParentView<T>; |
| |
| struct CopyableChild : std::ranges::view_base { |
| int* ptr_; |
| unsigned size_; |
| |
| using iterator = cpp17_input_iterator<int*>; |
| using const_iterator = cpp17_input_iterator<const int*>; |
| using sentinel = sentinel_wrapper<iterator>; |
| using const_sentinel = sentinel_wrapper<const_iterator>; |
| |
| constexpr CopyableChild(int* ptr = globalBuffer[0], unsigned size = 4) : ptr_(ptr), size_(size) {} |
| |
| constexpr iterator begin() { return iterator(ptr_); } |
| constexpr const_iterator begin() const { return const_iterator(ptr_); } |
| constexpr sentinel end() { return sentinel(iterator(ptr_ + size_)); } |
| constexpr const_sentinel end() const { return const_sentinel(const_iterator(ptr_ + size_)); } |
| }; |
| |
| struct CopyableParent : std::ranges::view_base { |
| CopyableChild* ptr_; |
| |
| using iterator = cpp17_input_iterator<CopyableChild*>; |
| using const_iterator = cpp17_input_iterator<const CopyableChild*>; |
| using sentinel = sentinel_wrapper<iterator>; |
| using const_sentinel = sentinel_wrapper<const_iterator>; |
| |
| constexpr CopyableParent(CopyableChild* ptr) : ptr_(ptr) {} |
| |
| constexpr iterator begin() { return iterator(ptr_); } |
| constexpr const_iterator begin() const { return const_iterator(ptr_); } |
| constexpr sentinel end() { return sentinel(iterator(ptr_ + 4)); } |
| constexpr const_sentinel end() const { return const_sentinel(const_iterator(ptr_ + 4)); } |
| }; |
| |
| struct Box { |
| int x; |
| }; |
| |
| template <class T> |
| struct InputValueIter { |
| typedef std::input_iterator_tag iterator_category; |
| typedef T value_type; |
| typedef int difference_type; |
| typedef T reference; |
| |
| T* ptr_ = nullptr; |
| constexpr InputValueIter() = default; |
| constexpr InputValueIter(T* ptr) : ptr_(ptr) {} |
| |
| constexpr T operator*() const { return std::move(*ptr_); } |
| constexpr void operator++(int) { ++ptr_; } |
| constexpr InputValueIter& operator++() { |
| ++ptr_; |
| return *this; |
| } |
| |
| constexpr T* operator->() { return ptr_; } |
| |
| constexpr friend bool operator==(const InputValueIter&, const InputValueIter&) = default; |
| }; |
| |
| template <class T> |
| struct ValueView : std::ranges::view_base { |
| InputValueIter<T> ptr_; |
| |
| using sentinel = sentinel_wrapper<InputValueIter<T>>; |
| |
| constexpr ValueView(T* ptr) : ptr_(ptr) {} |
| |
| constexpr ValueView(ValueView&& other) : ptr_(other.ptr_) { other.ptr_.ptr_ = nullptr; } |
| |
| constexpr ValueView& operator=(ValueView&& other) { |
| ptr_ = other.ptr_; |
| other.ptr_ = InputValueIter<T>(nullptr); |
| return *this; |
| } |
| |
| ValueView(const ValueView&) = delete; |
| ValueView& operator=(const ValueView&) = delete; |
| |
| constexpr InputValueIter<T> begin() const { return ptr_; } |
| constexpr sentinel end() const { return sentinel(InputValueIter<T>(ptr_.ptr_ + 4)); } |
| }; |
| |
| template <class Iter, class Sent = Iter, class NonConstIter = Iter, class NonConstSent = Sent> |
| struct BufferView : std::ranges::view_base { |
| |
| using T = std::iter_value_t<Iter>; |
| T* data_; |
| std::size_t size_; |
| |
| template <std::size_t N> |
| constexpr BufferView(T (&b)[N]) : data_(b), size_(N) {} |
| constexpr BufferView(T* p, std::size_t s) : data_(p), size_(s) {} |
| |
| constexpr NonConstIter begin() |
| requires(!std::is_same_v<Iter, NonConstIter>) { |
| return NonConstIter(this->data_); |
| } |
| constexpr Iter begin() const { return Iter(this->data_); } |
| |
| constexpr NonConstSent end() |
| requires(!std::is_same_v<Sent, NonConstSent>) { |
| if constexpr (std::is_same_v<NonConstIter, NonConstSent>) { |
| return NonConstIter(this->data_ + this->size_); |
| } else { |
| return NonConstSent(NonConstIter(this->data_ + this->size_)); |
| } |
| } |
| |
| constexpr Sent end() const { |
| if constexpr (std::is_same_v<Iter, Sent>) { |
| return Iter(this->data_ + this->size_); |
| } else { |
| return Sent(Iter(this->data_ + this->size_)); |
| } |
| } |
| }; |
| |
| using InputCommonInner = BufferView<common_input_iterator<int*>>; |
| static_assert(std::ranges::input_range<InputCommonInner>); |
| static_assert(!std::ranges::forward_range<InputCommonInner>); |
| static_assert(std::ranges::common_range<InputCommonInner>); |
| |
| using InputNonCommonInner = BufferView<common_input_iterator<int*>, sentinel_wrapper<common_input_iterator<int*>>>; |
| static_assert(std::ranges::input_range<InputNonCommonInner>); |
| static_assert(!std::ranges::forward_range<InputNonCommonInner>); |
| static_assert(!std::ranges::common_range<InputNonCommonInner>); |
| |
| using ForwardCommonInner = BufferView<forward_iterator<int*>>; |
| static_assert(std::ranges::forward_range<ForwardCommonInner>); |
| static_assert(!std::ranges::bidirectional_range<ForwardCommonInner>); |
| static_assert(std::ranges::common_range<ForwardCommonInner>); |
| |
| using ForwardNonCommonInner = BufferView<forward_iterator<int*>, sentinel_wrapper<forward_iterator<int*>>>; |
| static_assert(std::ranges::forward_range<ForwardNonCommonInner>); |
| static_assert(!std::ranges::bidirectional_range<ForwardNonCommonInner>); |
| static_assert(!std::ranges::common_range<ForwardNonCommonInner>); |
| |
| using BidiCommonInner = BufferView<bidirectional_iterator<int*>>; |
| static_assert(std::ranges::bidirectional_range<BidiCommonInner>); |
| static_assert(std::ranges::common_range<BidiCommonInner>); |
| |
| using BidiNonCommonInner = BufferView<bidirectional_iterator<int*>, sentinel_wrapper<bidirectional_iterator<int*>>>; |
| static_assert(std::ranges::bidirectional_range<BidiNonCommonInner>); |
| static_assert(!std::ranges::common_range<BidiNonCommonInner>); |
| |
| template <class Inner = BufferView<int*>> |
| using SimpleInputCommonOuter = BufferView<common_input_iterator<Inner*>>; |
| static_assert(!std::ranges::forward_range<SimpleInputCommonOuter<>>); |
| static_assert(!std::ranges::bidirectional_range<SimpleInputCommonOuter<>>); |
| static_assert(std::ranges::common_range<SimpleInputCommonOuter<>>); |
| LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<SimpleInputCommonOuter<>>); |
| |
| template <class Inner = BufferView<int*>> |
| using NonSimpleInputCommonOuter = BufferView<common_input_iterator<const Inner*>, common_input_iterator<const Inner*>, |
| common_input_iterator< Inner*>, common_input_iterator< Inner*>>; |
| static_assert(!std::ranges::forward_range<NonSimpleInputCommonOuter<>>); |
| static_assert(!std::ranges::bidirectional_range<NonSimpleInputCommonOuter<>>); |
| static_assert(std::ranges::common_range<NonSimpleInputCommonOuter<>>); |
| LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<NonSimpleInputCommonOuter<>>); |
| |
| template <class Inner = BufferView<int*>> |
| using SimpleForwardCommonOuter = BufferView<forward_iterator<Inner*>>; |
| static_assert(std::ranges::forward_range<SimpleForwardCommonOuter<>>); |
| static_assert(!std::ranges::bidirectional_range<SimpleForwardCommonOuter<>>); |
| static_assert(std::ranges::common_range<SimpleForwardCommonOuter<>>); |
| LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<SimpleForwardCommonOuter<>>); |
| |
| template <class Inner = BufferView<int*>> |
| using NonSimpleForwardCommonOuter = BufferView<forward_iterator<const Inner*>, forward_iterator<const Inner*>, |
| forward_iterator<Inner*>, forward_iterator<Inner*>>; |
| static_assert(std::ranges::forward_range<NonSimpleForwardCommonOuter<>>); |
| static_assert(!std::ranges::bidirectional_range<NonSimpleForwardCommonOuter<>>); |
| static_assert(std::ranges::common_range<NonSimpleForwardCommonOuter<>>); |
| LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<NonSimpleForwardCommonOuter<>>); |
| |
| template <class Inner = BufferView<int*>> |
| using SimpleForwardNonCommonOuter = BufferView<forward_iterator<Inner*>, sentinel_wrapper<forward_iterator<Inner*>>>; |
| static_assert(std::ranges::forward_range<SimpleForwardNonCommonOuter<>>); |
| static_assert(!std::ranges::bidirectional_range<SimpleForwardNonCommonOuter<>>); |
| static_assert(!std::ranges::common_range<SimpleForwardNonCommonOuter<>>); |
| LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<SimpleForwardNonCommonOuter<>>); |
| |
| template <class Inner = BufferView<int*>> |
| using NonSimpleForwardNonCommonOuter = |
| BufferView<forward_iterator<const Inner*>, sentinel_wrapper<forward_iterator<const Inner*>>, |
| forward_iterator<Inner*>, sentinel_wrapper<forward_iterator<Inner*>>>; |
| static_assert(std::ranges::forward_range<NonSimpleForwardNonCommonOuter<>>); |
| static_assert(!std::ranges::bidirectional_range<NonSimpleForwardNonCommonOuter<>>); |
| static_assert(!std::ranges::common_range<NonSimpleForwardNonCommonOuter<>>); |
| LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<NonSimpleForwardNonCommonOuter<>>); |
| |
| template <class Inner = BufferView<int*>> |
| using BidiCommonOuter = BufferView<bidirectional_iterator<Inner*>>; |
| static_assert(std::ranges::bidirectional_range<BidiCommonOuter<>>); |
| static_assert(std::ranges::common_range<BidiCommonOuter<>>); |
| LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<BidiCommonOuter<>>); |
| |
| // an iterator where its operator* makes a copy of underlying operator* |
| template <class It> |
| struct copying_iterator { |
| It it_ = It(); |
| |
| using value_type = typename std::iterator_traits<It>::value_type; |
| using difference_type = typename std::iterator_traits<It>::difference_type; |
| using pointer = typename std::iterator_traits<It>::pointer; |
| |
| copying_iterator() requires std::default_initializable<It> = default; |
| constexpr copying_iterator(It it) : it_(std::move(it)) {} |
| |
| // makes a copy of underlying operator* to create a PRValue |
| constexpr value_type operator*() const { return *it_; } |
| |
| constexpr copying_iterator& operator++() { |
| ++it_; |
| return *this; |
| } |
| constexpr copying_iterator& operator--() |
| requires std::bidirectional_iterator<It> { |
| --it_; |
| return *this; |
| } |
| constexpr copying_iterator operator++(int) |
| requires std::forward_iterator<It> { |
| return copying_iterator(it_++); |
| } |
| constexpr void operator++(int) { return it_++; } |
| constexpr copying_iterator operator--(int) |
| requires std::bidirectional_iterator<It> { |
| return copying_iterator(it_--); |
| } |
| |
| friend constexpr bool operator==(const copying_iterator& x, const copying_iterator& y) = default; |
| }; |
| |
| template <class Outer> |
| struct InnerRValue : Outer { |
| |
| using iterator = copying_iterator<std::ranges::iterator_t<Outer>>; |
| using const_iterator = copying_iterator<std::ranges::iterator_t<const Outer>>; |
| using sentinel = copying_iterator<std::ranges::sentinel_t<Outer>>; |
| using const_sentinel = copying_iterator<std::ranges::sentinel_t<const Outer>>; |
| |
| using Outer::Outer; |
| static_assert(std::ranges::common_range<Outer>, "non-common range is not supported yet"); |
| |
| constexpr iterator begin() { return Outer::begin(); } |
| constexpr const_iterator begin() const |
| requires std::ranges::range<const Outer> { |
| return Outer::begin(); |
| } |
| |
| constexpr auto end() { return iterator{Outer::end()}; } |
| constexpr auto end() const |
| requires std::ranges::range<const Outer> { |
| return const_iterator{Outer::end()}; |
| } |
| }; |
| static_assert(std::ranges::forward_range<InnerRValue<SimpleForwardCommonOuter<>>>); |
| static_assert(!std::ranges::bidirectional_range<InnerRValue<SimpleForwardCommonOuter<>>>); |
| static_assert(std::ranges::common_range<InnerRValue<SimpleForwardCommonOuter<>>>); |
| LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<InnerRValue<SimpleForwardCommonOuter<>>>); |
| static_assert(!std::is_lvalue_reference_v<std::ranges::range_reference_t<InnerRValue<SimpleForwardCommonOuter<>>>>); |
| |
| struct move_swap_aware_iter { |
| |
| // This is a proxy-like iterator where `reference` is a prvalue, and |
| // `reference` and `value_type` are distinct types (similar to `zip_view::iterator`). |
| using value_type = std::pair<int, int>; |
| using reference = std::pair<int&, int&>; |
| using rvalue_reference = std::pair<int&&, int&&>; |
| |
| using difference_type = std::intptr_t; |
| using iterator_concept = std::input_iterator_tag; |
| |
| int* iter_move_called = nullptr; |
| int* iter_swap_called = nullptr; |
| int* i_ = nullptr; |
| |
| constexpr move_swap_aware_iter& operator++() { |
| ++i_; |
| return *this; |
| } |
| constexpr void operator++(int) { ++i_; } |
| |
| constexpr reference operator*() const { return reference(*i_, *i_); } |
| constexpr friend bool operator==(const move_swap_aware_iter& x, const move_swap_aware_iter& y) { |
| return x.i_ == y.i_; |
| } |
| |
| constexpr friend rvalue_reference iter_move(const move_swap_aware_iter& x) noexcept { |
| ++(*x.iter_move_called); |
| return rvalue_reference{std::move(*x.i_), std::move(*x.i_)}; |
| } |
| |
| constexpr friend void iter_swap(const move_swap_aware_iter& x, const move_swap_aware_iter& y) noexcept { |
| ++(*x.iter_swap_called); |
| std::swap(*x.i_, *y.i_); |
| } |
| }; |
| |
| struct IterMoveSwapAwareView : BufferView<int*> { |
| int iter_move_called = 0; |
| int iter_swap_called = 0; |
| using BufferView<int*>::BufferView; |
| |
| constexpr auto begin() { return move_swap_aware_iter{&iter_move_called, &iter_swap_called, data_}; } |
| |
| constexpr auto end() { return move_swap_aware_iter{&iter_move_called, &iter_swap_called, data_ + size_}; } |
| }; |
| static_assert(std::ranges::input_range<IterMoveSwapAwareView>); |
| |
| #endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_JOIN_TYPES_H |