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<class R> 13 // concept viewable_range; 14 15 #include <ranges> 16 #include <type_traits> 17 18 #include "test_iterators.h" 19 #include "test_range.h" 20 21 // The constraints we have in viewable_range are: 22 // range<T> 23 // view<remove_cvref_t<T>> 24 // constructible_from<remove_cvref_t<T>, T> 25 // lvalue_reference_t<T> || movable<remove_reference_t<T>> 26 // is-initializer-list<T> 27 // 28 // We test all the relevant combinations of satisfying/not satisfying those constraints. 29 30 // viewable_range<T> is not satisfied for (range=false, view=*, constructible_from=*, lvalue-or-movable=*) 31 struct T1 { }; 32 static_assert(!std::ranges::range<T1>); 33 34 static_assert(!std::ranges::viewable_range<T1>); 35 static_assert(!std::ranges::viewable_range<T1&>); 36 static_assert(!std::ranges::viewable_range<T1&&>); 37 static_assert(!std::ranges::viewable_range<T1 const>); 38 static_assert(!std::ranges::viewable_range<T1 const&>); 39 static_assert(!std::ranges::viewable_range<T1 const&&>); 40 41 // viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, lvalue-or-movable=true) 42 struct T2 : test_range<cpp20_input_iterator>, std::ranges::view_base { 43 T2(T2 const&) = default; 44 }; 45 static_assert(std::ranges::range<T2>); 46 static_assert(std::ranges::view<T2>); 47 static_assert(std::constructible_from<T2, T2>); 48 49 static_assert(std::ranges::viewable_range<T2>); 50 static_assert(std::ranges::viewable_range<T2&>); 51 static_assert(std::ranges::viewable_range<T2&&>); 52 static_assert(std::ranges::viewable_range<T2 const>); 53 static_assert(std::ranges::viewable_range<T2 const&>); 54 static_assert(std::ranges::viewable_range<T2 const&&>); 55 56 // viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, lvalue-or-movable=false) 57 struct T3 : test_range<cpp20_input_iterator>, std::ranges::view_base { 58 T3(T3 const&) = default; 59 }; 60 static_assert(std::ranges::range<T3>); 61 static_assert(std::ranges::view<T3>); 62 static_assert(std::constructible_from<T3, T3>); 63 64 static_assert(std::ranges::viewable_range<T3>); 65 static_assert(std::ranges::viewable_range<T3&>); 66 static_assert(std::ranges::viewable_range<T3&&>); 67 static_assert(std::ranges::viewable_range<T3 const>); 68 static_assert(std::ranges::viewable_range<T3 const&>); 69 static_assert(std::ranges::viewable_range<T3 const&&>); 70 71 // viewable_range<T> is not satisfied for (range=true, view=true, constructible_from=false, lvalue-or-movable=true) 72 struct T4 : test_range<cpp20_input_iterator>, std::ranges::view_base { 73 T4(T4 const&) = delete; 74 T4(T4&&) = default; // necessary to model view 75 T4& operator=(T4&&) = default; // necessary to model view 76 }; 77 static_assert(std::ranges::range<T4 const&>); 78 static_assert(std::ranges::view<std::remove_cvref_t<T4 const&>>); 79 static_assert(!std::constructible_from<std::remove_cvref_t<T4 const&>, T4 const&>); 80 81 static_assert(!std::ranges::viewable_range<T4 const&>); 82 83 // A type that satisfies (range=true, view=true, constructible_from=false, lvalue-or-movable=false) can't be formed, 84 // because views are movable by definition 85 86 // viewable_range<T> is satisfied for (range=true, view=false, constructible_from=true, lvalue-or-movable=true)... 87 struct T5 : test_range<cpp20_input_iterator> { }; 88 static_assert( std::ranges::range<T5>); 89 static_assert(!std::ranges::view<T5>); 90 static_assert( std::constructible_from<T5, T5>); 91 static_assert( std::movable<T5>); 92 static_assert(!std::movable<const T5>); 93 94 static_assert( std::ranges::viewable_range<T5>); // movable 95 static_assert( std::ranges::viewable_range<T5&>); // movable 96 static_assert( std::ranges::viewable_range<T5&&>); // movable 97 static_assert(!std::ranges::viewable_range<const T5>); 98 static_assert( std::ranges::viewable_range<const T5&>); // lvalue 99 static_assert(!std::ranges::viewable_range<const T5&&>); 100 101 // ...but not if the (non-view, lvalue-or-movable) range is an initializer_list. 102 static_assert( std::ranges::range<std::initializer_list<int>>); 103 static_assert(!std::ranges::view<std::initializer_list<int>>); 104 static_assert( std::constructible_from<std::initializer_list<int>, std::initializer_list<int>>); 105 static_assert( std::movable<std::initializer_list<int>>); 106 107 static_assert(!std::ranges::viewable_range<std::initializer_list<int>>); 108 static_assert( std::ranges::viewable_range<std::initializer_list<int>&>); 109 static_assert(!std::ranges::viewable_range<std::initializer_list<int>&&>); 110 static_assert(!std::ranges::viewable_range<std::initializer_list<int> const>); 111 static_assert( std::ranges::viewable_range<std::initializer_list<int> const&>); 112 static_assert(!std::ranges::viewable_range<std::initializer_list<int> const&&>); 113 114 // viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=true, lvalue-or-movable=false) 115 struct T6 : test_range<cpp20_input_iterator> { T6(T6&&); T6& operator=(T6&&) = delete; }; 116 static_assert( std::ranges::range<T6>); 117 static_assert(!std::ranges::view<T6>); 118 static_assert( std::constructible_from<T6, T6>); 119 static_assert(!std::movable<T6>); 120 121 static_assert(!std::ranges::viewable_range<T6>); 122 static_assert( std::ranges::viewable_range<T6&>); // lvalue 123 static_assert(!std::ranges::viewable_range<T6&&>); 124 static_assert(!std::ranges::viewable_range<const T6>); 125 static_assert( std::ranges::viewable_range<const T6&>); // lvalue 126 static_assert(!std::ranges::viewable_range<const T6&&>); 127 128 // viewable_range<T> is satisfied for (range=true, view=false, constructible_from=false, lvalue-or-movable=true) 129 struct T7 : test_range<cpp20_input_iterator> { 130 T7(T7 const&) = delete; 131 }; 132 static_assert(std::ranges::range<T7&>); 133 static_assert(!std::ranges::view<std::remove_cvref_t<T7&>>); 134 static_assert(!std::constructible_from<std::remove_cvref_t<T7&>, T7&>); 135 136 static_assert(!std::ranges::viewable_range<T7>); 137 static_assert( std::ranges::viewable_range<T7&>); 138 static_assert(!std::ranges::viewable_range<T7&&>); 139 static_assert(!std::ranges::viewable_range<const T7>); 140 static_assert( std::ranges::viewable_range<const T7&>); 141 static_assert(!std::ranges::viewable_range<const T7&&>); 142 143 // viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=false, lvalue-or-movable=false) 144 struct T8 : test_range<cpp20_input_iterator> { 145 T8(T8 const&) = delete; 146 }; 147 static_assert(std::ranges::range<T8>); 148 static_assert(!std::ranges::view<T8>); 149 static_assert(!std::constructible_from<T8, T8>); 150 151 static_assert(!std::ranges::viewable_range<T8>); 152 static_assert( std::ranges::viewable_range<T8&>); 153 static_assert(!std::ranges::viewable_range<T8&&>); 154 static_assert(!std::ranges::viewable_range<const T8>); 155 static_assert( std::ranges::viewable_range<const T8&>); 156 static_assert(!std::ranges::viewable_range<const T8&&>); 157 158 // Test with a few degenerate types 159 static_assert(!std::ranges::viewable_range<void>); 160 static_assert(!std::ranges::viewable_range<int>); 161 static_assert(!std::ranges::viewable_range<int (*)(char)>); 162 static_assert(!std::ranges::viewable_range<int[]>); 163 static_assert(!std::ranges::viewable_range<int[10]>); 164 static_assert(!std::ranges::viewable_range<int(&)[]>); // not a range 165 static_assert( std::ranges::viewable_range<int(&)[10]>); // OK, lvalue 166 static_assert(!std::ranges::viewable_range<int(&&)[]>); 167 static_assert(!std::ranges::viewable_range<int(&&)[10]>); 168 169 // Test ADL-proofing. 170 struct Incomplete; 171 template<class T> struct Holder { T t; }; 172 173 static_assert(!std::ranges::viewable_range<Holder<Incomplete>*>); 174 static_assert(!std::ranges::viewable_range<Holder<Incomplete>*&>); 175 static_assert(!std::ranges::viewable_range<Holder<Incomplete>*&&>); 176 static_assert(!std::ranges::viewable_range<Holder<Incomplete>* const>); 177 static_assert(!std::ranges::viewable_range<Holder<Incomplete>* const&>); 178 static_assert(!std::ranges::viewable_range<Holder<Incomplete>* const&&>); 179 180 static_assert(!std::ranges::viewable_range<Holder<Incomplete>*[10]>); 181 static_assert( std::ranges::viewable_range<Holder<Incomplete>*(&)[10]>); 182 static_assert(!std::ranges::viewable_range<Holder<Incomplete>*(&&)[10]>); 183 static_assert(!std::ranges::viewable_range<Holder<Incomplete>* const[10]>); 184 static_assert( std::ranges::viewable_range<Holder<Incomplete>* const(&)[10]>); 185 static_assert(!std::ranges::viewable_range<Holder<Incomplete>* const(&&)[10]>); 186