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