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