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