1134723edSLouis Dionne //===----------------------------------------------------------------------===//
2134723edSLouis Dionne //
3134723edSLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4134723edSLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
5134723edSLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6134723edSLouis Dionne //
7134723edSLouis Dionne //===----------------------------------------------------------------------===//
8134723edSLouis Dionne
9134723edSLouis Dionne #ifndef _LIBCPP___ALGORITHM_NTH_ELEMENT_H
10134723edSLouis Dionne #define _LIBCPP___ALGORITHM_NTH_ELEMENT_H
11134723edSLouis Dionne
12134723edSLouis Dionne #include <__algorithm/comp.h>
13134723edSLouis Dionne #include <__algorithm/comp_ref_type.h>
14a7c3379cSKonstantin Varlamov #include <__algorithm/iterator_operations.h>
15134723edSLouis Dionne #include <__algorithm/sort.h>
16ea9af5e7SDaniel Kutenin #include <__assert>
174d81a46fSArthur O'Dwyer #include <__config>
182aea8af2SNikolas Klauser #include <__debug_utils/randomize_range.h>
19134723edSLouis Dionne #include <__iterator/iterator_traits.h>
2023c7328bSKonstantin Varlamov #include <__utility/move.h>
21134723edSLouis Dionne
22134723edSLouis Dionne #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23134723edSLouis Dionne # pragma GCC system_header
24134723edSLouis Dionne #endif
25134723edSLouis Dionne
26*7b462251SLouis Dionne _LIBCPP_PUSH_MACROS
27*7b462251SLouis Dionne #include <__undef_macros>
28*7b462251SLouis Dionne
29134723edSLouis Dionne _LIBCPP_BEGIN_NAMESPACE_STD
30134723edSLouis Dionne
31134723edSLouis Dionne template <class _Compare, class _RandomAccessIterator>
__nth_element_find_guard(_RandomAccessIterator & __i,_RandomAccessIterator & __j,_RandomAccessIterator __m,_Compare __comp)329783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool __nth_element_find_guard(
339783f28cSLouis Dionne _RandomAccessIterator& __i, _RandomAccessIterator& __j, _RandomAccessIterator __m, _Compare __comp) {
34134723edSLouis Dionne // manually guard downward moving __j against __i
35134723edSLouis Dionne while (true) {
36134723edSLouis Dionne if (__i == --__j) {
37134723edSLouis Dionne return false;
38134723edSLouis Dionne }
39134723edSLouis Dionne if (__comp(*__j, *__m)) {
40134723edSLouis Dionne return true; // found guard for downward moving __j, now use unguarded partition
41134723edSLouis Dionne }
42134723edSLouis Dionne }
43134723edSLouis Dionne }
44134723edSLouis Dionne
45a7c3379cSKonstantin Varlamov template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
465146b57bSNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
47ea9af5e7SDaniel Kutenin // NOLINTNEXTLINE(readability-function-cognitive-complexity)
__nth_element(_RandomAccessIterator __first,_RandomAccessIterator __nth,_RandomAccessIterator __last,_Compare __comp)489783f28cSLouis Dionne __nth_element(
499783f28cSLouis Dionne _RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp) {
50a7c3379cSKonstantin Varlamov using _Ops = _IterOps<_AlgPolicy>;
51a7c3379cSKonstantin Varlamov
52134723edSLouis Dionne // _Compare is known to be a reference type
53134723edSLouis Dionne typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
54134723edSLouis Dionne const difference_type __limit = 7;
559783f28cSLouis Dionne while (true) {
56134723edSLouis Dionne if (__nth == __last)
57134723edSLouis Dionne return;
58134723edSLouis Dionne difference_type __len = __last - __first;
599783f28cSLouis Dionne switch (__len) {
60134723edSLouis Dionne case 0:
61134723edSLouis Dionne case 1:
62134723edSLouis Dionne return;
63134723edSLouis Dionne case 2:
64134723edSLouis Dionne if (__comp(*--__last, *__first))
65a7c3379cSKonstantin Varlamov _Ops::iter_swap(__first, __last);
66134723edSLouis Dionne return;
679783f28cSLouis Dionne case 3: {
68134723edSLouis Dionne _RandomAccessIterator __m = __first;
69a7c3379cSKonstantin Varlamov std::__sort3<_AlgPolicy, _Compare>(__first, ++__m, --__last, __comp);
70134723edSLouis Dionne return;
71134723edSLouis Dionne }
72134723edSLouis Dionne }
739783f28cSLouis Dionne if (__len <= __limit) {
74a7c3379cSKonstantin Varlamov std::__selection_sort<_AlgPolicy, _Compare>(__first, __last, __comp);
75134723edSLouis Dionne return;
76134723edSLouis Dionne }
77134723edSLouis Dionne // __len > __limit >= 3
78134723edSLouis Dionne _RandomAccessIterator __m = __first + __len / 2;
79134723edSLouis Dionne _RandomAccessIterator __lm1 = __last;
80a7c3379cSKonstantin Varlamov unsigned __n_swaps = std::__sort3<_AlgPolicy, _Compare>(__first, __m, --__lm1, __comp);
81134723edSLouis Dionne // *__m is median
82134723edSLouis Dionne // partition [__first, __m) < *__m and *__m <= [__m, __last)
83134723edSLouis Dionne // (this inhibits tossing elements equivalent to __m around unnecessarily)
84134723edSLouis Dionne _RandomAccessIterator __i = __first;
85134723edSLouis Dionne _RandomAccessIterator __j = __lm1;
86134723edSLouis Dionne // j points beyond range to be tested, *__lm1 is known to be <= *__m
87134723edSLouis Dionne // The search going up is known to be guarded but the search coming down isn't.
88134723edSLouis Dionne // Prime the downward search with a guard.
89134723edSLouis Dionne if (!__comp(*__i, *__m)) // if *__first == *__m
90134723edSLouis Dionne {
91134723edSLouis Dionne // *__first == *__m, *__first doesn't go in first part
9277a00c0dSLouis Dionne if (std::__nth_element_find_guard<_Compare>(__i, __j, __m, __comp)) {
93a7c3379cSKonstantin Varlamov _Ops::iter_swap(__i, __j);
94134723edSLouis Dionne ++__n_swaps;
95134723edSLouis Dionne } else {
96134723edSLouis Dionne // *__first == *__m, *__m <= all other elements
97134723edSLouis Dionne // Partition instead into [__first, __i) == *__first and *__first < [__i, __last)
98134723edSLouis Dionne ++__i; // __first + 1
99134723edSLouis Dionne __j = __last;
100134723edSLouis Dionne if (!__comp(*__first, *--__j)) { // we need a guard if *__first == *(__last-1)
101134723edSLouis Dionne while (true) {
102134723edSLouis Dionne if (__i == __j) {
103134723edSLouis Dionne return; // [__first, __last) all equivalent elements
104134723edSLouis Dionne } else if (__comp(*__first, *__i)) {
105a7c3379cSKonstantin Varlamov _Ops::iter_swap(__i, __j);
106134723edSLouis Dionne ++__n_swaps;
107134723edSLouis Dionne ++__i;
108134723edSLouis Dionne break;
109134723edSLouis Dionne }
110134723edSLouis Dionne ++__i;
111134723edSLouis Dionne }
112134723edSLouis Dionne }
113134723edSLouis Dionne // [__first, __i) == *__first and *__first < [__j, __last) and __j == __last - 1
114134723edSLouis Dionne if (__i == __j) {
115134723edSLouis Dionne return;
116134723edSLouis Dionne }
117134723edSLouis Dionne while (true) {
118ea9af5e7SDaniel Kutenin while (!__comp(*__first, *__i)) {
119134723edSLouis Dionne ++__i;
1208938bc0aSKonstantin Varlamov _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
121ea9af5e7SDaniel Kutenin __i != __last,
122ea9af5e7SDaniel Kutenin "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
123ea9af5e7SDaniel Kutenin }
124ea9af5e7SDaniel Kutenin do {
1258938bc0aSKonstantin Varlamov _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
126ea9af5e7SDaniel Kutenin __j != __first,
127ea9af5e7SDaniel Kutenin "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
128ea9af5e7SDaniel Kutenin --__j;
129ea9af5e7SDaniel Kutenin } while (__comp(*__first, *__j));
130134723edSLouis Dionne if (__i >= __j)
131134723edSLouis Dionne break;
132a7c3379cSKonstantin Varlamov _Ops::iter_swap(__i, __j);
133134723edSLouis Dionne ++__n_swaps;
134134723edSLouis Dionne ++__i;
135134723edSLouis Dionne }
136134723edSLouis Dionne // [__first, __i) == *__first and *__first < [__i, __last)
137134723edSLouis Dionne // The first part is sorted,
138134723edSLouis Dionne if (__nth < __i) {
139134723edSLouis Dionne return;
140134723edSLouis Dionne }
141134723edSLouis Dionne // __nth_element the second part
14277a00c0dSLouis Dionne // std::__nth_element<_Compare>(__i, __nth, __last, __comp);
143134723edSLouis Dionne __first = __i;
144134723edSLouis Dionne continue;
145134723edSLouis Dionne }
146134723edSLouis Dionne }
147134723edSLouis Dionne ++__i;
148134723edSLouis Dionne // j points beyond range to be tested, *__lm1 is known to be <= *__m
149134723edSLouis Dionne // if not yet partitioned...
1509783f28cSLouis Dionne if (__i < __j) {
151134723edSLouis Dionne // known that *(__i - 1) < *__m
1529783f28cSLouis Dionne while (true) {
153134723edSLouis Dionne // __m still guards upward moving __i
154ea9af5e7SDaniel Kutenin while (__comp(*__i, *__m)) {
155134723edSLouis Dionne ++__i;
1568938bc0aSKonstantin Varlamov _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
157ea9af5e7SDaniel Kutenin __i != __last,
158ea9af5e7SDaniel Kutenin "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
159ea9af5e7SDaniel Kutenin }
160134723edSLouis Dionne // It is now known that a guard exists for downward moving __j
161ea9af5e7SDaniel Kutenin do {
1628938bc0aSKonstantin Varlamov _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
163ea9af5e7SDaniel Kutenin __j != __first,
164ea9af5e7SDaniel Kutenin "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
165ea9af5e7SDaniel Kutenin --__j;
166ea9af5e7SDaniel Kutenin } while (!__comp(*__j, *__m));
167134723edSLouis Dionne if (__i >= __j)
168134723edSLouis Dionne break;
169a7c3379cSKonstantin Varlamov _Ops::iter_swap(__i, __j);
170134723edSLouis Dionne ++__n_swaps;
171134723edSLouis Dionne // It is known that __m != __j
172134723edSLouis Dionne // If __m just moved, follow it
173134723edSLouis Dionne if (__m == __i)
174134723edSLouis Dionne __m = __j;
175134723edSLouis Dionne ++__i;
176134723edSLouis Dionne }
177134723edSLouis Dionne }
178134723edSLouis Dionne // [__first, __i) < *__m and *__m <= [__i, __last)
1799783f28cSLouis Dionne if (__i != __m && __comp(*__m, *__i)) {
180a7c3379cSKonstantin Varlamov _Ops::iter_swap(__i, __m);
181134723edSLouis Dionne ++__n_swaps;
182134723edSLouis Dionne }
183134723edSLouis Dionne // [__first, __i) < *__i and *__i <= [__i+1, __last)
184134723edSLouis Dionne if (__nth == __i)
185134723edSLouis Dionne return;
1869783f28cSLouis Dionne if (__n_swaps == 0) {
187134723edSLouis Dionne // We were given a perfectly partitioned sequence. Coincidence?
1889783f28cSLouis Dionne if (__nth < __i) {
189134723edSLouis Dionne // Check for [__first, __i) already sorted
190134723edSLouis Dionne __j = __m = __first;
191134723edSLouis Dionne while (true) {
192134723edSLouis Dionne if (++__j == __i) {
193134723edSLouis Dionne // [__first, __i) sorted
194134723edSLouis Dionne return;
195134723edSLouis Dionne }
196134723edSLouis Dionne if (__comp(*__j, *__m)) {
197134723edSLouis Dionne // not yet sorted, so sort
198134723edSLouis Dionne break;
199134723edSLouis Dionne }
200134723edSLouis Dionne __m = __j;
201134723edSLouis Dionne }
2029783f28cSLouis Dionne } else {
203134723edSLouis Dionne // Check for [__i, __last) already sorted
204134723edSLouis Dionne __j = __m = __i;
205134723edSLouis Dionne while (true) {
206134723edSLouis Dionne if (++__j == __last) {
207134723edSLouis Dionne // [__i, __last) sorted
208134723edSLouis Dionne return;
209134723edSLouis Dionne }
210134723edSLouis Dionne if (__comp(*__j, *__m)) {
211134723edSLouis Dionne // not yet sorted, so sort
212134723edSLouis Dionne break;
213134723edSLouis Dionne }
214134723edSLouis Dionne __m = __j;
215134723edSLouis Dionne }
216134723edSLouis Dionne }
217134723edSLouis Dionne }
218134723edSLouis Dionne // __nth_element on range containing __nth
2199783f28cSLouis Dionne if (__nth < __i) {
22077a00c0dSLouis Dionne // std::__nth_element<_Compare>(__first, __nth, __i, __comp);
221134723edSLouis Dionne __last = __i;
2229783f28cSLouis Dionne } else {
22377a00c0dSLouis Dionne // std::__nth_element<_Compare>(__i+1, __nth, __last, __comp);
224134723edSLouis Dionne __first = ++__i;
225134723edSLouis Dionne }
226134723edSLouis Dionne }
227134723edSLouis Dionne }
228134723edSLouis Dionne
229a7c3379cSKonstantin Varlamov template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
__nth_element_impl(_RandomAccessIterator __first,_RandomAccessIterator __nth,_RandomAccessIterator __last,_Compare & __comp)2309783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __nth_element_impl(
2319783f28cSLouis Dionne _RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare& __comp) {
23223c7328bSKonstantin Varlamov if (__nth == __last)
23323c7328bSKonstantin Varlamov return;
23423c7328bSKonstantin Varlamov
235a7c3379cSKonstantin Varlamov std::__debug_randomize_range<_AlgPolicy>(__first, __last);
23623c7328bSKonstantin Varlamov
237ed2d3644SNikolas Klauser std::__nth_element<_AlgPolicy, __comp_ref_type<_Compare> >(__first, __nth, __last, __comp);
23823c7328bSKonstantin Varlamov
239a7c3379cSKonstantin Varlamov std::__debug_randomize_range<_AlgPolicy>(__first, __nth);
240a45d2287SDanila Kutenin if (__nth != __last) {
241a7c3379cSKonstantin Varlamov std::__debug_randomize_range<_AlgPolicy>(++__nth, __last);
242a45d2287SDanila Kutenin }
243134723edSLouis Dionne }
244134723edSLouis Dionne
24523c7328bSKonstantin Varlamov template <class _RandomAccessIterator, class _Compare>
2469783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
nth_element(_RandomAccessIterator __first,_RandomAccessIterator __nth,_RandomAccessIterator __last,_Compare __comp)2479783f28cSLouis Dionne nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp) {
248a7c3379cSKonstantin Varlamov std::__nth_element_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__nth), std::move(__last), __comp);
24923c7328bSKonstantin Varlamov }
25023c7328bSKonstantin Varlamov
251134723edSLouis Dionne template <class _RandomAccessIterator>
2529783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
nth_element(_RandomAccessIterator __first,_RandomAccessIterator __nth,_RandomAccessIterator __last)2539783f28cSLouis Dionne nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last) {
25488632e48SNikolas Klauser std::nth_element(std::move(__first), std::move(__nth), std::move(__last), __less<>());
255134723edSLouis Dionne }
256134723edSLouis Dionne
257134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD
258134723edSLouis Dionne
259*7b462251SLouis Dionne _LIBCPP_POP_MACROS
260*7b462251SLouis Dionne
261134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_NTH_ELEMENT_H
262