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