xref: /llvm-project/libcxx/include/__algorithm/nth_element.h (revision 4d81a46f7f71559b48568a47edbe6b70a003029e)
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>
14134723edSLouis Dionne #include <__algorithm/sort.h>
15*4d81a46fSArthur O'Dwyer #include <__config>
16134723edSLouis Dionne #include <__iterator/iterator_traits.h>
176adbc83eSChristopher Di Bella #include <__utility/swap.h>
18134723edSLouis Dionne 
19a45d2287SDanila Kutenin #if defined(_LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY)
20a45d2287SDanila Kutenin #  include <__algorithm/shuffle.h>
21a45d2287SDanila Kutenin #endif
22a45d2287SDanila Kutenin 
23134723edSLouis Dionne #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
24134723edSLouis Dionne #pragma GCC system_header
25134723edSLouis Dionne #endif
26134723edSLouis Dionne 
27134723edSLouis Dionne _LIBCPP_BEGIN_NAMESPACE_STD
28134723edSLouis Dionne 
29134723edSLouis Dionne template<class _Compare, class _RandomAccessIterator>
30134723edSLouis Dionne _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
31134723edSLouis Dionne __nth_element_find_guard(_RandomAccessIterator& __i, _RandomAccessIterator& __j,
32134723edSLouis Dionne                          _RandomAccessIterator __m, _Compare __comp)
33134723edSLouis Dionne {
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 
45134723edSLouis Dionne template <class _Compare, class _RandomAccessIterator>
46134723edSLouis Dionne _LIBCPP_CONSTEXPR_AFTER_CXX11 void
47134723edSLouis Dionne __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp)
48134723edSLouis Dionne {
49134723edSLouis Dionne     // _Compare is known to be a reference type
50134723edSLouis Dionne     typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
51134723edSLouis Dionne     const difference_type __limit = 7;
52134723edSLouis Dionne     while (true)
53134723edSLouis Dionne     {
54134723edSLouis Dionne         if (__nth == __last)
55134723edSLouis Dionne             return;
56134723edSLouis Dionne         difference_type __len = __last - __first;
57134723edSLouis Dionne         switch (__len)
58134723edSLouis Dionne         {
59134723edSLouis Dionne         case 0:
60134723edSLouis Dionne         case 1:
61134723edSLouis Dionne             return;
62134723edSLouis Dionne         case 2:
63134723edSLouis Dionne             if (__comp(*--__last, *__first))
64134723edSLouis Dionne                 swap(*__first, *__last);
65134723edSLouis Dionne             return;
66134723edSLouis Dionne         case 3:
67134723edSLouis Dionne             {
68134723edSLouis Dionne             _RandomAccessIterator __m = __first;
69134723edSLouis Dionne             _VSTD::__sort3<_Compare>(__first, ++__m, --__last, __comp);
70134723edSLouis Dionne             return;
71134723edSLouis Dionne             }
72134723edSLouis Dionne         }
73134723edSLouis Dionne         if (__len <= __limit)
74134723edSLouis Dionne         {
75134723edSLouis Dionne             _VSTD::__selection_sort<_Compare>(__first, __last, __comp);
76134723edSLouis Dionne             return;
77134723edSLouis Dionne         }
78134723edSLouis Dionne         // __len > __limit >= 3
79134723edSLouis Dionne         _RandomAccessIterator __m = __first + __len/2;
80134723edSLouis Dionne         _RandomAccessIterator __lm1 = __last;
81134723edSLouis Dionne         unsigned __n_swaps = _VSTD::__sort3<_Compare>(__first, __m, --__lm1, __comp);
82134723edSLouis Dionne         // *__m is median
83134723edSLouis Dionne         // partition [__first, __m) < *__m and *__m <= [__m, __last)
84134723edSLouis Dionne         // (this inhibits tossing elements equivalent to __m around unnecessarily)
85134723edSLouis Dionne         _RandomAccessIterator __i = __first;
86134723edSLouis Dionne         _RandomAccessIterator __j = __lm1;
87134723edSLouis Dionne         // j points beyond range to be tested, *__lm1 is known to be <= *__m
88134723edSLouis Dionne         // The search going up is known to be guarded but the search coming down isn't.
89134723edSLouis Dionne         // Prime the downward search with a guard.
90134723edSLouis Dionne         if (!__comp(*__i, *__m))  // if *__first == *__m
91134723edSLouis Dionne         {
92134723edSLouis Dionne             // *__first == *__m, *__first doesn't go in first part
93134723edSLouis Dionne             if (_VSTD::__nth_element_find_guard<_Compare>(__i, __j, __m, __comp)) {
94134723edSLouis Dionne                 swap(*__i, *__j);
95134723edSLouis Dionne                 ++__n_swaps;
96134723edSLouis Dionne             } else {
97134723edSLouis Dionne                 // *__first == *__m, *__m <= all other elements
98134723edSLouis Dionne                 // Partition instead into [__first, __i) == *__first and *__first < [__i, __last)
99134723edSLouis Dionne                 ++__i;  // __first + 1
100134723edSLouis Dionne                 __j = __last;
101134723edSLouis Dionne                 if (!__comp(*__first, *--__j)) {  // we need a guard if *__first == *(__last-1)
102134723edSLouis Dionne                     while (true) {
103134723edSLouis Dionne                         if (__i == __j) {
104134723edSLouis Dionne                             return;  // [__first, __last) all equivalent elements
105134723edSLouis Dionne                         } else if (__comp(*__first, *__i)) {
106134723edSLouis Dionne                             swap(*__i, *__j);
107134723edSLouis Dionne                             ++__n_swaps;
108134723edSLouis Dionne                             ++__i;
109134723edSLouis Dionne                             break;
110134723edSLouis Dionne                         }
111134723edSLouis Dionne                         ++__i;
112134723edSLouis Dionne                     }
113134723edSLouis Dionne                 }
114134723edSLouis Dionne                 // [__first, __i) == *__first and *__first < [__j, __last) and __j == __last - 1
115134723edSLouis Dionne                 if (__i == __j) {
116134723edSLouis Dionne                     return;
117134723edSLouis Dionne                 }
118134723edSLouis Dionne                 while (true) {
119134723edSLouis Dionne                     while (!__comp(*__first, *__i))
120134723edSLouis Dionne                         ++__i;
121134723edSLouis Dionne                     while (__comp(*__first, *--__j))
122134723edSLouis Dionne                         ;
123134723edSLouis Dionne                     if (__i >= __j)
124134723edSLouis Dionne                         break;
125134723edSLouis Dionne                     swap(*__i, *__j);
126134723edSLouis Dionne                     ++__n_swaps;
127134723edSLouis Dionne                     ++__i;
128134723edSLouis Dionne                 }
129134723edSLouis Dionne                 // [__first, __i) == *__first and *__first < [__i, __last)
130134723edSLouis Dionne                 // The first part is sorted,
131134723edSLouis Dionne                 if (__nth < __i) {
132134723edSLouis Dionne                     return;
133134723edSLouis Dionne                 }
134134723edSLouis Dionne                 // __nth_element the second part
135134723edSLouis Dionne                 // _VSTD::__nth_element<_Compare>(__i, __nth, __last, __comp);
136134723edSLouis Dionne                 __first = __i;
137134723edSLouis Dionne                 continue;
138134723edSLouis Dionne             }
139134723edSLouis Dionne         }
140134723edSLouis Dionne         ++__i;
141134723edSLouis Dionne         // j points beyond range to be tested, *__lm1 is known to be <= *__m
142134723edSLouis Dionne         // if not yet partitioned...
143134723edSLouis Dionne         if (__i < __j)
144134723edSLouis Dionne         {
145134723edSLouis Dionne             // known that *(__i - 1) < *__m
146134723edSLouis Dionne             while (true)
147134723edSLouis Dionne             {
148134723edSLouis Dionne                 // __m still guards upward moving __i
149134723edSLouis Dionne                 while (__comp(*__i, *__m))
150134723edSLouis Dionne                     ++__i;
151134723edSLouis Dionne                 // It is now known that a guard exists for downward moving __j
152134723edSLouis Dionne                 while (!__comp(*--__j, *__m))
153134723edSLouis Dionne                     ;
154134723edSLouis Dionne                 if (__i >= __j)
155134723edSLouis Dionne                     break;
156134723edSLouis Dionne                 swap(*__i, *__j);
157134723edSLouis Dionne                 ++__n_swaps;
158134723edSLouis Dionne                 // It is known that __m != __j
159134723edSLouis Dionne                 // If __m just moved, follow it
160134723edSLouis Dionne                 if (__m == __i)
161134723edSLouis Dionne                     __m = __j;
162134723edSLouis Dionne                 ++__i;
163134723edSLouis Dionne             }
164134723edSLouis Dionne         }
165134723edSLouis Dionne         // [__first, __i) < *__m and *__m <= [__i, __last)
166134723edSLouis Dionne         if (__i != __m && __comp(*__m, *__i))
167134723edSLouis Dionne         {
168134723edSLouis Dionne             swap(*__i, *__m);
169134723edSLouis Dionne             ++__n_swaps;
170134723edSLouis Dionne         }
171134723edSLouis Dionne         // [__first, __i) < *__i and *__i <= [__i+1, __last)
172134723edSLouis Dionne         if (__nth == __i)
173134723edSLouis Dionne             return;
174134723edSLouis Dionne         if (__n_swaps == 0)
175134723edSLouis Dionne         {
176134723edSLouis Dionne             // We were given a perfectly partitioned sequence.  Coincidence?
177134723edSLouis Dionne             if (__nth < __i)
178134723edSLouis Dionne             {
179134723edSLouis Dionne                 // Check for [__first, __i) already sorted
180134723edSLouis Dionne                 __j = __m = __first;
181134723edSLouis Dionne                 while (true) {
182134723edSLouis Dionne                     if (++__j == __i) {
183134723edSLouis Dionne                         // [__first, __i) sorted
184134723edSLouis Dionne                         return;
185134723edSLouis Dionne                     }
186134723edSLouis Dionne                     if (__comp(*__j, *__m)) {
187134723edSLouis Dionne                         // not yet sorted, so sort
188134723edSLouis Dionne                         break;
189134723edSLouis Dionne                     }
190134723edSLouis Dionne                     __m = __j;
191134723edSLouis Dionne                 }
192134723edSLouis Dionne             }
193134723edSLouis Dionne             else
194134723edSLouis Dionne             {
195134723edSLouis Dionne                 // Check for [__i, __last) already sorted
196134723edSLouis Dionne                 __j = __m = __i;
197134723edSLouis Dionne                 while (true) {
198134723edSLouis Dionne                     if (++__j == __last) {
199134723edSLouis Dionne                         // [__i, __last) sorted
200134723edSLouis Dionne                         return;
201134723edSLouis Dionne                     }
202134723edSLouis Dionne                     if (__comp(*__j, *__m)) {
203134723edSLouis Dionne                         // not yet sorted, so sort
204134723edSLouis Dionne                         break;
205134723edSLouis Dionne                     }
206134723edSLouis Dionne                     __m = __j;
207134723edSLouis Dionne                 }
208134723edSLouis Dionne             }
209134723edSLouis Dionne         }
210134723edSLouis Dionne         // __nth_element on range containing __nth
211134723edSLouis Dionne         if (__nth < __i)
212134723edSLouis Dionne         {
213134723edSLouis Dionne             // _VSTD::__nth_element<_Compare>(__first, __nth, __i, __comp);
214134723edSLouis Dionne             __last = __i;
215134723edSLouis Dionne         }
216134723edSLouis Dionne         else
217134723edSLouis Dionne         {
218134723edSLouis Dionne             // _VSTD::__nth_element<_Compare>(__i+1, __nth, __last, __comp);
219134723edSLouis Dionne             __first = ++__i;
220134723edSLouis Dionne         }
221134723edSLouis Dionne     }
222134723edSLouis Dionne }
223134723edSLouis Dionne 
224134723edSLouis Dionne template <class _RandomAccessIterator, class _Compare>
225134723edSLouis Dionne inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
226134723edSLouis Dionne void
227134723edSLouis Dionne nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp)
228134723edSLouis Dionne {
229a45d2287SDanila Kutenin   _LIBCPP_DEBUG_RANDOMIZE_RANGE(__first, __last);
230134723edSLouis Dionne   typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
231134723edSLouis Dionne   _VSTD::__nth_element<_Comp_ref>(__first, __nth, __last, __comp);
232a45d2287SDanila Kutenin   _LIBCPP_DEBUG_RANDOMIZE_RANGE(__first, __nth);
233a45d2287SDanila Kutenin   if (__nth != __last) {
234a45d2287SDanila Kutenin     _LIBCPP_DEBUG_RANDOMIZE_RANGE(++__nth, __last);
235a45d2287SDanila Kutenin   }
236134723edSLouis Dionne }
237134723edSLouis Dionne 
238134723edSLouis Dionne template <class _RandomAccessIterator>
239134723edSLouis Dionne inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
240134723edSLouis Dionne void
241134723edSLouis Dionne nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last)
242134723edSLouis Dionne {
243134723edSLouis Dionne     _VSTD::nth_element(__first, __nth, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
244134723edSLouis Dionne }
245134723edSLouis Dionne 
246134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD
247134723edSLouis Dionne 
248134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_NTH_ELEMENT_H
249