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

source code of libcxx/test/std/algorithms/alg.sorting/alg.min.max/ranges.min.pass.cpp