xref: /freebsd/contrib/llvm-project/libcxx/include/__algorithm/stable_partition.h (revision b3edf4467982447620505a28fc82e38a414c07dc)
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