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 // std::views::all; 14 15 #include <ranges> 16 17 #include <cassert> 18 #include <concepts> 19 #include <type_traits> 20 #include <utility> 21 22 #include "test_macros.h" 23 #include "test_iterators.h" 24 25 int globalBuff[8]; 26 27 template<bool IsNoexcept> 28 struct View : std::ranges::view_base { 29 int start_ = 0; 30 explicit View() noexcept(IsNoexcept) = default; 31 constexpr explicit View(int start) : start_(start) {} 32 View(View&&) noexcept(IsNoexcept) = default; 33 View& operator=(View&&) noexcept(IsNoexcept) = default; 34 friend constexpr int* begin(View& view) { return globalBuff + view.start_; } 35 friend constexpr int* begin(View const& view) { return globalBuff + view.start_; } 36 friend constexpr int* end(View&) { return globalBuff + 8; } 37 friend constexpr int* end(View const&) { return globalBuff + 8; } 38 }; 39 static_assert(std::ranges::view<View<true>>); 40 static_assert(std::ranges::view<View<false>>); 41 42 template<bool IsNoexcept> 43 struct CopyableView : std::ranges::view_base { 44 int start_ = 0; 45 explicit CopyableView() noexcept(IsNoexcept) = default; 46 CopyableView(CopyableView const&) noexcept(IsNoexcept) = default; 47 CopyableView& operator=(CopyableView const&) noexcept(IsNoexcept) = default; 48 constexpr explicit CopyableView(int start) noexcept : start_(start) {} 49 friend constexpr int* begin(CopyableView& view) { return globalBuff + view.start_; } 50 friend constexpr int* begin(CopyableView const& view) { return globalBuff + view.start_; } 51 friend constexpr int* end(CopyableView&) { return globalBuff + 8; } 52 friend constexpr int* end(CopyableView const&) { return globalBuff + 8; } 53 }; 54 static_assert(std::ranges::view<CopyableView<true>>); 55 static_assert(std::ranges::view<CopyableView<false>>); 56 57 struct Range { 58 int start_; 59 constexpr explicit Range(int start) noexcept : start_(start) {} 60 friend constexpr int* begin(Range const& range) { return globalBuff + range.start_; } 61 friend constexpr int* begin(Range& range) { return globalBuff + range.start_; } 62 friend constexpr int* end(Range const&) { return globalBuff + 8; } 63 friend constexpr int* end(Range&) { return globalBuff + 8; } 64 }; 65 66 struct BorrowableRange { 67 int start_; 68 constexpr explicit BorrowableRange(int start) noexcept : start_(start) {} 69 friend constexpr int* begin(BorrowableRange const& range) { return globalBuff + range.start_; } 70 friend constexpr int* begin(BorrowableRange& range) { return globalBuff + range.start_; } 71 friend constexpr int* end(BorrowableRange const&) { return globalBuff + 8; } 72 friend constexpr int* end(BorrowableRange&) { return globalBuff + 8; } 73 }; 74 template<> 75 inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true; 76 77 struct RandomAccessRange { 78 struct sentinel { 79 friend constexpr bool operator==(sentinel, const random_access_iterator<int*> rai) { return rai.base() == globalBuff + 8; } 80 friend constexpr std::ptrdiff_t operator-(sentinel, random_access_iterator<int*>) { return -8; } 81 friend constexpr std::ptrdiff_t operator-(random_access_iterator<int*>, sentinel) { return 8; } 82 }; 83 84 constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{globalBuff}; } 85 constexpr sentinel end() { return {}; } 86 }; 87 template<> 88 inline constexpr bool std::ranges::enable_borrowed_range<RandomAccessRange> = true; 89 90 template <class View, class T> 91 concept CanBePiped = requires (View&& view, T&& t) { 92 { std::forward<View>(view) | std::forward<T>(t) }; 93 }; 94 95 constexpr bool test() { 96 { 97 ASSERT_SAME_TYPE(decltype(std::views::all(View<true>())), View<true>); 98 static_assert(noexcept(std::views::all(View<true>()))); 99 static_assert(!noexcept(std::views::all(View<false>()))); 100 101 auto viewCopy = std::views::all(View<true>(2)); 102 ASSERT_SAME_TYPE(decltype(viewCopy), View<true>); 103 assert(std::ranges::begin(viewCopy) == globalBuff + 2); 104 assert(std::ranges::end(viewCopy) == globalBuff + 8); 105 } 106 107 { 108 ASSERT_SAME_TYPE(decltype(std::views::all(std::declval<const CopyableView<true>&>())), CopyableView<true>); 109 static_assert(noexcept(std::views::all(CopyableView<true>()))); 110 static_assert(!noexcept(std::views::all(CopyableView<false>()))); 111 112 CopyableView<true> view(2); 113 auto viewCopy = std::views::all(view); 114 ASSERT_SAME_TYPE(decltype(viewCopy), CopyableView<true>); 115 assert(std::ranges::begin(viewCopy) == globalBuff + 2); 116 assert(std::ranges::end(viewCopy) == globalBuff + 8); 117 } 118 119 { 120 Range range(2); 121 auto ref = std::views::all(range); 122 ASSERT_SAME_TYPE(decltype(ref), std::ranges::ref_view<Range>); 123 assert(std::ranges::begin(ref) == globalBuff + 2); 124 assert(std::ranges::end(ref) == globalBuff + 8); 125 126 static_assert(!std::is_invocable_v<decltype(std::views::all), Range>); 127 } 128 129 { 130 const Range range(2); 131 auto ref = std::views::all(range); 132 static_assert(!noexcept(std::views::all(range))); 133 ASSERT_SAME_TYPE(decltype(ref), std::ranges::ref_view<const Range>); 134 assert(std::ranges::begin(ref) == globalBuff + 2); 135 assert(std::ranges::end(ref) == globalBuff + 8); 136 } 137 138 { 139 auto subrange = std::views::all(BorrowableRange(2)); 140 static_assert(!noexcept(std::views::all(BorrowableRange(2)))); 141 ASSERT_SAME_TYPE(decltype(subrange), std::ranges::subrange<int*>); 142 assert(std::ranges::begin(subrange) == globalBuff + 2); 143 assert(std::ranges::end(subrange) == globalBuff + 8); 144 } 145 146 { 147 auto subrange = std::views::all(RandomAccessRange()); 148 ASSERT_SAME_TYPE(decltype(subrange), 149 std::ranges::subrange<random_access_iterator<int*>, RandomAccessRange::sentinel>); 150 assert(std::ranges::begin(subrange).base() == globalBuff); 151 assert(std::ranges::end(subrange) == std::ranges::begin(subrange) + 8); 152 } 153 154 // Check SFINAE friendliness of the call operator 155 { 156 static_assert(!std::is_invocable_v<decltype(std::views::all)>); 157 static_assert(!std::is_invocable_v<decltype(std::views::all), RandomAccessRange, RandomAccessRange>); 158 } 159 160 // Test that std::views::all is a range adaptor 161 { 162 // Test `v | views::all` 163 { 164 Range range(0); 165 auto result = range | std::views::all; 166 ASSERT_SAME_TYPE(decltype(result), std::ranges::ref_view<Range>); 167 assert(&result.base() == &range); 168 } 169 170 // Test `adaptor | views::all` 171 { 172 Range range(0); 173 auto f = [](int i) { return i; }; 174 auto const partial = std::views::transform(f) | std::views::all; 175 using Result = std::ranges::transform_view<std::ranges::ref_view<Range>, decltype(f)>; 176 std::same_as<Result> auto result = partial(range); 177 assert(&result.base().base() == &range); 178 } 179 180 // Test `views::all | adaptor` 181 { 182 Range range(0); 183 auto f = [](int i) { return i; }; 184 auto const partial = std::views::all | std::views::transform(f); 185 using Result = std::ranges::transform_view<std::ranges::ref_view<Range>, decltype(f)>; 186 std::same_as<Result> auto result = partial(range); 187 assert(&result.base().base() == &range); 188 } 189 190 { 191 struct NotAView { }; 192 static_assert( CanBePiped<Range&, decltype(std::views::all)>); 193 static_assert(!CanBePiped<NotAView, decltype(std::views::all)>); 194 } 195 } 196 197 { 198 static_assert(std::same_as<decltype(std::views::all), decltype(std::ranges::views::all)>); 199 } 200 201 return true; 202 } 203 204 int main(int, char**) { 205 test(); 206 static_assert(test()); 207 208 return 0; 209 } 210