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