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 // template<range R> 13 // requires is_object_v<R> 14 // class ref_view; 15 16 #include <ranges> 17 18 #include <cassert> 19 #include "test_macros.h" 20 #include "test_iterators.h" 21 22 int globalBuff[8]; 23 24 template<class T> 25 concept ValidRefView = requires { typename std::ranges::ref_view<T>; }; 26 27 struct Range { 28 int start = 0; 29 friend constexpr int* begin(Range const& range) { return globalBuff + range.start; } 30 friend constexpr int* end(Range const&) { return globalBuff + 8; } 31 friend constexpr int* begin(Range& range) { return globalBuff + range.start; } 32 friend constexpr int* end(Range&) { return globalBuff + 8; } 33 }; 34 35 struct BeginOnly { 36 friend int* begin(BeginOnly const&); 37 friend int* begin(BeginOnly &); 38 }; 39 40 static_assert( ValidRefView<Range>); 41 static_assert(!ValidRefView<BeginOnly>); 42 static_assert(!ValidRefView<int (&)[4]>); 43 static_assert( ValidRefView<int[4]>); 44 45 static_assert(std::derived_from<std::ranges::ref_view<Range>, std::ranges::view_interface<std::ranges::ref_view<Range>>>); 46 47 struct RangeConvertible { 48 operator Range& (); 49 }; 50 51 struct RValueRangeConvertible { 52 operator Range&& (); 53 }; 54 55 static_assert( std::is_constructible_v<std::ranges::ref_view<Range>, Range&>); 56 static_assert( std::is_constructible_v<std::ranges::ref_view<Range>, RangeConvertible>); 57 static_assert(!std::is_constructible_v<std::ranges::ref_view<Range>, RValueRangeConvertible>); 58 59 struct ConstConvertibleToLValueAndRValue { 60 operator Range& () const; 61 operator Range&& () const; 62 }; 63 static_assert( std::is_convertible_v<RangeConvertible, std::ranges::ref_view<Range>>); 64 static_assert(!std::is_convertible_v<RValueRangeConvertible, std::ranges::ref_view<Range>>); 65 static_assert(!std::is_convertible_v<ConstConvertibleToLValueAndRValue, std::ranges::ref_view<Range>>); 66 67 struct ForwardRange { 68 constexpr forward_iterator<int*> begin() const { return forward_iterator<int*>(globalBuff); } 69 constexpr forward_iterator<int*> end() const { return forward_iterator<int*>(globalBuff + 8); } 70 }; 71 72 struct Cpp17InputRange { 73 struct sentinel { 74 friend constexpr bool operator==(sentinel, cpp17_input_iterator<int*> iter) { return base(iter) == globalBuff + 8; } 75 friend constexpr std::ptrdiff_t operator-(sentinel, cpp17_input_iterator<int*>) { return -8; } 76 friend constexpr std::ptrdiff_t operator-(cpp17_input_iterator<int*>, sentinel) { return 8; } 77 }; 78 79 constexpr cpp17_input_iterator<int*> begin() const { 80 return cpp17_input_iterator<int*>(globalBuff); 81 } 82 constexpr sentinel end() const { return {}; } 83 }; 84 85 struct Cpp20InputRange { 86 struct sentinel { 87 friend constexpr bool operator==(sentinel, const cpp20_input_iterator<int*> &iter) { return base(iter) == globalBuff + 8; } 88 friend constexpr std::ptrdiff_t operator-(sentinel, const cpp20_input_iterator<int*>&) { return -8; } 89 }; 90 91 constexpr cpp20_input_iterator<int*> begin() const { 92 return cpp20_input_iterator<int*>(globalBuff); 93 } 94 constexpr sentinel end() const { return {}; } 95 }; 96 97 template<> 98 inline constexpr bool std::ranges::enable_borrowed_range<Cpp20InputRange> = true; 99 100 template<class R> 101 concept EmptyIsInvocable = requires (std::ranges::ref_view<R> view) { view.empty(); }; 102 103 template<class R> 104 concept SizeIsInvocable = requires (std::ranges::ref_view<R> view) { view.size(); }; 105 106 template<class R> 107 concept DataIsInvocable = requires (std::ranges::ref_view<R> view) { view.data(); }; 108 109 // Testing ctad. 110 static_assert(std::same_as<decltype(std::ranges::ref_view(std::declval<Range&>())), 111 std::ranges::ref_view<Range>>); 112 113 constexpr bool test() { 114 { 115 // ref_view::base 116 Range range; 117 std::ranges::ref_view<Range> view{range}; 118 assert(view.begin() == globalBuff); 119 view.base() = Range{2}; 120 assert(view.begin() == globalBuff + 2); 121 } 122 123 { 124 // ref_view::begin 125 Range range1; 126 std::ranges::ref_view<Range> view1 = range1; 127 assert(view1.begin() == globalBuff); 128 129 ForwardRange range2; 130 std::ranges::ref_view<ForwardRange> view2 = range2; 131 assert(base(view2.begin()) == globalBuff); 132 133 Cpp17InputRange range3; 134 std::ranges::ref_view<Cpp17InputRange> view3 = range3; 135 assert(base(view3.begin()) == globalBuff); 136 137 Cpp20InputRange range4; 138 std::ranges::ref_view<Cpp20InputRange> view4 = range4; 139 assert(base(view4.begin()) == globalBuff); 140 } 141 142 { 143 // ref_view::end 144 Range range1; 145 std::ranges::ref_view<Range> view1 = range1; 146 assert(view1.end() == globalBuff + 8); 147 148 ForwardRange range2; 149 std::ranges::ref_view<ForwardRange> view2 = range2; 150 assert(base(view2.end()) == globalBuff + 8); 151 152 Cpp17InputRange range3; 153 std::ranges::ref_view<Cpp17InputRange> view3 = range3; 154 assert(view3.end() == cpp17_input_iterator(globalBuff + 8)); 155 156 Cpp20InputRange range4; 157 std::ranges::ref_view<Cpp20InputRange> view4 = range4; 158 assert(view4.end() == cpp20_input_iterator(globalBuff + 8)); 159 } 160 161 { 162 // ref_view::empty 163 Range range{8}; 164 std::ranges::ref_view<Range> view1 = range; 165 assert(view1.empty()); 166 167 ForwardRange range2; 168 std::ranges::ref_view<ForwardRange> view2 = range2; 169 assert(!view2.empty()); 170 171 static_assert(!EmptyIsInvocable<Cpp17InputRange>); 172 static_assert(!EmptyIsInvocable<Cpp20InputRange>); 173 } 174 175 { 176 // ref_view::size 177 Range range1{8}; 178 std::ranges::ref_view<Range> view1 = range1; 179 assert(view1.size() == 0); 180 181 Range range2{2}; 182 std::ranges::ref_view<Range> view2 = range2; 183 assert(view2.size() == 6); 184 185 static_assert(!SizeIsInvocable<ForwardRange>); 186 } 187 188 { 189 // ref_view::data 190 Range range1; 191 std::ranges::ref_view<Range> view1 = range1; 192 assert(view1.data() == globalBuff); 193 194 Range range2{2}; 195 std::ranges::ref_view<Range> view2 = range2; 196 assert(view2.data() == globalBuff + 2); 197 198 static_assert(!DataIsInvocable<ForwardRange>); 199 } 200 201 return true; 202 } 203 204 int main(int, char**) { 205 test(); 206 static_assert(test()); 207 208 return 0; 209 } 210