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