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