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