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

source code of libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp