1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
11 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template<class T, class Proj = identity,
14 // indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
15 // constexpr const T& ranges::max(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::max(initializer_list<T> r, Comp comp = {}, Proj proj = {});
21 // template<input_range R, class Proj = identity,
22 // indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
23 // requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
24 // constexpr range_value_t<R>
25 // ranges::max(R&& r, Comp comp = {}, Proj proj = {});
33 #include "almost_satisfies_types.h"
34 #include "test_iterators.h"
35 #include "test_macros.h"
38 concept HasMaxR
= requires
{ std::ranges::max(std::declval
<T
>()); };
40 struct NoLessThanOp
{};
41 struct NotTotallyOrdered
{
43 bool operator<(const NotTotallyOrdered
& o
) const { return i
< o
.i
; }
47 Movable
& operator=(Movable
&&) = default;
48 Movable(Movable
&&) = default;
49 Movable(const Movable
&) = delete;
52 static_assert(!HasMaxR
<int>);
54 static_assert(HasMaxR
<int(&)[10]>);
55 static_assert(HasMaxR
<int(&&)[10]>);
56 static_assert(!HasMaxR
<NoLessThanOp(&)[10]>);
57 static_assert(!HasMaxR
<NotTotallyOrdered(&)[10]>);
58 static_assert(!HasMaxR
<Movable(&)[10]>);
60 static_assert(HasMaxR
<std::initializer_list
<int>>);
61 static_assert(!HasMaxR
<std::initializer_list
<NoLessThanOp
>>);
62 static_assert(!HasMaxR
<std::initializer_list
<NotTotallyOrdered
>>);
63 static_assert(!HasMaxR
<std::initializer_list
<Movable
>>);
64 static_assert(!HasMaxR
<InputRangeNotDerivedFrom
>);
65 static_assert(!HasMaxR
<InputRangeNotIndirectlyReadable
>);
66 static_assert(!HasMaxR
<InputRangeNotInputOrOutputIterator
>);
67 static_assert(!HasMaxR
<InputRangeNotSentinelSemiregular
>);
68 static_assert(!HasMaxR
<InputRangeNotSentinelEqualityComparableWith
>);
70 template <class T
, class U
= T
>
71 concept HasMax2
= requires
{ std::ranges::max(std::declval
<T
>(), std::declval
<U
>()); };
73 static_assert(HasMax2
<int>);
74 static_assert(!HasMax2
<int, long>);
76 static_assert(std::is_same_v
<decltype(std::ranges::max(1, 2)), const int&>);
78 constexpr void test_2_arguments() {
79 assert(std::ranges::max(1, 2) == 2);
80 assert(std::ranges::max(2, 1) == 2);
82 assert(std::ranges::max(1, 2, std::ranges::greater
{}) == 1);
84 assert(std::ranges::max(1, 2, std::ranges::less
{}, [](int i
){ return i
== 1 ? 10 : i
; }) == 1);
86 { // check that std::invoke is used
88 S a
[3] = { S
{2}, S
{1}, S
{3} };
89 decltype(auto) ret
= std::ranges::max(a
[0], a
[1], {}, &S::i
);
90 ASSERT_SAME_TYPE(decltype(ret
), const S
&);
91 assert(&ret
== &a
[0]);
95 { // check that pointers are compared and not a range
97 int* a
[] = {i
, i
+ 1};
98 auto ret
= std::ranges::max(a
[0], a
[1]);
102 { // test predicate and projection count
105 auto comparator
= [&](int x
, int y
) {
109 auto projection
= [&](int x
) {
113 auto ret
= std::ranges::max(1, 2, comparator
, projection
);
115 assert(compares
== 1);
116 assert(projections
== 2);
119 { // check that the first argument is returned
120 struct S
{ int check
; int other
; };
121 auto ret
= std::ranges::max(S
{0, 1}, S
{0, 2}, {}, &S::check
);
122 assert(ret
.other
== 1);
126 constexpr void test_initializer_list() {
128 auto proj
= [](int i
) { return i
== 5 ? 100 : i
; };
129 int ret
= std::ranges::max({7, 6, 9, 3, 5, 1, 2, 4}, {}, proj
);
134 int ret
= std::ranges::max({7, 6, 9, 3, 5, 1, 2, 4}, std::ranges::greater
{});
138 { // check that complexity requirements are met
141 auto comparator
= [&](int a
, int b
) {
145 auto projection
= [&](int a
) {
149 std::same_as
<int> decltype(auto) ret
= std::ranges::max({1, 2, 3}, comparator
, projection
);
151 assert(compares
== 2);
152 assert(projections
== 4);
155 { // check that std::invoke is used
157 std::same_as
<S
> decltype(auto) ret
= std::ranges::max({ S
{2}, S
{1}, S
{3} }, {}, &S::i
);
161 { // check that the first largest element is returned
162 { // where the first element is the largest
163 struct S
{ int check
; int other
; };
164 auto ret
= std::ranges::max({ S
{1, 1}, S
{0, 2}, S
{1, 3} }, {}, &S::check
);
165 assert(ret
.check
== 1);
166 assert(ret
.other
== 1);
168 { // where the first element isn't the largest
169 struct S
{ int check
; int other
; };
170 auto ret
= std::ranges::max({ S
{0, 1}, S
{1, 2}, S
{1, 3} }, {}, &S::check
);
171 assert(ret
.check
== 1);
172 assert(ret
.other
== 2);
177 template <class It
, class Sent
= It
>
178 constexpr void test_range_types() {
179 std::iter_value_t
<It
> a
[] = {7, 6, 9, 3, 5, 1, 2, 4};
180 auto range
= std::ranges::subrange(It(a
), Sent(It(a
+ 8)));
181 auto ret
= std::ranges::max(range
);
185 constexpr void test_range() {
186 // check that all range types work
188 struct NonTrivialInt
{
190 constexpr NonTrivialInt(int val
) : val_(val
) {}
191 constexpr NonTrivialInt(const NonTrivialInt
& other
) : val_(other
.val_
) {}
192 constexpr NonTrivialInt
& operator=(const NonTrivialInt
& other
) {
197 constexpr ~NonTrivialInt() {}
199 auto operator<=>(const NonTrivialInt
&) const = default;
202 auto call_with_sentinels
= []<class Iter
> {
203 if constexpr (std::forward_iterator
<Iter
>)
204 test_range_types
<Iter
, Iter
>();
205 test_range_types
<Iter
, sentinel_wrapper
<Iter
>>();
206 test_range_types
<Iter
, sized_sentinel
<Iter
>>();
209 types::for_each(types::cpp20_input_iterator_list
<int*>{}, call_with_sentinels
);
210 types::for_each(types::cpp20_input_iterator_list
<NonTrivialInt
*>{}, call_with_sentinels
);
213 int a
[] = {7, 6, 9, 3, 5, 1, 2, 4};
215 auto proj
= [](int& i
) { return i
== 5 ? 100 : i
; };
216 int ret
= std::ranges::max(a
, std::ranges::less
{}, proj
);
221 int ret
= std::ranges::max(a
, std::ranges::greater
{});
225 { // check that predicate and projection call counts are correct
228 auto comparator
= [&](int x
, int y
) {
232 auto projection
= [&](int x
) {
236 std::same_as
<int> decltype(auto) ret
= std::ranges::max(std::array
{1, 2, 3}, comparator
, projection
);
238 assert(compares
== 2);
239 assert(projections
== 4);
242 { // check that std::invoke is used
244 S b
[3] = { S
{2}, S
{1}, S
{3} };
245 std::same_as
<S
> decltype(auto) ret
= std::ranges::max(b
, {}, &S::i
);
249 { // check that the first largest element is returned
250 { // where the first element is the largest
251 struct S
{ int check
; int other
; };
252 S b
[] = { S
{1, 1}, S
{0, 2}, S
{1, 3} };
253 auto ret
= std::ranges::max(b
, {}, &S::check
);
254 assert(ret
.check
== 1);
255 assert(ret
.other
== 1);
257 { // where the first element isn't the largest
258 struct S
{ int check
; int other
; };
259 S b
[] = { S
{0, 1}, S
{1, 2}, S
{1, 3} };
260 auto ret
= std::ranges::max(b
, {}, &S::check
);
261 assert(ret
.check
== 1);
262 assert(ret
.other
== 2);
267 constexpr bool test() {
269 test_initializer_list();
275 int main(int, char**) {
277 static_assert(test());