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 //===----------------------------------------------------------------------===//
9 #ifndef _LIBCPP___ALGORITHM_NTH_ELEMENT_H
10 #define _LIBCPP___ALGORITHM_NTH_ELEMENT_H
12 #include <__algorithm/comp.h>
13 #include <__algorithm/comp_ref_type.h>
14 #include <__algorithm/iterator_operations.h>
15 #include <__algorithm/sort.h>
18 #include <__debug_utils/randomize_range.h>
19 #include <__iterator/iterator_traits.h>
20 #include <__utility/move.h>
22 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23 # pragma GCC system_header
27 #include <__undef_macros>
29 _LIBCPP_BEGIN_NAMESPACE_STD
31 template <class _Compare
, class _RandomAccessIterator
>
32 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
bool __nth_element_find_guard(
33 _RandomAccessIterator
& __i
, _RandomAccessIterator
& __j
, _RandomAccessIterator __m
, _Compare __comp
) {
34 // manually guard downward moving __j against __i
39 if (__comp(*__j
, *__m
)) {
40 return true; // found guard for downward moving __j, now use unguarded partition
45 template <class _AlgPolicy
, class _Compare
, class _RandomAccessIterator
>
46 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
void
47 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
49 _RandomAccessIterator __first
, _RandomAccessIterator __nth
, _RandomAccessIterator __last
, _Compare __comp
) {
50 using _Ops
= _IterOps
<_AlgPolicy
>;
52 // _Compare is known to be a reference type
53 typedef typename iterator_traits
<_RandomAccessIterator
>::difference_type difference_type
;
54 const difference_type __limit
= 7;
58 difference_type __len
= __last
- __first
;
64 if (__comp(*--__last
, *__first
))
65 _Ops::iter_swap(__first
, __last
);
68 _RandomAccessIterator __m
= __first
;
69 std::__sort3
<_AlgPolicy
, _Compare
>(__first
, ++__m
, --__last
, __comp
);
73 if (__len
<= __limit
) {
74 std::__selection_sort
<_AlgPolicy
, _Compare
>(__first
, __last
, __comp
);
77 // __len > __limit >= 3
78 _RandomAccessIterator __m
= __first
+ __len
/ 2;
79 _RandomAccessIterator __lm1
= __last
;
80 unsigned __n_swaps
= std::__sort3
<_AlgPolicy
, _Compare
>(__first
, __m
, --__lm1
, __comp
);
82 // partition [__first, __m) < *__m and *__m <= [__m, __last)
83 // (this inhibits tossing elements equivalent to __m around unnecessarily)
84 _RandomAccessIterator __i
= __first
;
85 _RandomAccessIterator __j
= __lm1
;
86 // j points beyond range to be tested, *__lm1 is known to be <= *__m
87 // The search going up is known to be guarded but the search coming down isn't.
88 // Prime the downward search with a guard.
89 if (!__comp(*__i
, *__m
)) // if *__first == *__m
91 // *__first == *__m, *__first doesn't go in first part
92 if (std::__nth_element_find_guard
<_Compare
>(__i
, __j
, __m
, __comp
)) {
93 _Ops::iter_swap(__i
, __j
);
96 // *__first == *__m, *__m <= all other elements
97 // Partition instead into [__first, __i) == *__first and *__first < [__i, __last)
100 if (!__comp(*__first
, *--__j
)) { // we need a guard if *__first == *(__last-1)
103 return; // [__first, __last) all equivalent elements
104 } else if (__comp(*__first
, *__i
)) {
105 _Ops::iter_swap(__i
, __j
);
113 // [__first, __i) == *__first and *__first < [__j, __last) and __j == __last - 1
118 while (!__comp(*__first
, *__i
)) {
120 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
122 "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
125 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
127 "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
129 } while (__comp(*__first
, *__j
));
132 _Ops::iter_swap(__i
, __j
);
136 // [__first, __i) == *__first and *__first < [__i, __last)
137 // The first part is sorted,
141 // __nth_element the second part
142 // std::__nth_element<_Compare>(__i, __nth, __last, __comp);
148 // j points beyond range to be tested, *__lm1 is known to be <= *__m
149 // if not yet partitioned...
151 // known that *(__i - 1) < *__m
153 // __m still guards upward moving __i
154 while (__comp(*__i
, *__m
)) {
156 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
158 "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
160 // It is now known that a guard exists for downward moving __j
162 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
164 "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
166 } while (!__comp(*__j
, *__m
));
169 _Ops::iter_swap(__i
, __j
);
171 // It is known that __m != __j
172 // If __m just moved, follow it
178 // [__first, __i) < *__m and *__m <= [__i, __last)
179 if (__i
!= __m
&& __comp(*__m
, *__i
)) {
180 _Ops::iter_swap(__i
, __m
);
183 // [__first, __i) < *__i and *__i <= [__i+1, __last)
186 if (__n_swaps
== 0) {
187 // We were given a perfectly partitioned sequence. Coincidence?
189 // Check for [__first, __i) already sorted
193 // [__first, __i) sorted
196 if (__comp(*__j
, *__m
)) {
197 // not yet sorted, so sort
203 // Check for [__i, __last) already sorted
206 if (++__j
== __last
) {
207 // [__i, __last) sorted
210 if (__comp(*__j
, *__m
)) {
211 // not yet sorted, so sort
218 // __nth_element on range containing __nth
220 // std::__nth_element<_Compare>(__first, __nth, __i, __comp);
223 // std::__nth_element<_Compare>(__i+1, __nth, __last, __comp);
229 template <class _AlgPolicy
, class _RandomAccessIterator
, class _Compare
>
230 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void __nth_element_impl(
231 _RandomAccessIterator __first
, _RandomAccessIterator __nth
, _RandomAccessIterator __last
, _Compare
& __comp
) {
235 std::__debug_randomize_range
<_AlgPolicy
>(__first
, __last
);
237 std::__nth_element
<_AlgPolicy
, __comp_ref_type
<_Compare
> >(__first
, __nth
, __last
, __comp
);
239 std::__debug_randomize_range
<_AlgPolicy
>(__first
, __nth
);
240 if (__nth
!= __last
) {
241 std::__debug_randomize_range
<_AlgPolicy
>(++__nth
, __last
);
245 template <class _RandomAccessIterator
, class _Compare
>
246 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void
247 nth_element(_RandomAccessIterator __first
, _RandomAccessIterator __nth
, _RandomAccessIterator __last
, _Compare __comp
) {
248 std::__nth_element_impl
<_ClassicAlgPolicy
>(std::move(__first
), std::move(__nth
), std::move(__last
), __comp
);
251 template <class _RandomAccessIterator
>
252 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void
253 nth_element(_RandomAccessIterator __first
, _RandomAccessIterator __nth
, _RandomAccessIterator __last
) {
254 std::nth_element(std::move(__first
), std::move(__nth
), std::move(__last
), __less
<>());
257 _LIBCPP_END_NAMESPACE_STD
261 #endif // _LIBCPP___ALGORITHM_NTH_ELEMENT_H