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<forward_iterator I, sentinel_for<I> S, class Proj = identity,
14// indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
15// constexpr I ranges::min_element(I first, S last, Comp comp = {}, Proj proj = {});
16//
17// template<forward_range R, class Proj = identity,
18// indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
19// constexpr borrowed_iterator_t<R> ranges::min_element(R&& r, Comp comp = {}, Proj proj = {});
20
21#include <algorithm>
22#include <array>
23#include <cassert>
24#include <functional>
25#include <random>
26#include <ranges>
27
28#include "test_macros.h"
29#include "test_iterators.h"
30
31template <class T>
32concept HasMinElement = requires (T t) { std::ranges::min_element(t); };
33
34struct NoLessThanOp {};
35struct NotTotallyOrdered {
36 int i;
37 bool operator<(const NotTotallyOrdered& o) const { return i < o.i; }
38};
39
40static_assert(HasMinElement<std::array<int, 0>>);
41static_assert(!HasMinElement<int>);
42static_assert(!HasMinElement<NoLessThanOp>);
43static_assert(!HasMinElement<NotTotallyOrdered>);
44
45template <class Iter>
46constexpr void test_iterators(Iter first, Iter last) {
47 std::same_as<Iter> auto it = std::ranges::min_element(first, last);
48 if (first != last) {
49 for (Iter j = first; j != last; ++j)
50 assert(!(*j < *it));
51 } else {
52 assert(it == first);
53 }
54}
55
56template <class Range, class Iter>
57constexpr void test_range(Range&& rng, Iter begin, Iter end) {
58 std::same_as<Iter> auto it = std::ranges::min_element(std::forward<Range>(rng));
59 if (begin != end) {
60 for (Iter j = begin; j != end; ++j)
61 assert(!(*j < *it));
62 } else {
63 assert(it == begin);
64 }
65}
66
67template <class It>
68constexpr void test(std::initializer_list<int> a, int expected) {
69 const int* first = a.begin();
70 const int* last = a.end();
71 {
72 std::same_as<It> auto it = std::ranges::min_element(It(first), It(last));
73 assert(base(it) == first + expected);
74 }
75 {
76 using Sent = sentinel_wrapper<It>;
77 std::same_as<It> auto it = std::ranges::min_element(It(first), Sent(It(last)));
78 assert(base(it) == first + expected);
79 }
80 {
81 auto range = std::ranges::subrange(It(first), It(last));
82 std::same_as<It> auto it = std::ranges::min_element(range);
83 assert(base(it) == first + expected);
84 }
85 {
86 using Sent = sentinel_wrapper<It>;
87 auto range = std::ranges::subrange(It(first), Sent(It(last)));
88 std::same_as<It> auto it = std::ranges::min_element(range);
89 assert(base(it) == first + expected);
90 }
91}
92
93template <class It>
94constexpr bool test() {
95 test<It>({}, 0);
96 test<It>({1}, 0);
97 test<It>({1, 2}, 0);
98 test<It>({2, 1}, 1);
99 test<It>({2, 1, 2}, 1);
100 test<It>({2, 1, 1}, 1);
101
102 return true;
103}
104
105constexpr void test_borrowed_range_and_sentinel() {
106 int a[] = {7, 6, 1, 3, 5, 1, 2, 4};
107
108 int* ret = std::ranges::min_element(std::views::all(a));
109 assert(ret == a + 2);
110 assert(*ret == 1);
111}
112
113constexpr void test_comparator() {
114 int a[] = {7, 6, 9, 3, 5, 1, 2, 4};
115 int* ret = std::ranges::min_element(a, std::ranges::greater{});
116 assert(ret == a + 2);
117 assert(*ret == 9);
118}
119
120constexpr void test_projection() {
121 int a[] = {7, 6, 9, 3, 5, 1, 2, 4};
122 {
123 int* ret = std::ranges::min_element(a, std::ranges::less{}, [](int i) { return i == 5 ? -100 : i; });
124 assert(ret == a + 4);
125 assert(*ret == 5);
126 }
127 {
128 int* ret = std::ranges::min_element(a, std::less<int*>{}, [](int& i) { return &i; });
129 assert(ret == a);
130 assert(*ret == 7);
131 }
132}
133
134struct Immobile {
135 int i;
136
137 constexpr Immobile(int i_) : i(i_) {}
138 Immobile(const Immobile&) = delete;
139 Immobile(Immobile&&) = delete;
140
141 auto operator<=>(const Immobile&) const = default;
142};
143
144constexpr void test_immobile() {
145
146 Immobile arr[] {1, 2, 3};
147 assert(std::ranges::min_element(arr) == arr);
148 assert(std::ranges::min_element(arr, arr + 3) == arr);
149}
150
151constexpr void test_dangling() {
152 int compares = 0;
153 int projections = 0;
154 auto comparator = [&](int a, int b) {
155 ++compares;
156 return a < b;
157 };
158 auto projection = [&](int a) {
159 ++projections;
160 return a;
161 };
162 [[maybe_unused]] std::same_as<std::ranges::dangling> auto ret =
163 std::ranges::min_element(std::array{1, 2, 3}, comparator, projection);
164 assert(compares == 2);
165 assert(projections == 4);
166}
167
168constexpr bool test() {
169
170 test<forward_iterator<const int*>>();
171 test<bidirectional_iterator<const int*>>();
172 test<random_access_iterator<const int*>>();
173 test<const int*>();
174
175 int a[] = {7, 6, 5, 3, 4, 2, 1, 8};
176 test_iterators(first: a, last: a + 8);
177 int a2[] = {7, 6, 5, 3, 4, 2, 1, 8};
178 test_range(rng&: a2, begin: a2, end: a2 + 8);
179
180 test_borrowed_range_and_sentinel();
181 test_comparator();
182 test_projection();
183 test_dangling();
184
185 return true;
186}
187
188int main(int, char**) {
189 test();
190 static_assert(test());
191
192 return 0;
193}
194

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