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-has-no-incomplete-ranges 11 12 // std::views::all; 13 14 #include <ranges> 15 16 #include <cassert> 17 #include <concepts> 18 #include <type_traits> 19 #include <utility> 20 21 #include "test_macros.h" 22 #include "test_iterators.h" 23 24 int globalBuff[8]; 25 26 template<bool IsNoexcept> 27 struct View : std::ranges::view_base { 28 int start_ = 0; 29 explicit View() noexcept(IsNoexcept) = default; 30 constexpr explicit View(int start) : start_(start) {} 31 View(View&&) noexcept(IsNoexcept) = default; 32 View& operator=(View&&) noexcept(IsNoexcept) = default; 33 constexpr int* begin() const { return globalBuff + start_; } 34 constexpr int* end() const { return globalBuff + 8; } 35 }; 36 static_assert(std::ranges::view<View<true>>); 37 static_assert(std::ranges::view<View<false>>); 38 39 template<bool IsNoexcept> 40 struct CopyableView : std::ranges::view_base { 41 int start_ = 0; 42 explicit CopyableView() noexcept(IsNoexcept) = default; 43 CopyableView(CopyableView const&) noexcept(IsNoexcept) = default; 44 CopyableView& operator=(CopyableView const&) noexcept(IsNoexcept) = default; 45 constexpr explicit CopyableView(int start) noexcept : start_(start) {} 46 constexpr int* begin() const { return globalBuff + start_; } 47 constexpr int* end() const { return globalBuff + 8; } 48 }; 49 static_assert(std::ranges::view<CopyableView<true>>); 50 static_assert(std::ranges::view<CopyableView<false>>); 51 52 struct MoveOnlyView : std::ranges::view_base{ 53 MoveOnlyView() = default; 54 MoveOnlyView(const MoveOnlyView&) = delete; 55 MoveOnlyView& operator=(const MoveOnlyView&) = delete; 56 MoveOnlyView(MoveOnlyView&&) = default; 57 MoveOnlyView& operator=(MoveOnlyView&&) = default; 58 59 int* begin() const; 60 int* end() const; 61 }; 62 63 struct Range { 64 int start_; 65 constexpr explicit Range(int start) noexcept : start_(start) {} 66 constexpr int* begin() const { return globalBuff + start_; } 67 constexpr int* end() const { return globalBuff + 8; } 68 }; 69 70 struct BorrowableRange { 71 int start_; 72 constexpr explicit BorrowableRange(int start) noexcept : start_(start) {} 73 constexpr int* begin() const { return globalBuff + start_; } 74 constexpr int* end() const { return globalBuff + 8; } 75 }; 76 template<> 77 inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true; 78 79 struct RandomAccessRange { 80 constexpr auto begin() { return random_access_iterator<int*>(globalBuff); } 81 constexpr auto end() { return sized_sentinel(random_access_iterator<int*>(globalBuff + 8)); } 82 }; 83 template<> 84 inline constexpr bool std::ranges::enable_borrowed_range<RandomAccessRange> = true; 85 86 template <class View, class T> 87 concept CanBePiped = requires (View&& view, T&& t) { 88 { std::forward<View>(view) | std::forward<T>(t) }; 89 }; 90 91 constexpr bool test() { 92 { 93 ASSERT_SAME_TYPE(decltype(std::views::all(View<true>())), View<true>); 94 static_assert(noexcept(std::views::all(View<true>()))); 95 static_assert(!noexcept(std::views::all(View<false>()))); 96 97 auto viewCopy = std::views::all(View<true>(2)); 98 ASSERT_SAME_TYPE(decltype(viewCopy), View<true>); 99 assert(std::ranges::begin(viewCopy) == globalBuff + 2); 100 assert(std::ranges::end(viewCopy) == globalBuff + 8); 101 } 102 103 { 104 ASSERT_SAME_TYPE(decltype(std::views::all(std::declval<const CopyableView<true>&>())), CopyableView<true>); 105 static_assert(noexcept(std::views::all(CopyableView<true>()))); 106 static_assert(!noexcept(std::views::all(CopyableView<false>()))); 107 108 CopyableView<true> view(2); 109 auto viewCopy = std::views::all(view); 110 ASSERT_SAME_TYPE(decltype(viewCopy), CopyableView<true>); 111 assert(std::ranges::begin(viewCopy) == globalBuff + 2); 112 assert(std::ranges::end(viewCopy) == globalBuff + 8); 113 } 114 115 { 116 Range range(2); 117 auto ref = std::views::all(range); 118 ASSERT_SAME_TYPE(decltype(ref), std::ranges::ref_view<Range>); 119 assert(std::ranges::begin(ref) == globalBuff + 2); 120 assert(std::ranges::end(ref) == globalBuff + 8); 121 122 auto own = std::views::all(std::move(range)); 123 ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<Range>); 124 assert(std::ranges::begin(own) == globalBuff + 2); 125 assert(std::ranges::end(own) == globalBuff + 8); 126 127 auto cref = std::views::all(std::as_const(range)); 128 ASSERT_SAME_TYPE(decltype(cref), std::ranges::ref_view<const Range>); 129 assert(std::ranges::begin(cref) == globalBuff + 2); 130 assert(std::ranges::end(cref) == globalBuff + 8); 131 132 static_assert(!std::is_invocable_v<decltype(std::views::all), const Range&&>); 133 } 134 135 { 136 auto own = std::views::all(BorrowableRange(2)); 137 ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<BorrowableRange>); 138 assert(std::ranges::begin(own) == globalBuff + 2); 139 assert(std::ranges::end(own) == globalBuff + 8); 140 } 141 142 { 143 auto own = std::views::all(RandomAccessRange()); 144 ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view<RandomAccessRange>); 145 assert(base(std::ranges::begin(own)) == globalBuff); 146 assert(base(base(std::ranges::end(own))) == globalBuff + 8); 147 } 148 149 // Check SFINAE friendliness of the call operator 150 { 151 static_assert(!std::is_invocable_v<decltype(std::views::all)>); 152 static_assert(!std::is_invocable_v<decltype(std::views::all), RandomAccessRange, RandomAccessRange>); 153 154 // `views::all(v)` is expression equivalent to `decay-copy(v)` if the decayed type 155 // of `v` models `view`. If `v` is an lvalue-reference to a move-only view, the 156 // expression should be ill-formed because `v` is not copyable 157 static_assert(!std::is_invocable_v<decltype(std::views::all), MoveOnlyView&>); 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