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::reverse 14 15 #include <ranges> 16 17 #include <cassert> 18 #include <concepts> 19 #include <iterator> 20 #include <utility> 21 22 #include "types.h" 23 24 template <class View, class T> 25 concept CanBePiped = requires (View&& view, T&& t) { 26 { std::forward<View>(view) | std::forward<T>(t) }; 27 }; 28 29 constexpr bool test() { 30 int buf[] = {1, 2, 3}; 31 32 // views::reverse(x) is equivalent to x.base() if x is a reverse_view 33 { 34 { 35 BidirRange view(buf, buf + 3); 36 std::ranges::reverse_view<BidirRange> reversed(view); 37 std::same_as<BidirRange> auto result = std::views::reverse(reversed); 38 assert(result.begin_ == buf); 39 assert(result.end_ == buf + 3); 40 } 41 { 42 // Common use case is worth testing 43 BidirRange view(buf, buf + 3); 44 std::same_as<BidirRange> auto result = std::views::reverse(std::views::reverse(view)); 45 assert(result.begin_ == buf); 46 assert(result.end_ == buf + 3); 47 } 48 } 49 50 // views::reverse(x) is equivalent to subrange{end, begin, size} if x is a 51 // sized subrange over reverse iterators 52 { 53 using It = bidirectional_iterator<int*>; 54 using Subrange = std::ranges::subrange<It, It, std::ranges::subrange_kind::sized>; 55 56 using ReverseIt = std::reverse_iterator<It>; 57 using ReverseSubrange = std::ranges::subrange<ReverseIt, ReverseIt, std::ranges::subrange_kind::sized>; 58 59 { 60 BidirRange view(buf, buf + 3); 61 ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)), /* size */3); 62 std::same_as<Subrange> auto result = std::views::reverse(subrange); 63 assert(result.begin().base() == buf); 64 assert(result.end().base() == buf + 3); 65 } 66 { 67 // std::move into views::reverse 68 BidirRange view(buf, buf + 3); 69 ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)), /* size */3); 70 std::same_as<Subrange> auto result = std::views::reverse(std::move(subrange)); 71 assert(result.begin().base() == buf); 72 assert(result.end().base() == buf + 3); 73 } 74 { 75 // with a const subrange 76 BidirRange view(buf, buf + 3); 77 ReverseSubrange const subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view)), /* size */3); 78 std::same_as<Subrange> auto result = std::views::reverse(subrange); 79 assert(result.begin().base() == buf); 80 assert(result.end().base() == buf + 3); 81 } 82 } 83 84 // views::reverse(x) is equivalent to subrange{end, begin} if x is an 85 // unsized subrange over reverse iterators 86 { 87 using It = bidirectional_iterator<int*>; 88 using Subrange = std::ranges::subrange<It, It, std::ranges::subrange_kind::unsized>; 89 90 using ReverseIt = std::reverse_iterator<It>; 91 using ReverseSubrange = std::ranges::subrange<ReverseIt, ReverseIt, std::ranges::subrange_kind::unsized>; 92 93 { 94 BidirRange view(buf, buf + 3); 95 ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view))); 96 std::same_as<Subrange> auto result = std::views::reverse(subrange); 97 assert(result.begin().base() == buf); 98 assert(result.end().base() == buf + 3); 99 } 100 { 101 // std::move into views::reverse 102 BidirRange view(buf, buf + 3); 103 ReverseSubrange subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view))); 104 std::same_as<Subrange> auto result = std::views::reverse(std::move(subrange)); 105 assert(result.begin().base() == buf); 106 assert(result.end().base() == buf + 3); 107 } 108 { 109 // with a const subrange 110 BidirRange view(buf, buf + 3); 111 ReverseSubrange const subrange(ReverseIt(std::ranges::end(view)), ReverseIt(std::ranges::begin(view))); 112 std::same_as<Subrange> auto result = std::views::reverse(subrange); 113 assert(result.begin().base() == buf); 114 assert(result.end().base() == buf + 3); 115 } 116 } 117 118 // Otherwise, views::reverse(x) is equivalent to ranges::reverse_view{x} 119 { 120 BidirRange view(buf, buf + 3); 121 std::same_as<std::ranges::reverse_view<BidirRange>> auto result = std::views::reverse(view); 122 assert(result.begin().base().base() == buf + 3); 123 assert(result.end().base().base() == buf); 124 } 125 126 // Test that std::views::reverse is a range adaptor 127 { 128 // Test `v | views::reverse` 129 { 130 BidirRange view(buf, buf + 3); 131 std::same_as<std::ranges::reverse_view<BidirRange>> auto result = view | std::views::reverse; 132 assert(result.begin().base().base() == buf + 3); 133 assert(result.end().base().base() == buf); 134 } 135 136 // Test `adaptor | views::reverse` 137 { 138 BidirRange view(buf, buf + 3); 139 auto f = [](int i) { return i; }; 140 auto const partial = std::views::transform(f) | std::views::reverse; 141 using Result = std::ranges::reverse_view<std::ranges::transform_view<BidirRange, decltype(f)>>; 142 std::same_as<Result> auto result = partial(view); 143 assert(result.begin().base().base().base() == buf + 3); 144 assert(result.end().base().base().base() == buf); 145 } 146 147 // Test `views::reverse | adaptor` 148 { 149 BidirRange view(buf, buf + 3); 150 auto f = [](int i) { return i; }; 151 auto const partial = std::views::reverse | std::views::transform(f); 152 using Result = std::ranges::transform_view<std::ranges::reverse_view<BidirRange>, decltype(f)>; 153 std::same_as<Result> auto result = partial(view); 154 assert(result.begin().base().base().base() == buf + 3); 155 assert(result.end().base().base().base() == buf); 156 } 157 158 // Check SFINAE friendliness 159 { 160 struct NotABidirRange { }; 161 static_assert(!std::is_invocable_v<decltype(std::views::reverse)>); 162 static_assert(!std::is_invocable_v<decltype(std::views::reverse), NotABidirRange>); 163 static_assert( CanBePiped<BidirRange, decltype(std::views::reverse)>); 164 static_assert( CanBePiped<BidirRange&, decltype(std::views::reverse)>); 165 static_assert(!CanBePiped<NotABidirRange, decltype(std::views::reverse)>); 166 } 167 } 168 169 { 170 static_assert(std::same_as<decltype(std::views::reverse), decltype(std::ranges::views::reverse)>); 171 } 172 173 return true; 174 } 175 176 int main(int, char**) { 177 test(); 178 static_assert(test()); 179 180 return 0; 181 } 182