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
26 _LIBCPP_BEGIN_NAMESPACE_STD
28 template<class _Compare
, class _RandomAccessIterator
>
29 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
bool
30 __nth_element_find_guard(_RandomAccessIterator
& __i
, _RandomAccessIterator
& __j
,
31 _RandomAccessIterator __m
, _Compare __comp
)
33 // manually guard downward moving __j against __i
38 if (__comp(*__j
, *__m
)) {
39 return true; // found guard for downward moving __j, now use unguarded partition
44 template <class _AlgPolicy
, class _Compare
, class _RandomAccessIterator
>
45 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
void
46 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
47 __nth_element(_RandomAccessIterator __first
, _RandomAccessIterator __nth
, _RandomAccessIterator __last
, _Compare __comp
)
49 using _Ops
= _IterOps
<_AlgPolicy
>;
51 // _Compare is known to be a reference type
52 typedef typename iterator_traits
<_RandomAccessIterator
>::difference_type difference_type
;
53 const difference_type __limit
= 7;
58 difference_type __len
= __last
- __first
;
65 if (__comp(*--__last
, *__first
))
66 _Ops::iter_swap(__first
, __last
);
70 _RandomAccessIterator __m
= __first
;
71 std::__sort3
<_AlgPolicy
, _Compare
>(__first
, ++__m
, --__last
, __comp
);
77 std::__selection_sort
<_AlgPolicy
, _Compare
>(__first
, __last
, __comp
);
80 // __len > __limit >= 3
81 _RandomAccessIterator __m
= __first
+ __len
/2;
82 _RandomAccessIterator __lm1
= __last
;
83 unsigned __n_swaps
= std::__sort3
<_AlgPolicy
, _Compare
>(__first
, __m
, --__lm1
, __comp
);
85 // partition [__first, __m) < *__m and *__m <= [__m, __last)
86 // (this inhibits tossing elements equivalent to __m around unnecessarily)
87 _RandomAccessIterator __i
= __first
;
88 _RandomAccessIterator __j
= __lm1
;
89 // j points beyond range to be tested, *__lm1 is known to be <= *__m
90 // The search going up is known to be guarded but the search coming down isn't.
91 // Prime the downward search with a guard.
92 if (!__comp(*__i
, *__m
)) // if *__first == *__m
94 // *__first == *__m, *__first doesn't go in first part
95 if (_VSTD::__nth_element_find_guard
<_Compare
>(__i
, __j
, __m
, __comp
)) {
96 _Ops::iter_swap(__i
, __j
);
99 // *__first == *__m, *__m <= all other elements
100 // Partition instead into [__first, __i) == *__first and *__first < [__i, __last)
101 ++__i
; // __first + 1
103 if (!__comp(*__first
, *--__j
)) { // we need a guard if *__first == *(__last-1)
106 return; // [__first, __last) all equivalent elements
107 } else if (__comp(*__first
, *__i
)) {
108 _Ops::iter_swap(__i
, __j
);
116 // [__first, __i) == *__first and *__first < [__j, __last) and __j == __last - 1
121 while (!__comp(*__first
, *__i
)) {
123 _LIBCPP_ASSERT_UNCATEGORIZED(
125 "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
128 _LIBCPP_ASSERT_UNCATEGORIZED(
130 "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
132 } while (__comp(*__first
, *__j
));
135 _Ops::iter_swap(__i
, __j
);
139 // [__first, __i) == *__first and *__first < [__i, __last)
140 // The first part is sorted,
144 // __nth_element the second part
145 // _VSTD::__nth_element<_Compare>(__i, __nth, __last, __comp);
151 // j points beyond range to be tested, *__lm1 is known to be <= *__m
152 // if not yet partitioned...
155 // known that *(__i - 1) < *__m
158 // __m still guards upward moving __i
159 while (__comp(*__i
, *__m
)) {
161 _LIBCPP_ASSERT_UNCATEGORIZED(
163 "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
165 // It is now known that a guard exists for downward moving __j
167 _LIBCPP_ASSERT_UNCATEGORIZED(
169 "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
171 } while (!__comp(*__j
, *__m
));
174 _Ops::iter_swap(__i
, __j
);
176 // It is known that __m != __j
177 // If __m just moved, follow it
183 // [__first, __i) < *__m and *__m <= [__i, __last)
184 if (__i
!= __m
&& __comp(*__m
, *__i
))
186 _Ops::iter_swap(__i
, __m
);
189 // [__first, __i) < *__i and *__i <= [__i+1, __last)
194 // We were given a perfectly partitioned sequence. Coincidence?
197 // Check for [__first, __i) already sorted
201 // [__first, __i) sorted
204 if (__comp(*__j
, *__m
)) {
205 // not yet sorted, so sort
213 // Check for [__i, __last) already sorted
216 if (++__j
== __last
) {
217 // [__i, __last) sorted
220 if (__comp(*__j
, *__m
)) {
221 // not yet sorted, so sort
228 // __nth_element on range containing __nth
231 // _VSTD::__nth_element<_Compare>(__first, __nth, __i, __comp);
236 // _VSTD::__nth_element<_Compare>(__i+1, __nth, __last, __comp);
242 template <class _AlgPolicy
, class _RandomAccessIterator
, class _Compare
>
243 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
244 void __nth_element_impl(_RandomAccessIterator __first
, _RandomAccessIterator __nth
, _RandomAccessIterator __last
,
249 std::__debug_randomize_range
<_AlgPolicy
>(__first
, __last
);
251 std::__nth_element
<_AlgPolicy
, __comp_ref_type
<_Compare
> >(__first
, __nth
, __last
, __comp
);
253 std::__debug_randomize_range
<_AlgPolicy
>(__first
, __nth
);
254 if (__nth
!= __last
) {
255 std::__debug_randomize_range
<_AlgPolicy
>(++__nth
, __last
);
259 template <class _RandomAccessIterator
, class _Compare
>
260 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
261 void nth_element(_RandomAccessIterator __first
, _RandomAccessIterator __nth
, _RandomAccessIterator __last
,
263 std::__nth_element_impl
<_ClassicAlgPolicy
>(std::move(__first
), std::move(__nth
), std::move(__last
), __comp
);
266 template <class _RandomAccessIterator
>
267 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
268 void nth_element(_RandomAccessIterator __first
, _RandomAccessIterator __nth
, _RandomAccessIterator __last
) {
269 std::nth_element(std::move(__first
), std::move(__nth
), std::move(__last
), __less
<>());
272 _LIBCPP_END_NAMESPACE_STD
274 #endif // _LIBCPP___ALGORITHM_NTH_ELEMENT_H