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
1071909de3SMark de Wever // UNSUPPORTED: libcpp-has-no-incomplete-ranges
113001b48dSLouis Dionne 
123001b48dSLouis Dionne // template<class R>
133001b48dSLouis Dionne // concept viewable_range;
143001b48dSLouis Dionne 
153001b48dSLouis Dionne #include <ranges>
163001b48dSLouis Dionne #include <type_traits>
173001b48dSLouis Dionne 
183001b48dSLouis Dionne #include "test_iterators.h"
193001b48dSLouis Dionne #include "test_range.h"
203001b48dSLouis Dionne 
213001b48dSLouis Dionne // The constraints we have in viewable_range are:
223001b48dSLouis Dionne //  range<T>
233001b48dSLouis Dionne //  view<remove_cvref_t<T>>
243001b48dSLouis Dionne //  constructible_from<remove_cvref_t<T>, T>
2567151d02SArthur O'Dwyer //  lvalue_reference_t<T> || movable<remove_reference_t<T>>
2667151d02SArthur O'Dwyer //  is-initializer-list<T>
273001b48dSLouis Dionne //
283001b48dSLouis Dionne // We test all the relevant combinations of satisfying/not satisfying those constraints.
293001b48dSLouis Dionne 
3067151d02SArthur O'Dwyer // viewable_range<T> is not satisfied for (range=false, view=*, constructible_from=*, lvalue-or-movable=*)
313001b48dSLouis Dionne struct T1 { };
323001b48dSLouis Dionne static_assert(!std::ranges::range<T1>);
333001b48dSLouis Dionne 
343001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T1>);
353001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T1&>);
3667151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<T1&&>);
373001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T1 const>);
383001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T1 const&>);
3967151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<T1 const&&>);
403001b48dSLouis Dionne 
4167151d02SArthur O'Dwyer // viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, lvalue-or-movable=true)
423001b48dSLouis Dionne struct T2 : test_range<cpp20_input_iterator>, std::ranges::view_base {
433001b48dSLouis Dionne   T2(T2 const&) = default;
443001b48dSLouis Dionne };
453001b48dSLouis Dionne static_assert(std::ranges::range<T2>);
463001b48dSLouis Dionne static_assert(std::ranges::view<T2>);
473001b48dSLouis Dionne static_assert(std::constructible_from<T2, T2>);
483001b48dSLouis Dionne 
493001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T2>);
503001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T2&>);
5167151d02SArthur O'Dwyer static_assert(std::ranges::viewable_range<T2&&>);
523001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T2 const>);
533001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T2 const&>);
5467151d02SArthur O'Dwyer static_assert(std::ranges::viewable_range<T2 const&&>);
553001b48dSLouis Dionne 
5667151d02SArthur O'Dwyer // viewable_range<T> is satisfied for (range=true, view=true, constructible_from=true, lvalue-or-movable=false)
573001b48dSLouis Dionne struct T3 : test_range<cpp20_input_iterator>, std::ranges::view_base {
583001b48dSLouis Dionne   T3(T3 const&) = default;
593001b48dSLouis Dionne };
603001b48dSLouis Dionne static_assert(std::ranges::range<T3>);
613001b48dSLouis Dionne static_assert(std::ranges::view<T3>);
623001b48dSLouis Dionne static_assert(std::constructible_from<T3, T3>);
633001b48dSLouis Dionne 
643001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T3>);
653001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T3&>);
6667151d02SArthur O'Dwyer static_assert(std::ranges::viewable_range<T3&&>);
673001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T3 const>);
683001b48dSLouis Dionne static_assert(std::ranges::viewable_range<T3 const&>);
6967151d02SArthur O'Dwyer static_assert(std::ranges::viewable_range<T3 const&&>);
703001b48dSLouis Dionne 
7167151d02SArthur O'Dwyer // viewable_range<T> is not satisfied for (range=true, view=true, constructible_from=false, lvalue-or-movable=true)
723001b48dSLouis Dionne struct T4 : test_range<cpp20_input_iterator>, std::ranges::view_base {
733001b48dSLouis Dionne   T4(T4 const&) = delete;
743001b48dSLouis Dionne   T4(T4&&) = default;             // necessary to model view
753001b48dSLouis Dionne   T4& operator=(T4&&) = default;  // necessary to model view
763001b48dSLouis Dionne };
773001b48dSLouis Dionne static_assert(std::ranges::range<T4 const&>);
783001b48dSLouis Dionne static_assert(std::ranges::view<std::remove_cvref_t<T4 const&>>);
793001b48dSLouis Dionne static_assert(!std::constructible_from<std::remove_cvref_t<T4 const&>, T4 const&>);
803001b48dSLouis Dionne 
813001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T4 const&>);
823001b48dSLouis Dionne 
8367151d02SArthur O'Dwyer // A type that satisfies (range=true, view=true, constructible_from=false, lvalue-or-movable=false) can't be formed,
8467151d02SArthur O'Dwyer // because views are movable by definition
853001b48dSLouis Dionne 
8667151d02SArthur O'Dwyer // viewable_range<T> is satisfied for (range=true, view=false, constructible_from=true, lvalue-or-movable=true)...
873001b48dSLouis Dionne struct T5 : test_range<cpp20_input_iterator> { };
883001b48dSLouis Dionne static_assert( std::ranges::range<T5>);
893001b48dSLouis Dionne static_assert(!std::ranges::view<T5>);
903001b48dSLouis Dionne static_assert( std::constructible_from<T5, T5>);
9167151d02SArthur O'Dwyer static_assert( std::movable<T5>);
9267151d02SArthur O'Dwyer static_assert(!std::movable<const T5>);
933001b48dSLouis Dionne 
9467151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<T5>); // movable
9567151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<T5&>); // movable
9667151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<T5&&>); // movable
9767151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T5>);
9867151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<const T5&>); // lvalue
9967151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T5&&>);
1003001b48dSLouis Dionne 
10167151d02SArthur O'Dwyer // ...but not if the (non-view, lvalue-or-movable) range is an initializer_list.
10267151d02SArthur O'Dwyer static_assert( std::ranges::range<std::initializer_list<int>>);
10367151d02SArthur O'Dwyer static_assert(!std::ranges::view<std::initializer_list<int>>);
10467151d02SArthur O'Dwyer static_assert( std::constructible_from<std::initializer_list<int>, std::initializer_list<int>>);
10567151d02SArthur O'Dwyer static_assert( std::movable<std::initializer_list<int>>);
10667151d02SArthur O'Dwyer 
10767151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<std::initializer_list<int>>);
10867151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<std::initializer_list<int>&>);
10967151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<std::initializer_list<int>&&>);
11067151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<std::initializer_list<int> const>);
11167151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<std::initializer_list<int> const&>);
11267151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<std::initializer_list<int> const&&>);
11367151d02SArthur O'Dwyer 
11467151d02SArthur O'Dwyer // viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=true, lvalue-or-movable=false)
11567151d02SArthur O'Dwyer struct T6 : test_range<cpp20_input_iterator> { T6(T6&&); T6& operator=(T6&&) = delete; };
1163001b48dSLouis Dionne static_assert( std::ranges::range<T6>);
1173001b48dSLouis Dionne static_assert(!std::ranges::view<T6>);
1183001b48dSLouis Dionne static_assert( std::constructible_from<T6, T6>);
11967151d02SArthur O'Dwyer static_assert(!std::movable<T6>);
1203001b48dSLouis Dionne 
1213001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T6>);
12267151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<T6&>); // lvalue
12367151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<T6&&>);
12467151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T6>);
12567151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<const T6&>); // lvalue
12667151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T6&&>);
1273001b48dSLouis Dionne 
12867151d02SArthur O'Dwyer // viewable_range<T> is satisfied for (range=true, view=false, constructible_from=false, lvalue-or-movable=true)
1293001b48dSLouis Dionne struct T7 : test_range<cpp20_input_iterator> {
1303001b48dSLouis Dionne   T7(T7 const&) = delete;
1313001b48dSLouis Dionne };
1323001b48dSLouis Dionne static_assert(std::ranges::range<T7&>);
1333001b48dSLouis Dionne static_assert(!std::ranges::view<std::remove_cvref_t<T7&>>);
1343001b48dSLouis Dionne static_assert(!std::constructible_from<std::remove_cvref_t<T7&>, T7&>);
1353001b48dSLouis Dionne 
13667151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<T7>);
1373001b48dSLouis Dionne static_assert( std::ranges::viewable_range<T7&>);
13867151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<T7&&>);
13967151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T7>);
14067151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<const T7&>);
14167151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T7&&>);
1423001b48dSLouis Dionne 
14367151d02SArthur O'Dwyer // viewable_range<T> is not satisfied for (range=true, view=false, constructible_from=false, lvalue-or-movable=false)
1443001b48dSLouis Dionne struct T8 : test_range<cpp20_input_iterator> {
1453001b48dSLouis Dionne   T8(T8 const&) = delete;
1463001b48dSLouis Dionne };
1473001b48dSLouis Dionne static_assert(std::ranges::range<T8>);
1483001b48dSLouis Dionne static_assert(!std::ranges::view<T8>);
1493001b48dSLouis Dionne static_assert(!std::constructible_from<T8, T8>);
1503001b48dSLouis Dionne 
1513001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<T8>);
15267151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<T8&>);
15367151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<T8&&>);
15467151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T8>);
15567151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<const T8&>);
15667151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<const T8&&>);
1573001b48dSLouis Dionne 
1583001b48dSLouis Dionne // Test with a few degenerate types
1593001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<void>);
1603001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<int>);
1613001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<int (*)(char)>);
1623001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<int[]>);
1633001b48dSLouis Dionne static_assert(!std::ranges::viewable_range<int[10]>);
16467151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<int(&)[]>); // not a range
16567151d02SArthur O'Dwyer static_assert( std::ranges::viewable_range<int(&)[10]>); // OK, lvalue
16667151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<int(&&)[]>);
16767151d02SArthur O'Dwyer static_assert(!std::ranges::viewable_range<int(&&)[10]>);
168*bf150e8dSArthur O'Dwyer 
169*bf150e8dSArthur O'Dwyer // Test ADL-proofing.
170*bf150e8dSArthur O'Dwyer struct Incomplete;
171*bf150e8dSArthur O'Dwyer template<class T> struct Holder { T t; };
172*bf150e8dSArthur O'Dwyer 
173*bf150e8dSArthur O'Dwyer static_assert(!std::ranges::viewable_range<Holder<Incomplete>*>);
174*bf150e8dSArthur O'Dwyer static_assert(!std::ranges::viewable_range<Holder<Incomplete>*&>);
175*bf150e8dSArthur O'Dwyer static_assert(!std::ranges::viewable_range<Holder<Incomplete>*&&>);
176*bf150e8dSArthur O'Dwyer static_assert(!std::ranges::viewable_range<Holder<Incomplete>* const>);
177*bf150e8dSArthur O'Dwyer static_assert(!std::ranges::viewable_range<Holder<Incomplete>* const&>);
178*bf150e8dSArthur O'Dwyer static_assert(!std::ranges::viewable_range<Holder<Incomplete>* const&&>);
179*bf150e8dSArthur O'Dwyer 
180*bf150e8dSArthur O'Dwyer static_assert(!std::ranges::viewable_range<Holder<Incomplete>*[10]>);
181*bf150e8dSArthur O'Dwyer static_assert( std::ranges::viewable_range<Holder<Incomplete>*(&)[10]>);
182*bf150e8dSArthur O'Dwyer static_assert(!std::ranges::viewable_range<Holder<Incomplete>*(&&)[10]>);
183*bf150e8dSArthur O'Dwyer static_assert(!std::ranges::viewable_range<Holder<Incomplete>* const[10]>);
184*bf150e8dSArthur O'Dwyer static_assert( std::ranges::viewable_range<Holder<Incomplete>* const(&)[10]>);
185*bf150e8dSArthur O'Dwyer static_assert(!std::ranges::viewable_range<Holder<Incomplete>* const(&&)[10]>);
186