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-has-no-incomplete-ranges
11 
12 // constexpr InnerIter operator->() const
13 //   requires has-arrow<InnerIter> && copyable<InnerIter>;
14 
15 #include <cassert>
16 #include <ranges>
17 
18 #include "../types.h"
19 
20 template <class T>
21 concept HasArrow = std::input_iterator<T> && (std::is_pointer_v<T> || requires(T i) { i.operator->(); });
22 
23 template <class Base>
24 struct move_only_input_iter_with_arrow {
25   Base it_;
26 
27   using value_type = std::iter_value_t<Base>;
28   using difference_type = std::intptr_t;
29   using iterator_concept = std::input_iterator_tag;
30 
move_only_input_iter_with_arrowmove_only_input_iter_with_arrow31   constexpr move_only_input_iter_with_arrow(Base it) : it_(std::move(it)) {}
32   constexpr move_only_input_iter_with_arrow(move_only_input_iter_with_arrow&&) = default;
33   constexpr move_only_input_iter_with_arrow(const move_only_input_iter_with_arrow&) = delete;
34   constexpr move_only_input_iter_with_arrow& operator=(move_only_input_iter_with_arrow&&) = default;
35   constexpr move_only_input_iter_with_arrow& operator=(const move_only_input_iter_with_arrow&) = delete;
36 
operator ++move_only_input_iter_with_arrow37   constexpr move_only_input_iter_with_arrow& operator++() {
38     ++it_;
39     return *this;
40   }
operator ++move_only_input_iter_with_arrow41   constexpr void operator++(int) { ++it_; }
42 
operator *move_only_input_iter_with_arrow43   constexpr std::iter_reference_t<Base> operator*() const { return *it_; }
operator ->move_only_input_iter_with_arrow44   constexpr auto operator->() const
45     requires(HasArrow<Base> && std::copyable<Base>) {
46     return it_;
47   }
48 };
49 static_assert(!std::copyable<move_only_input_iter_with_arrow<int*>>);
50 static_assert(std::input_iterator<move_only_input_iter_with_arrow<int*>>);
51 
52 template <class Base>
53 struct move_iter_sentinel {
54   Base it_;
55   explicit move_iter_sentinel() = default;
move_iter_sentinelmove_iter_sentinel56   constexpr move_iter_sentinel(Base it) : it_(std::move(it)) {}
operator ==move_iter_sentinel57   constexpr bool operator==(const move_only_input_iter_with_arrow<Base>& other) const { return it_ == other.it_; }
58 };
59 static_assert(std::sentinel_for<move_iter_sentinel<int*>, move_only_input_iter_with_arrow<int*>>);
60 
61 struct MoveOnlyIterInner : BufferView<move_only_input_iter_with_arrow<Box*>, move_iter_sentinel<Box*>> {
62   using BufferView::BufferView;
63 
64   using iterator = move_only_input_iter_with_arrow<Box*>;
65   using sentinel = move_iter_sentinel<Box*>;
66 
beginMoveOnlyIterInner67   iterator begin() const { return data_; }
endMoveOnlyIterInner68   sentinel end() const { return sentinel{data_ + size_}; }
69 };
70 static_assert(std::ranges::input_range<MoveOnlyIterInner>);
71 
72 template <class Base>
73 struct arrow_input_iter {
74   Base it_;
75 
76   using value_type = std::iter_value_t<Base>;
77   using difference_type = std::intptr_t;
78   using iterator_concept = std::input_iterator_tag;
79 
80   arrow_input_iter() = default;
arrow_input_iterarrow_input_iter81   constexpr arrow_input_iter(Base it) : it_(std::move(it)) {}
82 
operator ++arrow_input_iter83   constexpr arrow_input_iter& operator++() {
84     ++it_;
85     return *this;
86   }
operator ++arrow_input_iter87   constexpr void operator++(int) { ++it_; }
88 
operator *arrow_input_iter89   constexpr std::iter_reference_t<Base> operator*() const { return *it_; }
operator ->arrow_input_iter90   constexpr auto operator->() const { return it_; }
91 
92   friend constexpr bool operator==(const arrow_input_iter& x, const arrow_input_iter& y) = default;
93 };
94 
95 using ArrowInner = BufferView<arrow_input_iter<Box*>>;
96 static_assert(std::ranges::input_range<ArrowInner>);
97 static_assert(HasArrow<std::ranges::iterator_t<ArrowInner>>);
98 
test()99 constexpr bool test() {
100   Box buffer[4][4] = {{{1111}, {2222}, {3333}, {4444}},
101                       {{555}, {666}, {777}, {888}},
102                       {{99}, {1010}, {1111}, {1212}},
103                       {{13}, {14}, {15}, {16}}};
104 
105   {
106     // Copyable input iterator with arrow.
107     ValueView<Box> children[4] = {ValueView(buffer[0]), ValueView(buffer[1]), ValueView(buffer[2]),
108                                   ValueView(buffer[3])};
109     std::ranges::join_view jv(ValueView<ValueView<Box>>{children});
110     assert(jv.begin()->x == 1111);
111     static_assert(HasArrow<decltype(jv.begin())>);
112   }
113 
114   {
115     std::ranges::join_view jv(buffer);
116     assert(jv.begin()->x == 1111);
117     static_assert(HasArrow<decltype(jv.begin())>);
118   }
119 
120   {
121     const std::ranges::join_view jv(buffer);
122     assert(jv.begin()->x == 1111);
123     static_assert(HasArrow<decltype(jv.begin())>);
124   }
125 
126   {
127     // LWG3500 `join_view::iterator::operator->()` is bogus
128     // `operator->` should not be defined if inner iterator is not copyable
129     // has-arrow<InnerIter> && !copyable<InnerIter>
130     static_assert(HasArrow<move_only_input_iter_with_arrow<int*>>);
131     MoveOnlyIterInner inners[2] = {buffer[0], buffer[1]};
132     std::ranges::join_view jv{inners};
133     static_assert(HasArrow<decltype(std::ranges::begin(inners[0]))>);
134     static_assert(!HasArrow<decltype(jv.begin())>);
135   }
136 
137   {
138     // LWG3500 `join_view::iterator::operator->()` is bogus
139     // `operator->` should not be defined if inner iterator does not have `operator->`
140     // !has-arrow<InnerIter> && copyable<InnerIter>
141     using Inner = BufferView<forward_iterator<Box*>>;
142     Inner inners[2] = {buffer[0], buffer[1]};
143     std::ranges::join_view jv{inners};
144     static_assert(!HasArrow<decltype(std::ranges::begin(inners[0]))>);
145     static_assert(!HasArrow<decltype(jv.begin())>);
146   }
147 
148   {
149     // arrow returns inner iterator
150     ArrowInner inners[2] = {buffer[0], buffer[1]};
151     std::ranges::join_view jv{inners};
152     static_assert(HasArrow<decltype(std::ranges::begin(inners[0]))>);
153     static_assert(HasArrow<decltype(jv.begin())>);
154 
155     auto jv_it = jv.begin();
156     std::same_as<arrow_input_iter<Box*>> auto arrow_it = jv_it.operator->();
157     assert(arrow_it->x == 1111);
158   }
159   return true;
160 }
161 
main(int,char **)162 int main(int, char**) {
163   test();
164   static_assert(test());
165 
166   return 0;
167 }
168