1e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===// 2e78f53d1SNikolas Klauser // 3e78f53d1SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e78f53d1SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information. 5e78f53d1SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e78f53d1SNikolas Klauser // 7e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===// 8e78f53d1SNikolas Klauser 9*ce777190SNikolas Klauser #ifndef _LIBCPP___CXX03___ALGORITHM_NTH_ELEMENT_H 10*ce777190SNikolas Klauser #define _LIBCPP___CXX03___ALGORITHM_NTH_ELEMENT_H 11e78f53d1SNikolas Klauser 1273fbae83SNikolas Klauser #include <__cxx03/__algorithm/comp.h> 1373fbae83SNikolas Klauser #include <__cxx03/__algorithm/comp_ref_type.h> 1473fbae83SNikolas Klauser #include <__cxx03/__algorithm/iterator_operations.h> 1573fbae83SNikolas Klauser #include <__cxx03/__algorithm/sort.h> 1673fbae83SNikolas Klauser #include <__cxx03/__assert> 1773fbae83SNikolas Klauser #include <__cxx03/__config> 1873fbae83SNikolas Klauser #include <__cxx03/__debug_utils/randomize_range.h> 1973fbae83SNikolas Klauser #include <__cxx03/__iterator/iterator_traits.h> 2073fbae83SNikolas Klauser #include <__cxx03/__utility/move.h> 21e78f53d1SNikolas Klauser 22e78f53d1SNikolas Klauser #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 23e78f53d1SNikolas Klauser # pragma GCC system_header 24e78f53d1SNikolas Klauser #endif 25e78f53d1SNikolas Klauser 26e78f53d1SNikolas Klauser _LIBCPP_PUSH_MACROS 2773fbae83SNikolas Klauser #include <__cxx03/__undef_macros> 28e78f53d1SNikolas Klauser 29e78f53d1SNikolas Klauser _LIBCPP_BEGIN_NAMESPACE_STD 30e78f53d1SNikolas Klauser 31e78f53d1SNikolas Klauser template <class _Compare, class _RandomAccessIterator> 32e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool __nth_element_find_guard( 33e78f53d1SNikolas Klauser _RandomAccessIterator& __i, _RandomAccessIterator& __j, _RandomAccessIterator __m, _Compare __comp) { 34e78f53d1SNikolas Klauser // manually guard downward moving __j against __i 35e78f53d1SNikolas Klauser while (true) { 36e78f53d1SNikolas Klauser if (__i == --__j) { 37e78f53d1SNikolas Klauser return false; 38e78f53d1SNikolas Klauser } 39e78f53d1SNikolas Klauser if (__comp(*__j, *__m)) { 40e78f53d1SNikolas Klauser return true; // found guard for downward moving __j, now use unguarded partition 41e78f53d1SNikolas Klauser } 42e78f53d1SNikolas Klauser } 43e78f53d1SNikolas Klauser } 44e78f53d1SNikolas Klauser 45e78f53d1SNikolas Klauser template <class _AlgPolicy, class _Compare, class _RandomAccessIterator> 46e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void 47e78f53d1SNikolas Klauser // NOLINTNEXTLINE(readability-function-cognitive-complexity) 48e78f53d1SNikolas Klauser __nth_element( 49e78f53d1SNikolas Klauser _RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp) { 50e78f53d1SNikolas Klauser using _Ops = _IterOps<_AlgPolicy>; 51e78f53d1SNikolas Klauser 52e78f53d1SNikolas Klauser // _Compare is known to be a reference type 53e78f53d1SNikolas Klauser typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; 54e78f53d1SNikolas Klauser const difference_type __limit = 7; 55e78f53d1SNikolas Klauser while (true) { 56e78f53d1SNikolas Klauser if (__nth == __last) 57e78f53d1SNikolas Klauser return; 58e78f53d1SNikolas Klauser difference_type __len = __last - __first; 59e78f53d1SNikolas Klauser switch (__len) { 60e78f53d1SNikolas Klauser case 0: 61e78f53d1SNikolas Klauser case 1: 62e78f53d1SNikolas Klauser return; 63e78f53d1SNikolas Klauser case 2: 64e78f53d1SNikolas Klauser if (__comp(*--__last, *__first)) 65e78f53d1SNikolas Klauser _Ops::iter_swap(__first, __last); 66e78f53d1SNikolas Klauser return; 67e78f53d1SNikolas Klauser case 3: { 68e78f53d1SNikolas Klauser _RandomAccessIterator __m = __first; 69e78f53d1SNikolas Klauser std::__sort3<_AlgPolicy, _Compare>(__first, ++__m, --__last, __comp); 70e78f53d1SNikolas Klauser return; 71e78f53d1SNikolas Klauser } 72e78f53d1SNikolas Klauser } 73e78f53d1SNikolas Klauser if (__len <= __limit) { 74e78f53d1SNikolas Klauser std::__selection_sort<_AlgPolicy, _Compare>(__first, __last, __comp); 75e78f53d1SNikolas Klauser return; 76e78f53d1SNikolas Klauser } 77e78f53d1SNikolas Klauser // __len > __limit >= 3 78e78f53d1SNikolas Klauser _RandomAccessIterator __m = __first + __len / 2; 79e78f53d1SNikolas Klauser _RandomAccessIterator __lm1 = __last; 80e78f53d1SNikolas Klauser unsigned __n_swaps = std::__sort3<_AlgPolicy, _Compare>(__first, __m, --__lm1, __comp); 81e78f53d1SNikolas Klauser // *__m is median 82e78f53d1SNikolas Klauser // partition [__first, __m) < *__m and *__m <= [__m, __last) 83e78f53d1SNikolas Klauser // (this inhibits tossing elements equivalent to __m around unnecessarily) 84e78f53d1SNikolas Klauser _RandomAccessIterator __i = __first; 85e78f53d1SNikolas Klauser _RandomAccessIterator __j = __lm1; 86e78f53d1SNikolas Klauser // j points beyond range to be tested, *__lm1 is known to be <= *__m 87e78f53d1SNikolas Klauser // The search going up is known to be guarded but the search coming down isn't. 88e78f53d1SNikolas Klauser // Prime the downward search with a guard. 89e78f53d1SNikolas Klauser if (!__comp(*__i, *__m)) // if *__first == *__m 90e78f53d1SNikolas Klauser { 91e78f53d1SNikolas Klauser // *__first == *__m, *__first doesn't go in first part 92e78f53d1SNikolas Klauser if (std::__nth_element_find_guard<_Compare>(__i, __j, __m, __comp)) { 93e78f53d1SNikolas Klauser _Ops::iter_swap(__i, __j); 94e78f53d1SNikolas Klauser ++__n_swaps; 95e78f53d1SNikolas Klauser } else { 96e78f53d1SNikolas Klauser // *__first == *__m, *__m <= all other elements 97e78f53d1SNikolas Klauser // Partition instead into [__first, __i) == *__first and *__first < [__i, __last) 98e78f53d1SNikolas Klauser ++__i; // __first + 1 99e78f53d1SNikolas Klauser __j = __last; 100e78f53d1SNikolas Klauser if (!__comp(*__first, *--__j)) { // we need a guard if *__first == *(__last-1) 101e78f53d1SNikolas Klauser while (true) { 102e78f53d1SNikolas Klauser if (__i == __j) { 103e78f53d1SNikolas Klauser return; // [__first, __last) all equivalent elements 104e78f53d1SNikolas Klauser } else if (__comp(*__first, *__i)) { 105e78f53d1SNikolas Klauser _Ops::iter_swap(__i, __j); 106e78f53d1SNikolas Klauser ++__n_swaps; 107e78f53d1SNikolas Klauser ++__i; 108e78f53d1SNikolas Klauser break; 109e78f53d1SNikolas Klauser } 110e78f53d1SNikolas Klauser ++__i; 111e78f53d1SNikolas Klauser } 112e78f53d1SNikolas Klauser } 113e78f53d1SNikolas Klauser // [__first, __i) == *__first and *__first < [__j, __last) and __j == __last - 1 114e78f53d1SNikolas Klauser if (__i == __j) { 115e78f53d1SNikolas Klauser return; 116e78f53d1SNikolas Klauser } 117e78f53d1SNikolas Klauser while (true) { 118e78f53d1SNikolas Klauser while (!__comp(*__first, *__i)) { 119e78f53d1SNikolas Klauser ++__i; 120e78f53d1SNikolas Klauser _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 121e78f53d1SNikolas Klauser __i != __last, 122e78f53d1SNikolas Klauser "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); 123e78f53d1SNikolas Klauser } 124e78f53d1SNikolas Klauser do { 125e78f53d1SNikolas Klauser _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 126e78f53d1SNikolas Klauser __j != __first, 127e78f53d1SNikolas Klauser "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); 128e78f53d1SNikolas Klauser --__j; 129e78f53d1SNikolas Klauser } while (__comp(*__first, *__j)); 130e78f53d1SNikolas Klauser if (__i >= __j) 131e78f53d1SNikolas Klauser break; 132e78f53d1SNikolas Klauser _Ops::iter_swap(__i, __j); 133e78f53d1SNikolas Klauser ++__n_swaps; 134e78f53d1SNikolas Klauser ++__i; 135e78f53d1SNikolas Klauser } 136e78f53d1SNikolas Klauser // [__first, __i) == *__first and *__first < [__i, __last) 137e78f53d1SNikolas Klauser // The first part is sorted, 138e78f53d1SNikolas Klauser if (__nth < __i) { 139e78f53d1SNikolas Klauser return; 140e78f53d1SNikolas Klauser } 141e78f53d1SNikolas Klauser // __nth_element the second part 142e78f53d1SNikolas Klauser // std::__nth_element<_Compare>(__i, __nth, __last, __comp); 143e78f53d1SNikolas Klauser __first = __i; 144e78f53d1SNikolas Klauser continue; 145e78f53d1SNikolas Klauser } 146e78f53d1SNikolas Klauser } 147e78f53d1SNikolas Klauser ++__i; 148e78f53d1SNikolas Klauser // j points beyond range to be tested, *__lm1 is known to be <= *__m 149e78f53d1SNikolas Klauser // if not yet partitioned... 150e78f53d1SNikolas Klauser if (__i < __j) { 151e78f53d1SNikolas Klauser // known that *(__i - 1) < *__m 152e78f53d1SNikolas Klauser while (true) { 153e78f53d1SNikolas Klauser // __m still guards upward moving __i 154e78f53d1SNikolas Klauser while (__comp(*__i, *__m)) { 155e78f53d1SNikolas Klauser ++__i; 156e78f53d1SNikolas Klauser _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 157e78f53d1SNikolas Klauser __i != __last, 158e78f53d1SNikolas Klauser "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); 159e78f53d1SNikolas Klauser } 160e78f53d1SNikolas Klauser // It is now known that a guard exists for downward moving __j 161e78f53d1SNikolas Klauser do { 162e78f53d1SNikolas Klauser _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 163e78f53d1SNikolas Klauser __j != __first, 164e78f53d1SNikolas Klauser "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); 165e78f53d1SNikolas Klauser --__j; 166e78f53d1SNikolas Klauser } while (!__comp(*__j, *__m)); 167e78f53d1SNikolas Klauser if (__i >= __j) 168e78f53d1SNikolas Klauser break; 169e78f53d1SNikolas Klauser _Ops::iter_swap(__i, __j); 170e78f53d1SNikolas Klauser ++__n_swaps; 171e78f53d1SNikolas Klauser // It is known that __m != __j 172e78f53d1SNikolas Klauser // If __m just moved, follow it 173e78f53d1SNikolas Klauser if (__m == __i) 174e78f53d1SNikolas Klauser __m = __j; 175e78f53d1SNikolas Klauser ++__i; 176e78f53d1SNikolas Klauser } 177e78f53d1SNikolas Klauser } 178e78f53d1SNikolas Klauser // [__first, __i) < *__m and *__m <= [__i, __last) 179e78f53d1SNikolas Klauser if (__i != __m && __comp(*__m, *__i)) { 180e78f53d1SNikolas Klauser _Ops::iter_swap(__i, __m); 181e78f53d1SNikolas Klauser ++__n_swaps; 182e78f53d1SNikolas Klauser } 183e78f53d1SNikolas Klauser // [__first, __i) < *__i and *__i <= [__i+1, __last) 184e78f53d1SNikolas Klauser if (__nth == __i) 185e78f53d1SNikolas Klauser return; 186e78f53d1SNikolas Klauser if (__n_swaps == 0) { 187e78f53d1SNikolas Klauser // We were given a perfectly partitioned sequence. Coincidence? 188e78f53d1SNikolas Klauser if (__nth < __i) { 189e78f53d1SNikolas Klauser // Check for [__first, __i) already sorted 190e78f53d1SNikolas Klauser __j = __m = __first; 191e78f53d1SNikolas Klauser while (true) { 192e78f53d1SNikolas Klauser if (++__j == __i) { 193e78f53d1SNikolas Klauser // [__first, __i) sorted 194e78f53d1SNikolas Klauser return; 195e78f53d1SNikolas Klauser } 196e78f53d1SNikolas Klauser if (__comp(*__j, *__m)) { 197e78f53d1SNikolas Klauser // not yet sorted, so sort 198e78f53d1SNikolas Klauser break; 199e78f53d1SNikolas Klauser } 200e78f53d1SNikolas Klauser __m = __j; 201e78f53d1SNikolas Klauser } 202e78f53d1SNikolas Klauser } else { 203e78f53d1SNikolas Klauser // Check for [__i, __last) already sorted 204e78f53d1SNikolas Klauser __j = __m = __i; 205e78f53d1SNikolas Klauser while (true) { 206e78f53d1SNikolas Klauser if (++__j == __last) { 207e78f53d1SNikolas Klauser // [__i, __last) sorted 208e78f53d1SNikolas Klauser return; 209e78f53d1SNikolas Klauser } 210e78f53d1SNikolas Klauser if (__comp(*__j, *__m)) { 211e78f53d1SNikolas Klauser // not yet sorted, so sort 212e78f53d1SNikolas Klauser break; 213e78f53d1SNikolas Klauser } 214e78f53d1SNikolas Klauser __m = __j; 215e78f53d1SNikolas Klauser } 216e78f53d1SNikolas Klauser } 217e78f53d1SNikolas Klauser } 218e78f53d1SNikolas Klauser // __nth_element on range containing __nth 219e78f53d1SNikolas Klauser if (__nth < __i) { 220e78f53d1SNikolas Klauser // std::__nth_element<_Compare>(__first, __nth, __i, __comp); 221e78f53d1SNikolas Klauser __last = __i; 222e78f53d1SNikolas Klauser } else { 223e78f53d1SNikolas Klauser // std::__nth_element<_Compare>(__i+1, __nth, __last, __comp); 224e78f53d1SNikolas Klauser __first = ++__i; 225e78f53d1SNikolas Klauser } 226e78f53d1SNikolas Klauser } 227e78f53d1SNikolas Klauser } 228e78f53d1SNikolas Klauser 229e78f53d1SNikolas Klauser template <class _AlgPolicy, class _RandomAccessIterator, class _Compare> 230e78f53d1SNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __nth_element_impl( 231e78f53d1SNikolas Klauser _RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare& __comp) { 232e78f53d1SNikolas Klauser if (__nth == __last) 233e78f53d1SNikolas Klauser return; 234e78f53d1SNikolas Klauser 235e78f53d1SNikolas Klauser std::__debug_randomize_range<_AlgPolicy>(__first, __last); 236e78f53d1SNikolas Klauser 237e78f53d1SNikolas Klauser std::__nth_element<_AlgPolicy, __comp_ref_type<_Compare> >(__first, __nth, __last, __comp); 238e78f53d1SNikolas Klauser 239e78f53d1SNikolas Klauser std::__debug_randomize_range<_AlgPolicy>(__first, __nth); 240e78f53d1SNikolas Klauser if (__nth != __last) { 241e78f53d1SNikolas Klauser std::__debug_randomize_range<_AlgPolicy>(++__nth, __last); 242e78f53d1SNikolas Klauser } 243e78f53d1SNikolas Klauser } 244e78f53d1SNikolas Klauser 245e78f53d1SNikolas Klauser template <class _RandomAccessIterator, class _Compare> 246e78f53d1SNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void 247e78f53d1SNikolas Klauser nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp) { 248e78f53d1SNikolas Klauser std::__nth_element_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__nth), std::move(__last), __comp); 249e78f53d1SNikolas Klauser } 250e78f53d1SNikolas Klauser 251e78f53d1SNikolas Klauser template <class _RandomAccessIterator> 252e78f53d1SNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void 253e78f53d1SNikolas Klauser nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last) { 254e78f53d1SNikolas Klauser std::nth_element(std::move(__first), std::move(__nth), std::move(__last), __less<>()); 255e78f53d1SNikolas Klauser } 256e78f53d1SNikolas Klauser 257e78f53d1SNikolas Klauser _LIBCPP_END_NAMESPACE_STD 258e78f53d1SNikolas Klauser 259e78f53d1SNikolas Klauser _LIBCPP_POP_MACROS 260e78f53d1SNikolas Klauser 261*ce777190SNikolas Klauser #endif // _LIBCPP___CXX03___ALGORITHM_NTH_ELEMENT_H 262