1 //===----------------------------------------------------------------------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef _LIBCPP___ALGORITHM_NTH_ELEMENT_H 10 #define _LIBCPP___ALGORITHM_NTH_ELEMENT_H 11 12 #include <__algorithm/comp.h> 13 #include <__algorithm/comp_ref_type.h> 14 #include <__algorithm/sort.h> 15 #include <__config> 16 #include <__debug> 17 #include <__debug_utils/randomize_range.h> 18 #include <__iterator/iterator_traits.h> 19 #include <__utility/swap.h> 20 21 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 22 # pragma GCC system_header 23 #endif 24 25 _LIBCPP_BEGIN_NAMESPACE_STD 26 27 template<class _Compare, class _RandomAccessIterator> 28 _LIBCPP_CONSTEXPR_AFTER_CXX11 bool 29 __nth_element_find_guard(_RandomAccessIterator& __i, _RandomAccessIterator& __j, 30 _RandomAccessIterator __m, _Compare __comp) 31 { 32 // manually guard downward moving __j against __i 33 while (true) { 34 if (__i == --__j) { 35 return false; 36 } 37 if (__comp(*__j, *__m)) { 38 return true; // found guard for downward moving __j, now use unguarded partition 39 } 40 } 41 } 42 43 template <class _Compare, class _RandomAccessIterator> 44 _LIBCPP_CONSTEXPR_AFTER_CXX11 void 45 __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp) 46 { 47 // _Compare is known to be a reference type 48 typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; 49 const difference_type __limit = 7; 50 while (true) 51 { 52 if (__nth == __last) 53 return; 54 difference_type __len = __last - __first; 55 switch (__len) 56 { 57 case 0: 58 case 1: 59 return; 60 case 2: 61 if (__comp(*--__last, *__first)) 62 swap(*__first, *__last); 63 return; 64 case 3: 65 { 66 _RandomAccessIterator __m = __first; 67 _VSTD::__sort3<_Compare>(__first, ++__m, --__last, __comp); 68 return; 69 } 70 } 71 if (__len <= __limit) 72 { 73 _VSTD::__selection_sort<_Compare>(__first, __last, __comp); 74 return; 75 } 76 // __len > __limit >= 3 77 _RandomAccessIterator __m = __first + __len/2; 78 _RandomAccessIterator __lm1 = __last; 79 unsigned __n_swaps = _VSTD::__sort3<_Compare>(__first, __m, --__lm1, __comp); 80 // *__m is median 81 // partition [__first, __m) < *__m and *__m <= [__m, __last) 82 // (this inhibits tossing elements equivalent to __m around unnecessarily) 83 _RandomAccessIterator __i = __first; 84 _RandomAccessIterator __j = __lm1; 85 // j points beyond range to be tested, *__lm1 is known to be <= *__m 86 // The search going up is known to be guarded but the search coming down isn't. 87 // Prime the downward search with a guard. 88 if (!__comp(*__i, *__m)) // if *__first == *__m 89 { 90 // *__first == *__m, *__first doesn't go in first part 91 if (_VSTD::__nth_element_find_guard<_Compare>(__i, __j, __m, __comp)) { 92 swap(*__i, *__j); 93 ++__n_swaps; 94 } else { 95 // *__first == *__m, *__m <= all other elements 96 // Partition instead into [__first, __i) == *__first and *__first < [__i, __last) 97 ++__i; // __first + 1 98 __j = __last; 99 if (!__comp(*__first, *--__j)) { // we need a guard if *__first == *(__last-1) 100 while (true) { 101 if (__i == __j) { 102 return; // [__first, __last) all equivalent elements 103 } else if (__comp(*__first, *__i)) { 104 swap(*__i, *__j); 105 ++__n_swaps; 106 ++__i; 107 break; 108 } 109 ++__i; 110 } 111 } 112 // [__first, __i) == *__first and *__first < [__j, __last) and __j == __last - 1 113 if (__i == __j) { 114 return; 115 } 116 while (true) { 117 while (!__comp(*__first, *__i)) 118 ++__i; 119 while (__comp(*__first, *--__j)) 120 ; 121 if (__i >= __j) 122 break; 123 swap(*__i, *__j); 124 ++__n_swaps; 125 ++__i; 126 } 127 // [__first, __i) == *__first and *__first < [__i, __last) 128 // The first part is sorted, 129 if (__nth < __i) { 130 return; 131 } 132 // __nth_element the second part 133 // _VSTD::__nth_element<_Compare>(__i, __nth, __last, __comp); 134 __first = __i; 135 continue; 136 } 137 } 138 ++__i; 139 // j points beyond range to be tested, *__lm1 is known to be <= *__m 140 // if not yet partitioned... 141 if (__i < __j) 142 { 143 // known that *(__i - 1) < *__m 144 while (true) 145 { 146 // __m still guards upward moving __i 147 while (__comp(*__i, *__m)) 148 ++__i; 149 // It is now known that a guard exists for downward moving __j 150 while (!__comp(*--__j, *__m)) 151 ; 152 if (__i >= __j) 153 break; 154 swap(*__i, *__j); 155 ++__n_swaps; 156 // It is known that __m != __j 157 // If __m just moved, follow it 158 if (__m == __i) 159 __m = __j; 160 ++__i; 161 } 162 } 163 // [__first, __i) < *__m and *__m <= [__i, __last) 164 if (__i != __m && __comp(*__m, *__i)) 165 { 166 swap(*__i, *__m); 167 ++__n_swaps; 168 } 169 // [__first, __i) < *__i and *__i <= [__i+1, __last) 170 if (__nth == __i) 171 return; 172 if (__n_swaps == 0) 173 { 174 // We were given a perfectly partitioned sequence. Coincidence? 175 if (__nth < __i) 176 { 177 // Check for [__first, __i) already sorted 178 __j = __m = __first; 179 while (true) { 180 if (++__j == __i) { 181 // [__first, __i) sorted 182 return; 183 } 184 if (__comp(*__j, *__m)) { 185 // not yet sorted, so sort 186 break; 187 } 188 __m = __j; 189 } 190 } 191 else 192 { 193 // Check for [__i, __last) already sorted 194 __j = __m = __i; 195 while (true) { 196 if (++__j == __last) { 197 // [__i, __last) sorted 198 return; 199 } 200 if (__comp(*__j, *__m)) { 201 // not yet sorted, so sort 202 break; 203 } 204 __m = __j; 205 } 206 } 207 } 208 // __nth_element on range containing __nth 209 if (__nth < __i) 210 { 211 // _VSTD::__nth_element<_Compare>(__first, __nth, __i, __comp); 212 __last = __i; 213 } 214 else 215 { 216 // _VSTD::__nth_element<_Compare>(__i+1, __nth, __last, __comp); 217 __first = ++__i; 218 } 219 } 220 } 221 222 template <class _RandomAccessIterator, class _Compare> 223 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 224 void 225 nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp) 226 { 227 std::__debug_randomize_range(__first, __last); 228 typedef typename __comp_ref_type<_Compare>::type _Comp_ref; 229 _VSTD::__nth_element<_Comp_ref>(__first, __nth, __last, __comp); 230 std::__debug_randomize_range(__first, __nth); 231 if (__nth != __last) { 232 std::__debug_randomize_range(++__nth, __last); 233 } 234 } 235 236 template <class _RandomAccessIterator> 237 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 238 void 239 nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last) 240 { 241 _VSTD::nth_element(__first, __nth, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>()); 242 } 243 244 _LIBCPP_END_NAMESPACE_STD 245 246 #endif // _LIBCPP___ALGORITHM_NTH_ELEMENT_H 247