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