File indexing completed on 2026-05-03 08:13:09
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef _LIBCPP___ALGORITHM_NTH_ELEMENT_H
0010 #define _LIBCPP___ALGORITHM_NTH_ELEMENT_H
0011
0012 #include <__algorithm/comp.h>
0013 #include <__algorithm/comp_ref_type.h>
0014 #include <__algorithm/iterator_operations.h>
0015 #include <__algorithm/sort.h>
0016 #include <__assert>
0017 #include <__config>
0018 #include <__debug_utils/randomize_range.h>
0019 #include <__iterator/iterator_traits.h>
0020 #include <__utility/move.h>
0021
0022 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0023 # pragma GCC system_header
0024 #endif
0025
0026 _LIBCPP_PUSH_MACROS
0027 #include <__undef_macros>
0028
0029 _LIBCPP_BEGIN_NAMESPACE_STD
0030
0031 template <class _Compare, class _RandomAccessIterator>
0032 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool __nth_element_find_guard(
0033 _RandomAccessIterator& __i, _RandomAccessIterator& __j, _RandomAccessIterator __m, _Compare __comp) {
0034
0035 while (true) {
0036 if (__i == --__j) {
0037 return false;
0038 }
0039 if (__comp(*__j, *__m)) {
0040 return true;
0041 }
0042 }
0043 }
0044
0045 template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
0046 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
0047
0048 __nth_element(
0049 _RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp) {
0050 using _Ops = _IterOps<_AlgPolicy>;
0051
0052
0053 typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
0054 const difference_type __limit = 7;
0055 while (true) {
0056 if (__nth == __last)
0057 return;
0058 difference_type __len = __last - __first;
0059 switch (__len) {
0060 case 0:
0061 case 1:
0062 return;
0063 case 2:
0064 if (__comp(*--__last, *__first))
0065 _Ops::iter_swap(__first, __last);
0066 return;
0067 case 3: {
0068 _RandomAccessIterator __m = __first;
0069 std::__sort3<_AlgPolicy, _Compare>(__first, ++__m, --__last, __comp);
0070 return;
0071 }
0072 }
0073 if (__len <= __limit) {
0074 std::__selection_sort<_AlgPolicy, _Compare>(__first, __last, __comp);
0075 return;
0076 }
0077
0078 _RandomAccessIterator __m = __first + __len / 2;
0079 _RandomAccessIterator __lm1 = __last;
0080 unsigned __n_swaps = std::__sort3<_AlgPolicy, _Compare>(__first, __m, --__lm1, __comp);
0081
0082
0083
0084 _RandomAccessIterator __i = __first;
0085 _RandomAccessIterator __j = __lm1;
0086
0087
0088
0089 if (!__comp(*__i, *__m))
0090 {
0091
0092 if (std::__nth_element_find_guard<_Compare>(__i, __j, __m, __comp)) {
0093 _Ops::iter_swap(__i, __j);
0094 ++__n_swaps;
0095 } else {
0096
0097
0098 ++__i;
0099 __j = __last;
0100 if (!__comp(*__first, *--__j)) {
0101 while (true) {
0102 if (__i == __j) {
0103 return;
0104 } else if (__comp(*__first, *__i)) {
0105 _Ops::iter_swap(__i, __j);
0106 ++__n_swaps;
0107 ++__i;
0108 break;
0109 }
0110 ++__i;
0111 }
0112 }
0113
0114 if (__i == __j) {
0115 return;
0116 }
0117 while (true) {
0118 while (!__comp(*__first, *__i)) {
0119 ++__i;
0120 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0121 __i != __last,
0122 "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
0123 }
0124 do {
0125 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0126 __j != __first,
0127 "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
0128 --__j;
0129 } while (__comp(*__first, *__j));
0130 if (__i >= __j)
0131 break;
0132 _Ops::iter_swap(__i, __j);
0133 ++__n_swaps;
0134 ++__i;
0135 }
0136
0137
0138 if (__nth < __i) {
0139 return;
0140 }
0141
0142
0143 __first = __i;
0144 continue;
0145 }
0146 }
0147 ++__i;
0148
0149
0150 if (__i < __j) {
0151
0152 while (true) {
0153
0154 while (__comp(*__i, *__m)) {
0155 ++__i;
0156 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0157 __i != __last,
0158 "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
0159 }
0160
0161 do {
0162 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0163 __j != __first,
0164 "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?");
0165 --__j;
0166 } while (!__comp(*__j, *__m));
0167 if (__i >= __j)
0168 break;
0169 _Ops::iter_swap(__i, __j);
0170 ++__n_swaps;
0171
0172
0173 if (__m == __i)
0174 __m = __j;
0175 ++__i;
0176 }
0177 }
0178
0179 if (__i != __m && __comp(*__m, *__i)) {
0180 _Ops::iter_swap(__i, __m);
0181 ++__n_swaps;
0182 }
0183
0184 if (__nth == __i)
0185 return;
0186 if (__n_swaps == 0) {
0187
0188 if (__nth < __i) {
0189
0190 __j = __m = __first;
0191 while (true) {
0192 if (++__j == __i) {
0193
0194 return;
0195 }
0196 if (__comp(*__j, *__m)) {
0197
0198 break;
0199 }
0200 __m = __j;
0201 }
0202 } else {
0203
0204 __j = __m = __i;
0205 while (true) {
0206 if (++__j == __last) {
0207
0208 return;
0209 }
0210 if (__comp(*__j, *__m)) {
0211
0212 break;
0213 }
0214 __m = __j;
0215 }
0216 }
0217 }
0218
0219 if (__nth < __i) {
0220
0221 __last = __i;
0222 } else {
0223
0224 __first = ++__i;
0225 }
0226 }
0227 }
0228
0229 template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
0230 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __nth_element_impl(
0231 _RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare& __comp) {
0232 if (__nth == __last)
0233 return;
0234
0235 std::__debug_randomize_range<_AlgPolicy>(__first, __last);
0236
0237 std::__nth_element<_AlgPolicy, __comp_ref_type<_Compare> >(__first, __nth, __last, __comp);
0238
0239 std::__debug_randomize_range<_AlgPolicy>(__first, __nth);
0240 if (__nth != __last) {
0241 std::__debug_randomize_range<_AlgPolicy>(++__nth, __last);
0242 }
0243 }
0244
0245 template <class _RandomAccessIterator, class _Compare>
0246 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
0247 nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp) {
0248 std::__nth_element_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__nth), std::move(__last), __comp);
0249 }
0250
0251 template <class _RandomAccessIterator>
0252 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
0253 nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last) {
0254 std::nth_element(std::move(__first), std::move(__nth), std::move(__last), __less<>());
0255 }
0256
0257 _LIBCPP_END_NAMESPACE_STD
0258
0259 _LIBCPP_POP_MACROS
0260
0261 #endif