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 | |
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 | |
170 | int main(int, char**) { |
171 | test(); |
172 | static_assert(test()); |
173 | |
174 | return 0; |
175 | } |
176 | |