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 
test()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 
main(int,char **)175 int main(int, char**) {
176   test();
177   static_assert(test());
178 
179   return 0;
180 }
181