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 31 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 37 constexpr move_only_input_iter_with_arrow& operator++() { 38 ++it_; 39 return *this; 40 } 41 constexpr void operator++(int) { ++it_; } 42 43 constexpr std::iter_reference_t<Base> operator*() const { return *it_; } 44 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; 56 constexpr move_iter_sentinel(Base it) : it_(std::move(it)) {} 57 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 67 iterator begin() const { return data_; } 68 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; 81 constexpr arrow_input_iter(Base it) : it_(std::move(it)) {} 82 83 constexpr arrow_input_iter& operator++() { 84 ++it_; 85 return *this; 86 } 87 constexpr void operator++(int) { ++it_; } 88 89 constexpr std::iter_reference_t<Base> operator*() const { return *it_; } 90 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 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 162 int main(int, char**) { 163 test(); 164 static_assert(test()); 165 166 return 0; 167 } 168