1fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric 9fe6060f1SDimitry Andric #ifndef _LIBCPP___ALGORITHM_STABLE_PARTITION_H 10fe6060f1SDimitry Andric #define _LIBCPP___ALGORITHM_STABLE_PARTITION_H 11fe6060f1SDimitry Andric 12fcaf7f86SDimitry Andric #include <__algorithm/iterator_operations.h> 13fe6060f1SDimitry Andric #include <__algorithm/rotate.h> 1404eeddc0SDimitry Andric #include <__config> 1581ad6265SDimitry Andric #include <__iterator/advance.h> 1681ad6265SDimitry Andric #include <__iterator/distance.h> 17fe6060f1SDimitry Andric #include <__iterator/iterator_traits.h> 18bdd1243dSDimitry Andric #include <__memory/destruct_n.h> 19bdd1243dSDimitry Andric #include <__memory/temporary_buffer.h> 20bdd1243dSDimitry Andric #include <__memory/unique_ptr.h> 21bdd1243dSDimitry Andric #include <__utility/move.h> 22bdd1243dSDimitry Andric #include <__utility/pair.h> 23bdd1243dSDimitry Andric #include <new> 24fe6060f1SDimitry Andric 25fe6060f1SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 26fe6060f1SDimitry Andric # pragma GCC system_header 27fe6060f1SDimitry Andric #endif 28fe6060f1SDimitry Andric 29*b3edf446SDimitry Andric _LIBCPP_PUSH_MACROS 30*b3edf446SDimitry Andric #include <__undef_macros> 31*b3edf446SDimitry Andric 32fe6060f1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 33fe6060f1SDimitry Andric 34fcaf7f86SDimitry Andric template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _Distance, class _Pair> 35cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition_impl( 36cb14a3feSDimitry Andric _ForwardIterator __first, 37cb14a3feSDimitry Andric _ForwardIterator __last, 38cb14a3feSDimitry Andric _Predicate __pred, 39cb14a3feSDimitry Andric _Distance __len, 40cb14a3feSDimitry Andric _Pair __p, 41cb14a3feSDimitry Andric forward_iterator_tag __fit) { 42fcaf7f86SDimitry Andric using _Ops = _IterOps<_AlgPolicy>; 43fcaf7f86SDimitry Andric 44fe6060f1SDimitry Andric // *__first is known to be false 45fe6060f1SDimitry Andric // __len >= 1 46fe6060f1SDimitry Andric if (__len == 1) 47fe6060f1SDimitry Andric return __first; 48cb14a3feSDimitry Andric if (__len == 2) { 49fe6060f1SDimitry Andric _ForwardIterator __m = __first; 50cb14a3feSDimitry Andric if (__pred(*++__m)) { 51fcaf7f86SDimitry Andric _Ops::iter_swap(__first, __m); 52fe6060f1SDimitry Andric return __m; 53fe6060f1SDimitry Andric } 54fe6060f1SDimitry Andric return __first; 55fe6060f1SDimitry Andric } 56cb14a3feSDimitry Andric if (__len <= __p.second) { // The buffer is big enough to use 57fe6060f1SDimitry Andric typedef typename iterator_traits<_ForwardIterator>::value_type value_type; 58fe6060f1SDimitry Andric __destruct_n __d(0); 59fe6060f1SDimitry Andric unique_ptr<value_type, __destruct_n&> __h(__p.first, __d); 60fe6060f1SDimitry Andric // Move the falses into the temporary buffer, and the trues to the front of the line 61fe6060f1SDimitry Andric // Update __first to always point to the end of the trues 62fe6060f1SDimitry Andric value_type* __t = __p.first; 63fcaf7f86SDimitry Andric ::new ((void*)__t) value_type(_Ops::__iter_move(__first)); 64fe6060f1SDimitry Andric __d.template __incr<value_type>(); 65fe6060f1SDimitry Andric ++__t; 66fe6060f1SDimitry Andric _ForwardIterator __i = __first; 67cb14a3feSDimitry Andric while (++__i != __last) { 68cb14a3feSDimitry Andric if (__pred(*__i)) { 69fcaf7f86SDimitry Andric *__first = _Ops::__iter_move(__i); 70fe6060f1SDimitry Andric ++__first; 71cb14a3feSDimitry Andric } else { 72fcaf7f86SDimitry Andric ::new ((void*)__t) value_type(_Ops::__iter_move(__i)); 73fe6060f1SDimitry Andric __d.template __incr<value_type>(); 74fe6060f1SDimitry Andric ++__t; 75fe6060f1SDimitry Andric } 76fe6060f1SDimitry Andric } 77fe6060f1SDimitry Andric // All trues now at start of range, all falses in buffer 78fe6060f1SDimitry Andric // Move falses back into range, but don't mess up __first which points to first false 79fe6060f1SDimitry Andric __i = __first; 80fe6060f1SDimitry Andric for (value_type* __t2 = __p.first; __t2 < __t; ++__t2, (void)++__i) 81fcaf7f86SDimitry Andric *__i = _Ops::__iter_move(__t2); 82fe6060f1SDimitry Andric // __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer 83fe6060f1SDimitry Andric return __first; 84fe6060f1SDimitry Andric } 85fe6060f1SDimitry Andric // Else not enough buffer, do in place 86fe6060f1SDimitry Andric // __len >= 3 87fe6060f1SDimitry Andric _ForwardIterator __m = __first; 88fe6060f1SDimitry Andric _Distance __len2 = __len / 2; // __len2 >= 2 89fcaf7f86SDimitry Andric _Ops::advance(__m, __len2); 90fe6060f1SDimitry Andric // recurse on [__first, __m), *__first know to be false 91fe6060f1SDimitry Andric // F????????????????? 92fe6060f1SDimitry Andric // f m l 93cb14a3feSDimitry Andric _ForwardIterator __first_false = 94cb14a3feSDimitry Andric std::__stable_partition_impl<_AlgPolicy, _Predicate&>(__first, __m, __pred, __len2, __p, __fit); 95fe6060f1SDimitry Andric // TTTFFFFF?????????? 96fe6060f1SDimitry Andric // f ff m l 97fe6060f1SDimitry Andric // recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true 98fe6060f1SDimitry Andric _ForwardIterator __m1 = __m; 99fe6060f1SDimitry Andric _ForwardIterator __second_false = __last; 100fe6060f1SDimitry Andric _Distance __len_half = __len - __len2; 101cb14a3feSDimitry Andric while (__pred(*__m1)) { 102fe6060f1SDimitry Andric if (++__m1 == __last) 103fe6060f1SDimitry Andric goto __second_half_done; 104fe6060f1SDimitry Andric --__len_half; 105fe6060f1SDimitry Andric } 106fe6060f1SDimitry Andric // TTTFFFFFTTTF?????? 107fe6060f1SDimitry Andric // f ff m m1 l 108cb14a3feSDimitry Andric __second_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(__m1, __last, __pred, __len_half, __p, __fit); 109fe6060f1SDimitry Andric __second_half_done: 110fe6060f1SDimitry Andric // TTTFFFFFTTTTTFFFFF 111fe6060f1SDimitry Andric // f ff m sf l 11261cfbce3SDimitry Andric return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false).first; 113fe6060f1SDimitry Andric // TTTTTTTTFFFFFFFFFF 114fe6060f1SDimitry Andric // | 115fe6060f1SDimitry Andric } 116fe6060f1SDimitry Andric 117fcaf7f86SDimitry Andric template <class _AlgPolicy, class _Predicate, class _ForwardIterator> 118bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _ForwardIterator 119cb14a3feSDimitry Andric __stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred, forward_iterator_tag) { 12006c3fb27SDimitry Andric typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type; 12106c3fb27SDimitry Andric typedef typename iterator_traits<_ForwardIterator>::value_type value_type; 12206c3fb27SDimitry Andric 12306c3fb27SDimitry Andric const difference_type __alloc_limit = 3; // might want to make this a function of trivial assignment 124fe6060f1SDimitry Andric // Either prove all true and return __first or point to first false 125cb14a3feSDimitry Andric while (true) { 126fe6060f1SDimitry Andric if (__first == __last) 127fe6060f1SDimitry Andric return __first; 128fe6060f1SDimitry Andric if (!__pred(*__first)) 129fe6060f1SDimitry Andric break; 130fe6060f1SDimitry Andric ++__first; 131fe6060f1SDimitry Andric } 132fe6060f1SDimitry Andric // We now have a reduced range [__first, __last) 133fe6060f1SDimitry Andric // *__first is known to be false 134fcaf7f86SDimitry Andric difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last); 135fe6060f1SDimitry Andric pair<value_type*, ptrdiff_t> __p(0, 0); 136fe6060f1SDimitry Andric unique_ptr<value_type, __return_temporary_buffer> __h; 137cb14a3feSDimitry Andric if (__len >= __alloc_limit) { 13881ad6265SDimitry Andric // TODO: Remove the use of std::get_temporary_buffer 13981ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH 1405f757f3fSDimitry Andric __p = std::get_temporary_buffer<value_type>(__len); 14181ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP 142fe6060f1SDimitry Andric __h.reset(__p.first); 143fe6060f1SDimitry Andric } 144fcaf7f86SDimitry Andric return std::__stable_partition_impl<_AlgPolicy, _Predicate&>( 145fcaf7f86SDimitry Andric std::move(__first), std::move(__last), __pred, __len, __p, forward_iterator_tag()); 146fe6060f1SDimitry Andric } 147fe6060f1SDimitry Andric 148fcaf7f86SDimitry Andric template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator, class _Distance, class _Pair> 149cb14a3feSDimitry Andric _BidirectionalIterator __stable_partition_impl( 150cb14a3feSDimitry Andric _BidirectionalIterator __first, 151cb14a3feSDimitry Andric _BidirectionalIterator __last, 152cb14a3feSDimitry Andric _Predicate __pred, 153cb14a3feSDimitry Andric _Distance __len, 154cb14a3feSDimitry Andric _Pair __p, 155cb14a3feSDimitry Andric bidirectional_iterator_tag __bit) { 156fcaf7f86SDimitry Andric using _Ops = _IterOps<_AlgPolicy>; 157fcaf7f86SDimitry Andric 158fe6060f1SDimitry Andric // *__first is known to be false 159fe6060f1SDimitry Andric // *__last is known to be true 160fe6060f1SDimitry Andric // __len >= 2 161cb14a3feSDimitry Andric if (__len == 2) { 162fcaf7f86SDimitry Andric _Ops::iter_swap(__first, __last); 163fe6060f1SDimitry Andric return __last; 164fe6060f1SDimitry Andric } 165cb14a3feSDimitry Andric if (__len == 3) { 166fe6060f1SDimitry Andric _BidirectionalIterator __m = __first; 167cb14a3feSDimitry Andric if (__pred(*++__m)) { 168fcaf7f86SDimitry Andric _Ops::iter_swap(__first, __m); 169fcaf7f86SDimitry Andric _Ops::iter_swap(__m, __last); 170fe6060f1SDimitry Andric return __last; 171fe6060f1SDimitry Andric } 172fcaf7f86SDimitry Andric _Ops::iter_swap(__m, __last); 173fcaf7f86SDimitry Andric _Ops::iter_swap(__first, __m); 174fe6060f1SDimitry Andric return __m; 175fe6060f1SDimitry Andric } 176cb14a3feSDimitry Andric if (__len <= __p.second) { // The buffer is big enough to use 177fe6060f1SDimitry Andric typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; 178fe6060f1SDimitry Andric __destruct_n __d(0); 179fe6060f1SDimitry Andric unique_ptr<value_type, __destruct_n&> __h(__p.first, __d); 180fe6060f1SDimitry Andric // Move the falses into the temporary buffer, and the trues to the front of the line 181fe6060f1SDimitry Andric // Update __first to always point to the end of the trues 182fe6060f1SDimitry Andric value_type* __t = __p.first; 183fcaf7f86SDimitry Andric ::new ((void*)__t) value_type(_Ops::__iter_move(__first)); 184fe6060f1SDimitry Andric __d.template __incr<value_type>(); 185fe6060f1SDimitry Andric ++__t; 186fe6060f1SDimitry Andric _BidirectionalIterator __i = __first; 187cb14a3feSDimitry Andric while (++__i != __last) { 188cb14a3feSDimitry Andric if (__pred(*__i)) { 189fcaf7f86SDimitry Andric *__first = _Ops::__iter_move(__i); 190fe6060f1SDimitry Andric ++__first; 191cb14a3feSDimitry Andric } else { 192fcaf7f86SDimitry Andric ::new ((void*)__t) value_type(_Ops::__iter_move(__i)); 193fe6060f1SDimitry Andric __d.template __incr<value_type>(); 194fe6060f1SDimitry Andric ++__t; 195fe6060f1SDimitry Andric } 196fe6060f1SDimitry Andric } 197fe6060f1SDimitry Andric // move *__last, known to be true 198fcaf7f86SDimitry Andric *__first = _Ops::__iter_move(__i); 199fe6060f1SDimitry Andric __i = ++__first; 200fe6060f1SDimitry Andric // All trues now at start of range, all falses in buffer 201fe6060f1SDimitry Andric // Move falses back into range, but don't mess up __first which points to first false 202fe6060f1SDimitry Andric for (value_type* __t2 = __p.first; __t2 < __t; ++__t2, (void)++__i) 203fcaf7f86SDimitry Andric *__i = _Ops::__iter_move(__t2); 204fe6060f1SDimitry Andric // __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer 205fe6060f1SDimitry Andric return __first; 206fe6060f1SDimitry Andric } 207fe6060f1SDimitry Andric // Else not enough buffer, do in place 208fe6060f1SDimitry Andric // __len >= 4 209fe6060f1SDimitry Andric _BidirectionalIterator __m = __first; 210fe6060f1SDimitry Andric _Distance __len2 = __len / 2; // __len2 >= 2 211fcaf7f86SDimitry Andric _Ops::advance(__m, __len2); 212fe6060f1SDimitry Andric // recurse on [__first, __m-1], except reduce __m-1 until *(__m-1) is true, *__first know to be false 213fe6060f1SDimitry Andric // F????????????????T 214fe6060f1SDimitry Andric // f m l 215fe6060f1SDimitry Andric _BidirectionalIterator __m1 = __m; 216fe6060f1SDimitry Andric _BidirectionalIterator __first_false = __first; 217fe6060f1SDimitry Andric _Distance __len_half = __len2; 218cb14a3feSDimitry Andric while (!__pred(*--__m1)) { 219fe6060f1SDimitry Andric if (__m1 == __first) 220fe6060f1SDimitry Andric goto __first_half_done; 221fe6060f1SDimitry Andric --__len_half; 222fe6060f1SDimitry Andric } 223fe6060f1SDimitry Andric // F???TFFF?????????T 224fe6060f1SDimitry Andric // f m1 m l 225cb14a3feSDimitry Andric __first_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(__first, __m1, __pred, __len_half, __p, __bit); 226fe6060f1SDimitry Andric __first_half_done: 227fe6060f1SDimitry Andric // TTTFFFFF?????????T 228fe6060f1SDimitry Andric // f ff m l 229fe6060f1SDimitry Andric // recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true 230fe6060f1SDimitry Andric __m1 = __m; 231fe6060f1SDimitry Andric _BidirectionalIterator __second_false = __last; 232fe6060f1SDimitry Andric ++__second_false; 233fe6060f1SDimitry Andric __len_half = __len - __len2; 234cb14a3feSDimitry Andric while (__pred(*__m1)) { 235fe6060f1SDimitry Andric if (++__m1 == __last) 236fe6060f1SDimitry Andric goto __second_half_done; 237fe6060f1SDimitry Andric --__len_half; 238fe6060f1SDimitry Andric } 239fe6060f1SDimitry Andric // TTTFFFFFTTTF?????T 240fe6060f1SDimitry Andric // f ff m m1 l 241cb14a3feSDimitry Andric __second_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(__m1, __last, __pred, __len_half, __p, __bit); 242fe6060f1SDimitry Andric __second_half_done: 243fe6060f1SDimitry Andric // TTTFFFFFTTTTTFFFFF 244fe6060f1SDimitry Andric // f ff m sf l 24561cfbce3SDimitry Andric return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false).first; 246fe6060f1SDimitry Andric // TTTTTTTTFFFFFFFFFF 247fe6060f1SDimitry Andric // | 248fe6060f1SDimitry Andric } 249fe6060f1SDimitry Andric 250fcaf7f86SDimitry Andric template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator> 251cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _BidirectionalIterator __stable_partition_impl( 252cb14a3feSDimitry Andric _BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred, bidirectional_iterator_tag) { 253fe6060f1SDimitry Andric typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type; 254fe6060f1SDimitry Andric typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; 255fe6060f1SDimitry Andric const difference_type __alloc_limit = 4; // might want to make this a function of trivial assignment 256fe6060f1SDimitry Andric // Either prove all true and return __first or point to first false 257cb14a3feSDimitry Andric while (true) { 258fe6060f1SDimitry Andric if (__first == __last) 259fe6060f1SDimitry Andric return __first; 260fe6060f1SDimitry Andric if (!__pred(*__first)) 261fe6060f1SDimitry Andric break; 262fe6060f1SDimitry Andric ++__first; 263fe6060f1SDimitry Andric } 264fe6060f1SDimitry Andric // __first points to first false, everything prior to __first is already set. 265fe6060f1SDimitry Andric // Either prove [__first, __last) is all false and return __first, or point __last to last true 266cb14a3feSDimitry Andric do { 267fe6060f1SDimitry Andric if (__first == --__last) 268fe6060f1SDimitry Andric return __first; 269fe6060f1SDimitry Andric } while (!__pred(*__last)); 270fe6060f1SDimitry Andric // We now have a reduced range [__first, __last] 271fe6060f1SDimitry Andric // *__first is known to be false 272fe6060f1SDimitry Andric // *__last is known to be true 273fe6060f1SDimitry Andric // __len >= 2 274fcaf7f86SDimitry Andric difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last) + 1; 275fe6060f1SDimitry Andric pair<value_type*, ptrdiff_t> __p(0, 0); 276fe6060f1SDimitry Andric unique_ptr<value_type, __return_temporary_buffer> __h; 277cb14a3feSDimitry Andric if (__len >= __alloc_limit) { 27881ad6265SDimitry Andric // TODO: Remove the use of std::get_temporary_buffer 27981ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH 2805f757f3fSDimitry Andric __p = std::get_temporary_buffer<value_type>(__len); 28181ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP 282fe6060f1SDimitry Andric __h.reset(__p.first); 283fe6060f1SDimitry Andric } 284fcaf7f86SDimitry Andric return std::__stable_partition_impl<_AlgPolicy, _Predicate&>( 285fcaf7f86SDimitry Andric std::move(__first), std::move(__last), __pred, __len, __p, bidirectional_iterator_tag()); 286fcaf7f86SDimitry Andric } 287fcaf7f86SDimitry Andric 288fcaf7f86SDimitry Andric template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _IterCategory> 289cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition( 290fcaf7f86SDimitry Andric _ForwardIterator __first, _ForwardIterator __last, _Predicate&& __pred, _IterCategory __iter_category) { 291bdd1243dSDimitry Andric return std::__stable_partition_impl<_AlgPolicy, __remove_cvref_t<_Predicate>&>( 292fcaf7f86SDimitry Andric std::move(__first), std::move(__last), __pred, __iter_category); 293fe6060f1SDimitry Andric } 294fe6060f1SDimitry Andric 295fe6060f1SDimitry Andric template <class _ForwardIterator, class _Predicate> 296cb14a3feSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator 297cb14a3feSDimitry Andric stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { 298fcaf7f86SDimitry Andric using _IterCategory = typename iterator_traits<_ForwardIterator>::iterator_category; 299fcaf7f86SDimitry Andric return std::__stable_partition<_ClassicAlgPolicy, _Predicate&>( 300fcaf7f86SDimitry Andric std::move(__first), std::move(__last), __pred, _IterCategory()); 301fe6060f1SDimitry Andric } 302fe6060f1SDimitry Andric 303fe6060f1SDimitry Andric _LIBCPP_END_NAMESPACE_STD 304fe6060f1SDimitry Andric 305*b3edf446SDimitry Andric _LIBCPP_POP_MACROS 306*b3edf446SDimitry Andric 307fe6060f1SDimitry Andric #endif // _LIBCPP___ALGORITHM_STABLE_PARTITION_H 308