13001b48dSLouis Dionne //===----------------------------------------------------------------------===//
23001b48dSLouis Dionne //
33001b48dSLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43001b48dSLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
53001b48dSLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63001b48dSLouis Dionne //
73001b48dSLouis Dionne //===----------------------------------------------------------------------===//
83001b48dSLouis Dionne 
93001b48dSLouis Dionne // UNSUPPORTED: c++03, c++11, c++14, c++17
103001b48dSLouis Dionne // UNSUPPORTED: libcpp-no-concepts
1171909de3SMark de Wever // UNSUPPORTED: libcpp-has-no-incomplete-ranges
123001b48dSLouis Dionne 
133001b48dSLouis Dionne // template<class R>
143001b48dSLouis Dionne // concept viewable_range;
153001b48dSLouis Dionne 
163001b48dSLouis Dionne #include <ranges>
173001b48dSLouis Dionne #include <type_traits>
183001b48dSLouis Dionne 
193001b48dSLouis Dionne #include "test_iterators.h"
203001b48dSLouis Dionne #include "test_range.h"
213001b48dSLouis Dionne 
223001b48dSLouis Dionne // The constraints we have in viewable_range are:
233001b48dSLouis Dionne //  range<T>
243001b48dSLouis Dionne //  view<remove_cvref_t<T>>
253001b48dSLouis Dionne //  constructible_from<remove_cvref_t<T>, T>
26*67151d02SArthur O'Dwyer //  lvalue_reference_t<T> || movable<remove_reference_t<T>>
27*67151d02SArthur O'Dwyer //  is-initializer-list<T>
283001b48dSLouis Dionne //
293001b48dSLouis Dionne // We test all the relevant combinations of satisfying/not satisfying those constraints.
303001b48dSLouis Dionne 
31*67151d02SArthur O'Dwyer // viewable_range<T> is not satisfied for (range=false, view=*, constructible_from=*, lvalue-or-movable=*)
323001b48dSLouis Dionne struct T1 { };
333001b48dSLouis Dionne static_assert(!std::ranges::range<T1>);
343001b48dSLouis Dionne 
353001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T1>);
363001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T1&>);
37*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<T1&&>);
383001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T1 const>);
393001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T1 const&>);
40*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<T1 const&&>);
413001b48dSLouis Dionne 
42*67151d02SArthur O'Dwyer // viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, lvalue-or-movable=true)
433001b48dSLouis Dionne struct T2 : test_range<cpp20_input_iterator>, std::ranges::view_base {
443001b48dSLouis Dionne   T2(T2 const&) = default;
453001b48dSLouis Dionne };
463001b48dSLouis Dionne static_assert(std::ranges::range<T2>);
473001b48dSLouis Dionne static_assert(std::ranges::view<T2>);
483001b48dSLouis Dionne static_assert(std::constructible_from<T2, T2>);
493001b48dSLouis Dionne 
503001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T2>);
513001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T2&>);
52*67151d02SArthur O'Dwyer static_assert(std::ranges::viewable_range<T2&&>);
533001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T2 const>);
543001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T2 const&>);
55*67151d02SArthur O'Dwyer static_assert(std::ranges::viewable_range<T2 const&&>);
563001b48dSLouis Dionne 
57*67151d02SArthur O'Dwyer // viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, lvalue-or-movable=false)
583001b48dSLouis Dionne struct T3 : test_range<cpp20_input_iterator>, std::ranges::view_base {
593001b48dSLouis Dionne   T3(T3 const&) = default;
603001b48dSLouis Dionne };
613001b48dSLouis Dionne static_assert(std::ranges::range<T3>);
623001b48dSLouis Dionne static_assert(std::ranges::view<T3>);
633001b48dSLouis Dionne static_assert(std::constructible_from<T3, T3>);
643001b48dSLouis Dionne 
653001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T3>);
663001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T3&>);
67*67151d02SArthur O'Dwyer static_assert(std::ranges::viewable_range<T3&&>);
683001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T3 const>);
693001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T3 const&>);
70*67151d02SArthur O'Dwyer static_assert(std::ranges::viewable_range<T3 const&&>);
713001b48dSLouis Dionne 
72*67151d02SArthur O'Dwyer // viewable_range<T> is not satisfied for (range=true, view=true, constructible_from=false, lvalue-or-movable=true)
733001b48dSLouis Dionne struct T4 : test_range<cpp20_input_iterator>, std::ranges::view_base {
743001b48dSLouis Dionne   T4(T4 const&) = delete;
753001b48dSLouis Dionne   T4(T4&&) = default;             // necessary to model view
763001b48dSLouis Dionne   T4& operator=(T4&&) = default;  // necessary to model view
773001b48dSLouis Dionne };
783001b48dSLouis Dionne static_assert(std::ranges::range<T4 const&>);
793001b48dSLouis Dionne static_assert(std::ranges::view<std::remove_cvref_t<T4 const&>>);
803001b48dSLouis Dionne static_assert(!std::constructible_from<std::remove_cvref_t<T4 const&>, T4 const&>);
813001b48dSLouis Dionne 
823001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T4 const&>);
833001b48dSLouis Dionne 
84*67151d02SArthur O'Dwyer // A type that satisfies (range=true, view=true, constructible_from=false, lvalue-or-movable=false) can't be formed,
85*67151d02SArthur O'Dwyer // because views are movable by definition
863001b48dSLouis Dionne 
87*67151d02SArthur O'Dwyer // viewable_range<T> is satisfied for (range=true, view=false, constructible_from=true, lvalue-or-movable=true)...
883001b48dSLouis Dionne struct T5 : test_range<cpp20_input_iterator> { };
893001b48dSLouis Dionne static_assert( std::ranges::range<T5>);
903001b48dSLouis Dionne static_assert(!std::ranges::view<T5>);
913001b48dSLouis Dionne static_assert( std::constructible_from<T5, T5>);
92*67151d02SArthur O'Dwyer static_assert( std::movable<T5>);
93*67151d02SArthur O'Dwyer static_assert(!std::movable<const T5>);
943001b48dSLouis Dionne 
95*67151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<T5>); // movable
96*67151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<T5&>); // movable
97*67151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<T5&&>); // movable
98*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T5>);
99*67151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<const T5&>); // lvalue
100*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T5&&>);
1013001b48dSLouis Dionne 
102*67151d02SArthur O'Dwyer // ...but not if the (non-view, lvalue-or-movable) range is an initializer_list.
103*67151d02SArthur O'Dwyer static_assert( std::ranges::range<std::initializer_list<int>>);
104*67151d02SArthur O'Dwyer static_assert(!std::ranges::view<std::initializer_list<int>>);
105*67151d02SArthur O'Dwyer static_assert( std::constructible_from<std::initializer_list<int>, std::initializer_list<int>>);
106*67151d02SArthur O'Dwyer static_assert( std::movable<std::initializer_list<int>>);
107*67151d02SArthur O'Dwyer 
108*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<std::initializer_list<int>>);
109*67151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<std::initializer_list<int>&>);
110*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<std::initializer_list<int>&&>);
111*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<std::initializer_list<int> const>);
112*67151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<std::initializer_list<int> const&>);
113*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<std::initializer_list<int> const&&>);
114*67151d02SArthur O'Dwyer 
115*67151d02SArthur O'Dwyer // viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=true, lvalue-or-movable=false)
116*67151d02SArthur O'Dwyer struct T6 : test_range<cpp20_input_iterator> { T6(T6&&); T6& operator=(T6&&) = delete; };
1173001b48dSLouis Dionne static_assert( std::ranges::range<T6>);
1183001b48dSLouis Dionne static_assert(!std::ranges::view<T6>);
1193001b48dSLouis Dionne static_assert( std::constructible_from<T6, T6>);
120*67151d02SArthur O'Dwyer static_assert(!std::movable<T6>);
1213001b48dSLouis Dionne 
1223001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T6>);
123*67151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<T6&>); // lvalue
124*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<T6&&>);
125*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T6>);
126*67151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<const T6&>); // lvalue
127*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T6&&>);
1283001b48dSLouis Dionne 
129*67151d02SArthur O'Dwyer // viewable_range<T> is satisfied for (range=true, view=false, constructible_from=false, lvalue-or-movable=true)
1303001b48dSLouis Dionne struct T7 : test_range<cpp20_input_iterator> {
1313001b48dSLouis Dionne   T7(T7 const&) = delete;
1323001b48dSLouis Dionne };
1333001b48dSLouis Dionne static_assert(std::ranges::range<T7&>);
1343001b48dSLouis Dionne static_assert(!std::ranges::view<std::remove_cvref_t<T7&>>);
1353001b48dSLouis Dionne static_assert(!std::constructible_from<std::remove_cvref_t<T7&>, T7&>);
1363001b48dSLouis Dionne 
137*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<T7>);
1383001b48dSLouis Dionne static_assert( std::ranges::viewable_range<T7&>);
139*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<T7&&>);
140*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T7>);
141*67151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<const T7&>);
142*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T7&&>);
1433001b48dSLouis Dionne 
144*67151d02SArthur O'Dwyer // viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=false, lvalue-or-movable=false)
1453001b48dSLouis Dionne struct T8 : test_range<cpp20_input_iterator> {
1463001b48dSLouis Dionne   T8(T8 const&) = delete;
1473001b48dSLouis Dionne };
1483001b48dSLouis Dionne static_assert(std::ranges::range<T8>);
1493001b48dSLouis Dionne static_assert(!std::ranges::view<T8>);
1503001b48dSLouis Dionne static_assert(!std::constructible_from<T8, T8>);
1513001b48dSLouis Dionne 
1523001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T8>);
153*67151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<T8&>);
154*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<T8&&>);
155*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T8>);
156*67151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<const T8&>);
157*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T8&&>);
1583001b48dSLouis Dionne 
1593001b48dSLouis Dionne // Test with a few degenerate types
1603001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<void>);
1613001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<int>);
1623001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<int (*)(char)>);
1633001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<int[]>);
1643001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<int[10]>);
165*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<int(&)[]>); // not a range
166*67151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<int(&)[10]>); // OK, lvalue
167*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<int(&&)[]>);
168*67151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<int(&&)[10]>);
169