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<class R>
14 // concept viewable_range;
15 
16 #include <ranges>
17 #include <type_traits>
18 
19 #include "test_iterators.h"
20 #include "test_range.h"
21 
22 // The constraints we have in viewable_range are:
23 //  range<T>
24 //  view<remove_cvref_t<T>>
25 //  constructible_from<remove_cvref_t<T>, T>
26 //  borrowed_range<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=*, borrowed_range=*)
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 const>);
37 static_assert(!std::ranges::viewable_range<T1 const&>);
38 
39 // viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, borrowed_range=true)
40 struct T2 : test_range<cpp20_input_iterator>, std::ranges::view_base {
41   T2(T2 const&) = default;
42 };
43 template<> constexpr bool std::ranges::enable_borrowed_range<T2> = true;
44 static_assert(std::ranges::range<T2>);
45 static_assert(std::ranges::view<T2>);
46 static_assert(std::constructible_from<T2, T2>);
47 static_assert(std::ranges::borrowed_range<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 const>);
52 static_assert(std::ranges::viewable_range<T2 const&>);
53 
54 // viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, borrowed_range=false)
55 struct T3 : test_range<cpp20_input_iterator>, std::ranges::view_base {
56   T3(T3 const&) = default;
57 };
58 template<> constexpr bool std::ranges::enable_borrowed_range<T3> = false;
59 static_assert(std::ranges::range<T3>);
60 static_assert(std::ranges::view<T3>);
61 static_assert(std::constructible_from<T3, T3>);
62 static_assert(!std::ranges::borrowed_range<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 const>);
67 static_assert(std::ranges::viewable_range<T3 const&>);
68 
69 // viewable_range<T> is not satisfied for (range=true, view=true, constructible_from=false, borrowed_range=true)
70 struct T4 : test_range<cpp20_input_iterator>, std::ranges::view_base {
71   T4(T4 const&) = delete;
72   T4(T4&&) = default;             // necessary to model view
73   T4& operator=(T4&&) = default;  // necessary to model view
74 };
75 static_assert(std::ranges::range<T4 const&>);
76 static_assert(std::ranges::view<std::remove_cvref_t<T4 const&>>);
77 static_assert(!std::constructible_from<std::remove_cvref_t<T4 const&>, T4 const&>);
78 static_assert(std::ranges::borrowed_range<T4 const&>);
79 
80 static_assert(!std::ranges::viewable_range<T4 const&>);
81 
82 // A type that satisfies (range=true, view=true, constructible_from=false, borrowed_range=false) can't be formed
83 
84 // viewable_range<T> is satisfied for (range=true, view=false, constructible_from=true, borrowed_range=true)
85 struct T5 : test_range<cpp20_input_iterator> { };
86 template<> constexpr bool std::ranges::enable_borrowed_range<T5> = true;
87 static_assert(std::ranges::range<T5>);
88 static_assert(!std::ranges::view<T5>);
89 static_assert(std::constructible_from<T5, T5>);
90 static_assert(std::ranges::borrowed_range<T5>);
91 
92 static_assert(std::ranges::viewable_range<T5>);
93 
94 // viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=true, borrowed_range=false)
95 struct T6 : test_range<cpp20_input_iterator> { };
96 template<> constexpr bool std::ranges::enable_borrowed_range<T6> = false;
97 static_assert(std::ranges::range<T6>);
98 static_assert(!std::ranges::view<T6>);
99 static_assert(std::constructible_from<T6, T6>);
100 static_assert(!std::ranges::borrowed_range<T6>);
101 
102 static_assert(!std::ranges::viewable_range<T6>);
103 
104 // viewable_range<T> is satisfied for (range=true, view=false, constructible_from=false, borrowed_range=true)
105 struct T7 : test_range<cpp20_input_iterator> {
106   T7(T7 const&) = delete;
107 };
108 static_assert(std::ranges::range<T7&>);
109 static_assert(!std::ranges::view<std::remove_cvref_t<T7&>>);
110 static_assert(!std::constructible_from<std::remove_cvref_t<T7&>, T7&>);
111 static_assert(std::ranges::borrowed_range<T7&>);
112 
113 static_assert(std::ranges::viewable_range<T7&>);
114 
115 // A type that satisfies (range=true, view=false, constructible_from=false, borrowed_range=false) can't be formed
116 struct T8 : test_range<cpp20_input_iterator> {
117   T8(T8 const&) = delete;
118 };
119 static_assert(std::ranges::range<T8>);
120 static_assert(!std::ranges::view<T8>);
121 static_assert(!std::constructible_from<T8, T8>);
122 static_assert(!std::ranges::borrowed_range<T8>);
123 
124 static_assert(!std::ranges::viewable_range<T8>);
125 
126 // Test with a few degenerate types
127 static_assert(!std::ranges::viewable_range<void>);
128 static_assert(!std::ranges::viewable_range<int>);
129 static_assert(!std::ranges::viewable_range<int (*)(char)>);
130 static_assert(!std::ranges::viewable_range<int[]>);
131 static_assert(!std::ranges::viewable_range<int[10]>);
132 static_assert(!std::ranges::viewable_range<int(&)[]>); // unbounded array is not a range
133 static_assert( std::ranges::viewable_range<int(&)[10]>);
134