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 // <algorithm>
10 
11 // UNSUPPORTED: c++03, c++11, c++14, c++17
12 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
13 
14 // template<class T, class Proj = identity,
15 //          indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
16 //   constexpr const T& ranges::min(const T& a, const T& b, Comp comp = {}, Proj proj = {});
17 // template<copyable T, class Proj = identity,
18 //          indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
19 //   constexpr T ranges::min(initializer_list<T> r, Comp comp = {}, Proj proj = {});
20 // template<input_range R, class Proj = identity,
21 //          indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
22 //   requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
23 //   constexpr range_value_t<R>
24 //     ranges::min(R&& r, Comp comp = {}, Proj proj = {});
25 
26 #include <algorithm>
27 #include <array>
28 #include <cassert>
29 #include <functional>
30 #include <ranges>
31 
32 #include "almost_satisfies_types.h"
33 #include "test_iterators.h"
34 #include "test_macros.h"
35 
36 template <class T>
37 concept HasMinR = requires { std::ranges::min(std::declval<T>()); };
38 
39 struct NoLessThanOp {};
40 struct NotTotallyOrdered {
41   int i;
operator <NotTotallyOrdered42   bool operator<(const NotTotallyOrdered& o) const { return i < o.i; }
43 };
44 
45 struct Movable {
46   Movable& operator=(Movable&&) = default;
47   Movable(Movable&&) = default;
48   Movable(const Movable&) = delete;
49 };
50 
51 static_assert(!HasMinR<int>);
52 
53 static_assert(HasMinR<int(&)[10]>);
54 static_assert(HasMinR<int(&&)[10]>);
55 static_assert(!HasMinR<NoLessThanOp(&)[10]>);
56 static_assert(!HasMinR<NotTotallyOrdered(&)[10]>);
57 static_assert(!HasMinR<Movable(&)[10]>);
58 
59 static_assert(HasMinR<std::initializer_list<int>>);
60 static_assert(!HasMinR<std::initializer_list<NoLessThanOp>>);
61 static_assert(!HasMinR<std::initializer_list<NotTotallyOrdered>>);
62 static_assert(!HasMinR<std::initializer_list<Movable>>);
63 static_assert(!HasMinR<InputRangeNotDerivedFrom>);
64 static_assert(!HasMinR<InputRangeNotIndirectlyReadable>);
65 static_assert(!HasMinR<InputRangeNotInputOrOutputIterator>);
66 static_assert(!HasMinR<InputRangeNotSentinelSemiregular>);
67 static_assert(!HasMinR<InputRangeNotSentinelEqualityComparableWith>);
68 
69 template <class T, class U = T>
70 concept HasMin2 = requires { std::ranges::min(std::declval<T>(), std::declval<U>()); };
71 
72 static_assert(HasMin2<int>);
73 static_assert(!HasMin2<int, long>);
74 
75 static_assert(std::is_same_v<decltype(std::ranges::min(1, 2)), const int&>);
76 
test_2_arguments()77 constexpr void test_2_arguments() {
78   assert(std::ranges::min(1, 2) == 1);
79   assert(std::ranges::min(2, 1) == 1);
80   // test comparator
81   assert(std::ranges::min(1, 2, std::ranges::greater{}) == 2);
82   // test projection
83   assert(std::ranges::min(1, 2, std::ranges::less{}, [](int i){ return i == 1 ? 10 : i; }) == 2);
84 
85   { // check that std::invoke is used
86     struct S { int i; };
87     S a[3] = { S{2}, S{1}, S{3} };
88     decltype(auto) ret = std::ranges::min(a[0], a[1], {}, &S::i);
89     ASSERT_SAME_TYPE(decltype(ret), const S&);
90     assert(&ret == &a[1]);
91     assert(ret.i == 1);
92   }
93 
94   { // check that pointers are compared and not a range
95     int i;
96     int* a[] = {&i, &i + 1};
97     auto ret = std::ranges::min(a[0], a[1]);
98     assert(ret == &i);
99   }
100 
101   { // test predicate and projection count
102     int compares = 0;
103     int projections = 0;
104     auto comparator = [&](int x, int y) {
105       ++compares;
106       return x < y;
107     };
108     auto projection = [&](int x) {
109       ++projections;
110       return x;
111     };
112     auto ret = std::ranges::min(1, 2, comparator, projection);
113     assert(ret == 1);
114     assert(compares == 1);
115     assert(projections == 2);
116   }
117 
118   { // check that the first argument is returned
119     struct S { int check; int other; };
120     auto ret = std::ranges::min(S {0, 1}, S {0, 2}, {}, &S::check);
121     assert(ret.other == 1);
122   }
123 }
124 
test_initializer_list()125 constexpr void test_initializer_list() {
126   {
127     // test projection
128     auto proj = [](int i) { return i == 5 ? -100 : i; };
129     int ret = std::ranges::min({7, 6, 9, 3, 5, 1, 2, 4}, std::ranges::less{}, proj);
130     assert(ret == 5);
131   }
132 
133   {
134     // test comparator
135     int ret = std::ranges::min({7, 6, 9, 3, 5, 1, 2, 4}, std::ranges::greater{});
136     assert(ret == 9);
137   }
138 
139   {
140     int compares = 0;
141     int projections = 0;
142     auto comparator = [&](int a, int b) {
143       ++compares;
144       return a < b;
145     };
146     auto projection = [&](int a) {
147       ++projections;
148       return a;
149     };
150     std::same_as<int> decltype(auto) ret = std::ranges::min({1, 2, 3}, comparator, projection);
151     assert(ret == 1);
152     assert(compares == 2);
153     assert(projections == 4);
154   }
155 
156   {
157     struct S { int i; };
158     decltype(auto) ret = std::ranges::min({ S{2}, S{1}, S{3} }, {}, &S::i);
159     ASSERT_SAME_TYPE(decltype(ret), S);
160     assert(ret.i == 1);
161   }
162 
163   {
164     int a[] = {7, 6, 9, 3, 5, 1, 2, 4};
165     using It = cpp20_input_iterator<int*>;
166     using Sent = sentinel_wrapper<It>;
167     auto range = std::ranges::subrange(It(a), Sent(It(a + 8)));
168     auto ret = std::ranges::min(range);
169     assert(ret == 1);
170   }
171 }
172 
173 template <class It, class Sent = It>
test_range_types()174 constexpr void test_range_types() {
175   int a[] = {7, 6, 9, 3, 5, 1, 2, 4};
176   auto range = std::ranges::subrange(It(a), Sent(It(a + 8)));
177   int ret = std::ranges::min(range);
178   assert(ret == 1);
179 }
180 
test_range()181 constexpr void test_range() {
182   { // check that all range types work
183     test_range_types<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>();
184     test_range_types<forward_iterator<int*>>();
185     test_range_types<bidirectional_iterator<int*>>();
186     test_range_types<random_access_iterator<int*>>();
187     test_range_types<contiguous_iterator<int*>>();
188   }
189 
190   int a[] = {7, 6, 9, 3, 5, 1, 2, 4};
191   {
192     // test projection
193     auto proj = [](int& i) { return i == 5 ? -100 : i; };
194     int ret = std::ranges::min(a, std::ranges::less{}, proj);
195     assert(ret == 5);
196   }
197 
198   {
199     // test comparator
200     int ret = std::ranges::min(a, std::ranges::greater{});
201     assert(ret == 9);
202   }
203 
204   { // check that predicate and projection call counts are correct
205     int compares = 0;
206     int projections = 0;
207     auto comparator = [&](int x, int y) {
208       ++compares;
209       return x < y;
210     };
211     auto projection = [&](int x) {
212       ++projections;
213       return x;
214     };
215     std::same_as<int> decltype(auto) ret = std::ranges::min(std::array{1, 2, 3}, comparator, projection);
216     assert(ret == 1);
217     assert(compares == 2);
218     assert(projections == 4);
219   }
220 
221   { // check that std::invoke is used
222     struct S { int i; };
223     S b[3] = { S{2}, S{1}, S{3} };
224     std::same_as<S> decltype(auto) ret = std::ranges::min(b, {}, &S::i);
225     assert(ret.i == 1);
226   }
227 
228   { // check that the first smallest element is returned
229     { // where the first element is the smallest
230       struct S { int check; int other; };
231       S b[] = { S{0, 1}, S{1, 2}, S{0, 3} };
232       auto ret = std::ranges::min(b, {}, &S::check);
233       assert(ret.check == 0);
234       assert(ret.other == 1);
235     }
236     { // where the first element isn't the smallest
237       struct S { int check; int other; };
238       S b[] = { S{2, 1}, S{0, 2}, S{0, 3} };
239       auto ret = std::ranges::min(b, {}, &S::check);
240       assert(ret.check == 0);
241       assert(ret.other == 2);
242     }
243   }
244 }
245 
test()246 constexpr bool test() {
247   test_2_arguments();
248   test_initializer_list();
249   test_range();
250 
251   return true;
252 }
253 
main(int,char **)254 int main(int, char**) {
255   test();
256   static_assert(test());
257 
258   return 0;
259 }
260