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 26134723edSLouis Dionne _LIBCPP_BEGIN_NAMESPACE_STD 27134723edSLouis Dionne 28134723edSLouis Dionne template<class _Compare, class _RandomAccessIterator> 295146b57bSNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool 30134723edSLouis Dionne __nth_element_find_guard(_RandomAccessIterator& __i, _RandomAccessIterator& __j, 31134723edSLouis Dionne _RandomAccessIterator __m, _Compare __comp) 32134723edSLouis Dionne { 33134723edSLouis Dionne // manually guard downward moving __j against __i 34134723edSLouis Dionne while (true) { 35134723edSLouis Dionne if (__i == --__j) { 36134723edSLouis Dionne return false; 37134723edSLouis Dionne } 38134723edSLouis Dionne if (__comp(*__j, *__m)) { 39134723edSLouis Dionne return true; // found guard for downward moving __j, now use unguarded partition 40134723edSLouis Dionne } 41134723edSLouis Dionne } 42134723edSLouis Dionne } 43134723edSLouis Dionne 44a7c3379cSKonstantin Varlamov template <class _AlgPolicy, class _Compare, class _RandomAccessIterator> 455146b57bSNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void 46ea9af5e7SDaniel Kutenin // NOLINTNEXTLINE(readability-function-cognitive-complexity) 47134723edSLouis Dionne __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp) 48134723edSLouis Dionne { 49a7c3379cSKonstantin Varlamov using _Ops = _IterOps<_AlgPolicy>; 50a7c3379cSKonstantin Varlamov 51134723edSLouis Dionne // _Compare is known to be a reference type 52134723edSLouis Dionne typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; 53134723edSLouis Dionne const difference_type __limit = 7; 54134723edSLouis Dionne while (true) 55134723edSLouis Dionne { 56134723edSLouis Dionne if (__nth == __last) 57134723edSLouis Dionne return; 58134723edSLouis Dionne difference_type __len = __last - __first; 59134723edSLouis Dionne switch (__len) 60134723edSLouis Dionne { 61134723edSLouis Dionne case 0: 62134723edSLouis Dionne case 1: 63134723edSLouis Dionne return; 64134723edSLouis Dionne case 2: 65134723edSLouis Dionne if (__comp(*--__last, *__first)) 66a7c3379cSKonstantin Varlamov _Ops::iter_swap(__first, __last); 67134723edSLouis Dionne return; 68134723edSLouis Dionne case 3: 69134723edSLouis Dionne { 70134723edSLouis Dionne _RandomAccessIterator __m = __first; 71a7c3379cSKonstantin Varlamov std::__sort3<_AlgPolicy, _Compare>(__first, ++__m, --__last, __comp); 72134723edSLouis Dionne return; 73134723edSLouis Dionne } 74134723edSLouis Dionne } 75134723edSLouis Dionne if (__len <= __limit) 76134723edSLouis Dionne { 77a7c3379cSKonstantin Varlamov std::__selection_sort<_AlgPolicy, _Compare>(__first, __last, __comp); 78134723edSLouis Dionne return; 79134723edSLouis Dionne } 80134723edSLouis Dionne // __len > __limit >= 3 81134723edSLouis Dionne _RandomAccessIterator __m = __first + __len/2; 82134723edSLouis Dionne _RandomAccessIterator __lm1 = __last; 83a7c3379cSKonstantin Varlamov unsigned __n_swaps = std::__sort3<_AlgPolicy, _Compare>(__first, __m, --__lm1, __comp); 84134723edSLouis Dionne // *__m is median 85134723edSLouis Dionne // partition [__first, __m) < *__m and *__m <= [__m, __last) 86134723edSLouis Dionne // (this inhibits tossing elements equivalent to __m around unnecessarily) 87134723edSLouis Dionne _RandomAccessIterator __i = __first; 88134723edSLouis Dionne _RandomAccessIterator __j = __lm1; 89134723edSLouis Dionne // j points beyond range to be tested, *__lm1 is known to be <= *__m 90134723edSLouis Dionne // The search going up is known to be guarded but the search coming down isn't. 91134723edSLouis Dionne // Prime the downward search with a guard. 92134723edSLouis Dionne if (!__comp(*__i, *__m)) // if *__first == *__m 93134723edSLouis Dionne { 94134723edSLouis Dionne // *__first == *__m, *__first doesn't go in first part 95*77a00c0dSLouis Dionne if (std::__nth_element_find_guard<_Compare>(__i, __j, __m, __comp)) { 96a7c3379cSKonstantin Varlamov _Ops::iter_swap(__i, __j); 97134723edSLouis Dionne ++__n_swaps; 98134723edSLouis Dionne } else { 99134723edSLouis Dionne // *__first == *__m, *__m <= all other elements 100134723edSLouis Dionne // Partition instead into [__first, __i) == *__first and *__first < [__i, __last) 101134723edSLouis Dionne ++__i; // __first + 1 102134723edSLouis Dionne __j = __last; 103134723edSLouis Dionne if (!__comp(*__first, *--__j)) { // we need a guard if *__first == *(__last-1) 104134723edSLouis Dionne while (true) { 105134723edSLouis Dionne if (__i == __j) { 106134723edSLouis Dionne return; // [__first, __last) all equivalent elements 107134723edSLouis Dionne } else if (__comp(*__first, *__i)) { 108a7c3379cSKonstantin Varlamov _Ops::iter_swap(__i, __j); 109134723edSLouis Dionne ++__n_swaps; 110134723edSLouis Dionne ++__i; 111134723edSLouis Dionne break; 112134723edSLouis Dionne } 113134723edSLouis Dionne ++__i; 114134723edSLouis Dionne } 115134723edSLouis Dionne } 116134723edSLouis Dionne // [__first, __i) == *__first and *__first < [__j, __last) and __j == __last - 1 117134723edSLouis Dionne if (__i == __j) { 118134723edSLouis Dionne return; 119134723edSLouis Dionne } 120134723edSLouis Dionne while (true) { 121ea9af5e7SDaniel Kutenin while (!__comp(*__first, *__i)) { 122134723edSLouis Dionne ++__i; 123ea9af5e7SDaniel Kutenin _LIBCPP_ASSERT_UNCATEGORIZED( 124ea9af5e7SDaniel Kutenin __i != __last, 125ea9af5e7SDaniel Kutenin "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); 126ea9af5e7SDaniel Kutenin } 127ea9af5e7SDaniel Kutenin do { 128ea9af5e7SDaniel Kutenin _LIBCPP_ASSERT_UNCATEGORIZED( 129ea9af5e7SDaniel Kutenin __j != __first, 130ea9af5e7SDaniel Kutenin "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); 131ea9af5e7SDaniel Kutenin --__j; 132ea9af5e7SDaniel Kutenin } while (__comp(*__first, *__j)); 133134723edSLouis Dionne if (__i >= __j) 134134723edSLouis Dionne break; 135a7c3379cSKonstantin Varlamov _Ops::iter_swap(__i, __j); 136134723edSLouis Dionne ++__n_swaps; 137134723edSLouis Dionne ++__i; 138134723edSLouis Dionne } 139134723edSLouis Dionne // [__first, __i) == *__first and *__first < [__i, __last) 140134723edSLouis Dionne // The first part is sorted, 141134723edSLouis Dionne if (__nth < __i) { 142134723edSLouis Dionne return; 143134723edSLouis Dionne } 144134723edSLouis Dionne // __nth_element the second part 145*77a00c0dSLouis Dionne // std::__nth_element<_Compare>(__i, __nth, __last, __comp); 146134723edSLouis Dionne __first = __i; 147134723edSLouis Dionne continue; 148134723edSLouis Dionne } 149134723edSLouis Dionne } 150134723edSLouis Dionne ++__i; 151134723edSLouis Dionne // j points beyond range to be tested, *__lm1 is known to be <= *__m 152134723edSLouis Dionne // if not yet partitioned... 153134723edSLouis Dionne if (__i < __j) 154134723edSLouis Dionne { 155134723edSLouis Dionne // known that *(__i - 1) < *__m 156134723edSLouis Dionne while (true) 157134723edSLouis Dionne { 158134723edSLouis Dionne // __m still guards upward moving __i 159ea9af5e7SDaniel Kutenin while (__comp(*__i, *__m)) { 160134723edSLouis Dionne ++__i; 161ea9af5e7SDaniel Kutenin _LIBCPP_ASSERT_UNCATEGORIZED( 162ea9af5e7SDaniel Kutenin __i != __last, 163ea9af5e7SDaniel Kutenin "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); 164ea9af5e7SDaniel Kutenin } 165134723edSLouis Dionne // It is now known that a guard exists for downward moving __j 166ea9af5e7SDaniel Kutenin do { 167ea9af5e7SDaniel Kutenin _LIBCPP_ASSERT_UNCATEGORIZED( 168ea9af5e7SDaniel Kutenin __j != __first, 169ea9af5e7SDaniel Kutenin "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); 170ea9af5e7SDaniel Kutenin --__j; 171ea9af5e7SDaniel Kutenin } while (!__comp(*__j, *__m)); 172134723edSLouis Dionne if (__i >= __j) 173134723edSLouis Dionne break; 174a7c3379cSKonstantin Varlamov _Ops::iter_swap(__i, __j); 175134723edSLouis Dionne ++__n_swaps; 176134723edSLouis Dionne // It is known that __m != __j 177134723edSLouis Dionne // If __m just moved, follow it 178134723edSLouis Dionne if (__m == __i) 179134723edSLouis Dionne __m = __j; 180134723edSLouis Dionne ++__i; 181134723edSLouis Dionne } 182134723edSLouis Dionne } 183134723edSLouis Dionne // [__first, __i) < *__m and *__m <= [__i, __last) 184134723edSLouis Dionne if (__i != __m && __comp(*__m, *__i)) 185134723edSLouis Dionne { 186a7c3379cSKonstantin Varlamov _Ops::iter_swap(__i, __m); 187134723edSLouis Dionne ++__n_swaps; 188134723edSLouis Dionne } 189134723edSLouis Dionne // [__first, __i) < *__i and *__i <= [__i+1, __last) 190134723edSLouis Dionne if (__nth == __i) 191134723edSLouis Dionne return; 192134723edSLouis Dionne if (__n_swaps == 0) 193134723edSLouis Dionne { 194134723edSLouis Dionne // We were given a perfectly partitioned sequence. Coincidence? 195134723edSLouis Dionne if (__nth < __i) 196134723edSLouis Dionne { 197134723edSLouis Dionne // Check for [__first, __i) already sorted 198134723edSLouis Dionne __j = __m = __first; 199134723edSLouis Dionne while (true) { 200134723edSLouis Dionne if (++__j == __i) { 201134723edSLouis Dionne // [__first, __i) sorted 202134723edSLouis Dionne return; 203134723edSLouis Dionne } 204134723edSLouis Dionne if (__comp(*__j, *__m)) { 205134723edSLouis Dionne // not yet sorted, so sort 206134723edSLouis Dionne break; 207134723edSLouis Dionne } 208134723edSLouis Dionne __m = __j; 209134723edSLouis Dionne } 210134723edSLouis Dionne } 211134723edSLouis Dionne else 212134723edSLouis Dionne { 213134723edSLouis Dionne // Check for [__i, __last) already sorted 214134723edSLouis Dionne __j = __m = __i; 215134723edSLouis Dionne while (true) { 216134723edSLouis Dionne if (++__j == __last) { 217134723edSLouis Dionne // [__i, __last) sorted 218134723edSLouis Dionne return; 219134723edSLouis Dionne } 220134723edSLouis Dionne if (__comp(*__j, *__m)) { 221134723edSLouis Dionne // not yet sorted, so sort 222134723edSLouis Dionne break; 223134723edSLouis Dionne } 224134723edSLouis Dionne __m = __j; 225134723edSLouis Dionne } 226134723edSLouis Dionne } 227134723edSLouis Dionne } 228134723edSLouis Dionne // __nth_element on range containing __nth 229134723edSLouis Dionne if (__nth < __i) 230134723edSLouis Dionne { 231*77a00c0dSLouis Dionne // std::__nth_element<_Compare>(__first, __nth, __i, __comp); 232134723edSLouis Dionne __last = __i; 233134723edSLouis Dionne } 234134723edSLouis Dionne else 235134723edSLouis Dionne { 236*77a00c0dSLouis Dionne // std::__nth_element<_Compare>(__i+1, __nth, __last, __comp); 237134723edSLouis Dionne __first = ++__i; 238134723edSLouis Dionne } 239134723edSLouis Dionne } 240134723edSLouis Dionne } 241134723edSLouis Dionne 242a7c3379cSKonstantin Varlamov template <class _AlgPolicy, class _RandomAccessIterator, class _Compare> 2435146b57bSNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 24423c7328bSKonstantin Varlamov void __nth_element_impl(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, 24523c7328bSKonstantin Varlamov _Compare& __comp) { 24623c7328bSKonstantin Varlamov if (__nth == __last) 24723c7328bSKonstantin Varlamov return; 24823c7328bSKonstantin Varlamov 249a7c3379cSKonstantin Varlamov std::__debug_randomize_range<_AlgPolicy>(__first, __last); 25023c7328bSKonstantin Varlamov 251ed2d3644SNikolas Klauser std::__nth_element<_AlgPolicy, __comp_ref_type<_Compare> >(__first, __nth, __last, __comp); 25223c7328bSKonstantin Varlamov 253a7c3379cSKonstantin Varlamov std::__debug_randomize_range<_AlgPolicy>(__first, __nth); 254a45d2287SDanila Kutenin if (__nth != __last) { 255a7c3379cSKonstantin Varlamov std::__debug_randomize_range<_AlgPolicy>(++__nth, __last); 256a45d2287SDanila Kutenin } 257134723edSLouis Dionne } 258134723edSLouis Dionne 25923c7328bSKonstantin Varlamov template <class _RandomAccessIterator, class _Compare> 2605146b57bSNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 26123c7328bSKonstantin Varlamov void nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, 26223c7328bSKonstantin Varlamov _Compare __comp) { 263a7c3379cSKonstantin Varlamov std::__nth_element_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__nth), std::move(__last), __comp); 26423c7328bSKonstantin Varlamov } 26523c7328bSKonstantin Varlamov 266134723edSLouis Dionne template <class _RandomAccessIterator> 2675146b57bSNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 26823c7328bSKonstantin Varlamov void nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last) { 26988632e48SNikolas Klauser std::nth_element(std::move(__first), std::move(__nth), std::move(__last), __less<>()); 270134723edSLouis Dionne } 271134723edSLouis Dionne 272134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD 273134723edSLouis Dionne 274134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_NTH_ELEMENT_H 275