xref: /llvm-project/libcxx/include/__algorithm/stable_partition.h (revision 59890c13343af9e308281b3c76bac425087f4f8a)
1134723edSLouis Dionne //===----------------------------------------------------------------------===//
2134723edSLouis Dionne //
3134723edSLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4134723edSLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
5134723edSLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6134723edSLouis Dionne //
7134723edSLouis Dionne //===----------------------------------------------------------------------===//
8134723edSLouis Dionne 
9134723edSLouis Dionne #ifndef _LIBCPP___ALGORITHM_STABLE_PARTITION_H
10134723edSLouis Dionne #define _LIBCPP___ALGORITHM_STABLE_PARTITION_H
11134723edSLouis Dionne 
128ed702b8SKonstantin Varlamov #include <__algorithm/iterator_operations.h>
13134723edSLouis Dionne #include <__algorithm/rotate.h>
144d81a46fSArthur O'Dwyer #include <__config>
15*e99c4906SNikolas Klauser #include <__cstddef/ptrdiff_t.h>
163cd4531bSNikolas Klauser #include <__iterator/advance.h>
173cd4531bSNikolas Klauser #include <__iterator/distance.h>
18134723edSLouis Dionne #include <__iterator/iterator_traits.h>
19d5e26775SNikolas Klauser #include <__memory/destruct_n.h>
20d5e26775SNikolas Klauser #include <__memory/unique_ptr.h>
2194e7c0b0SA. Jiang #include <__memory/unique_temporary_buffer.h>
2209e3a360SLouis Dionne #include <__type_traits/remove_cvref.h>
237712ae0aSMark de Wever #include <__utility/move.h>
24d5e26775SNikolas Klauser #include <__utility/pair.h>
25134723edSLouis Dionne 
26134723edSLouis Dionne #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
27134723edSLouis Dionne #  pragma GCC system_header
28134723edSLouis Dionne #endif
29134723edSLouis Dionne 
307b462251SLouis Dionne _LIBCPP_PUSH_MACROS
317b462251SLouis Dionne #include <__undef_macros>
327b462251SLouis Dionne 
33134723edSLouis Dionne _LIBCPP_BEGIN_NAMESPACE_STD
34134723edSLouis Dionne 
358ed702b8SKonstantin Varlamov template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _Distance, class _Pair>
369783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition_impl(
379783f28cSLouis Dionne     _ForwardIterator __first,
389783f28cSLouis Dionne     _ForwardIterator __last,
399783f28cSLouis Dionne     _Predicate __pred,
409783f28cSLouis Dionne     _Distance __len,
419783f28cSLouis Dionne     _Pair __p,
429783f28cSLouis Dionne     forward_iterator_tag __fit) {
438ed702b8SKonstantin Varlamov   using _Ops = _IterOps<_AlgPolicy>;
448ed702b8SKonstantin Varlamov 
45134723edSLouis Dionne   // *__first is known to be false
46134723edSLouis Dionne   // __len >= 1
47134723edSLouis Dionne   if (__len == 1)
48134723edSLouis Dionne     return __first;
499783f28cSLouis Dionne   if (__len == 2) {
50134723edSLouis Dionne     _ForwardIterator __m = __first;
519783f28cSLouis Dionne     if (__pred(*++__m)) {
528ed702b8SKonstantin Varlamov       _Ops::iter_swap(__first, __m);
53134723edSLouis Dionne       return __m;
54134723edSLouis Dionne     }
55134723edSLouis Dionne     return __first;
56134723edSLouis Dionne   }
579783f28cSLouis Dionne   if (__len <= __p.second) { // The buffer is big enough to use
58134723edSLouis Dionne     typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
59134723edSLouis Dionne     __destruct_n __d(0);
60134723edSLouis Dionne     unique_ptr<value_type, __destruct_n&> __h(__p.first, __d);
61134723edSLouis Dionne     // Move the falses into the temporary buffer, and the trues to the front of the line
62134723edSLouis Dionne     // Update __first to always point to the end of the trues
63134723edSLouis Dionne     value_type* __t = __p.first;
648ed702b8SKonstantin Varlamov     ::new ((void*)__t) value_type(_Ops::__iter_move(__first));
65134723edSLouis Dionne     __d.template __incr<value_type>();
66134723edSLouis Dionne     ++__t;
67134723edSLouis Dionne     _ForwardIterator __i = __first;
689783f28cSLouis Dionne     while (++__i != __last) {
699783f28cSLouis Dionne       if (__pred(*__i)) {
708ed702b8SKonstantin Varlamov         *__first = _Ops::__iter_move(__i);
71134723edSLouis Dionne         ++__first;
729783f28cSLouis Dionne       } else {
738ed702b8SKonstantin Varlamov         ::new ((void*)__t) value_type(_Ops::__iter_move(__i));
74134723edSLouis Dionne         __d.template __incr<value_type>();
75134723edSLouis Dionne         ++__t;
76134723edSLouis Dionne       }
77134723edSLouis Dionne     }
78134723edSLouis Dionne     // All trues now at start of range, all falses in buffer
79134723edSLouis Dionne     // Move falses back into range, but don't mess up __first which points to first false
80134723edSLouis Dionne     __i = __first;
81134723edSLouis Dionne     for (value_type* __t2 = __p.first; __t2 < __t; ++__t2, (void)++__i)
828ed702b8SKonstantin Varlamov       *__i = _Ops::__iter_move(__t2);
83134723edSLouis Dionne     // __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer
84134723edSLouis Dionne     return __first;
85134723edSLouis Dionne   }
86134723edSLouis Dionne   // Else not enough buffer, do in place
87134723edSLouis Dionne   // __len >= 3
88134723edSLouis Dionne   _ForwardIterator __m = __first;
89134723edSLouis Dionne   _Distance __len2     = __len / 2; // __len2 >= 2
908ed702b8SKonstantin Varlamov   _Ops::advance(__m, __len2);
91134723edSLouis Dionne   // recurse on [__first, __m), *__first know to be false
92134723edSLouis Dionne   // F?????????????????
93134723edSLouis Dionne   // f       m         l
949783f28cSLouis Dionne   _ForwardIterator __first_false =
959783f28cSLouis Dionne       std::__stable_partition_impl<_AlgPolicy, _Predicate&>(__first, __m, __pred, __len2, __p, __fit);
96134723edSLouis Dionne   // TTTFFFFF??????????
97134723edSLouis Dionne   // f  ff   m         l
98134723edSLouis Dionne   // recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true
99134723edSLouis Dionne   _ForwardIterator __m1           = __m;
100134723edSLouis Dionne   _ForwardIterator __second_false = __last;
101134723edSLouis Dionne   _Distance __len_half            = __len - __len2;
1029783f28cSLouis Dionne   while (__pred(*__m1)) {
103134723edSLouis Dionne     if (++__m1 == __last)
104134723edSLouis Dionne       goto __second_half_done;
105134723edSLouis Dionne     --__len_half;
106134723edSLouis Dionne   }
107134723edSLouis Dionne   // TTTFFFFFTTTF??????
108134723edSLouis Dionne   // f  ff   m  m1     l
1099783f28cSLouis Dionne   __second_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(__m1, __last, __pred, __len_half, __p, __fit);
110134723edSLouis Dionne __second_half_done:
111134723edSLouis Dionne   // TTTFFFFFTTTTTFFFFF
112134723edSLouis Dionne   // f  ff   m    sf   l
11336c746caSKonstantin Varlamov   return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false).first;
114134723edSLouis Dionne   // TTTTTTTTFFFFFFFFFF
115134723edSLouis Dionne   //         |
116134723edSLouis Dionne }
117134723edSLouis Dionne 
1188ed702b8SKonstantin Varlamov template <class _AlgPolicy, class _Predicate, class _ForwardIterator>
11980c7e93aSNikolas Klauser _LIBCPP_HIDE_FROM_ABI _ForwardIterator
1209783f28cSLouis Dionne __stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred, forward_iterator_tag) {
121b935ab8eSNikolas Klauser   typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type;
122b935ab8eSNikolas Klauser   typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
123b935ab8eSNikolas Klauser 
124b935ab8eSNikolas Klauser   const difference_type __alloc_limit = 3; // might want to make this a function of trivial assignment
125134723edSLouis Dionne   // Either prove all true and return __first or point to first false
1269783f28cSLouis Dionne   while (true) {
127134723edSLouis Dionne     if (__first == __last)
128134723edSLouis Dionne       return __first;
129134723edSLouis Dionne     if (!__pred(*__first))
130134723edSLouis Dionne       break;
131134723edSLouis Dionne     ++__first;
132134723edSLouis Dionne   }
133134723edSLouis Dionne   // We now have a reduced range [__first, __last)
134134723edSLouis Dionne   // *__first is known to be false
1358ed702b8SKonstantin Varlamov   difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last);
13694e7c0b0SA. Jiang   __unique_temporary_buffer<value_type> __unique_buf;
137f13e1a65SLouis Dionne   pair<value_type*, ptrdiff_t> __p(0, 0);
1389783f28cSLouis Dionne   if (__len >= __alloc_limit) {
13994e7c0b0SA. Jiang     __unique_buf = std::__allocate_unique_temporary_buffer<value_type>(__len);
14094e7c0b0SA. Jiang     __p.first    = __unique_buf.get();
14194e7c0b0SA. Jiang     __p.second   = __unique_buf.get_deleter().__count_;
142f13e1a65SLouis Dionne   }
1438ed702b8SKonstantin Varlamov   return std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
144f13e1a65SLouis Dionne       std::move(__first), std::move(__last), __pred, __len, __p, forward_iterator_tag());
145134723edSLouis Dionne }
146134723edSLouis Dionne 
1478ed702b8SKonstantin Varlamov template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator, class _Distance, class _Pair>
1489783f28cSLouis Dionne _BidirectionalIterator __stable_partition_impl(
1499783f28cSLouis Dionne     _BidirectionalIterator __first,
1509783f28cSLouis Dionne     _BidirectionalIterator __last,
1519783f28cSLouis Dionne     _Predicate __pred,
1529783f28cSLouis Dionne     _Distance __len,
1539783f28cSLouis Dionne     _Pair __p,
1549783f28cSLouis Dionne     bidirectional_iterator_tag __bit) {
1558ed702b8SKonstantin Varlamov   using _Ops = _IterOps<_AlgPolicy>;
1568ed702b8SKonstantin Varlamov 
157134723edSLouis Dionne   // *__first is known to be false
158134723edSLouis Dionne   // *__last is known to be true
159134723edSLouis Dionne   // __len >= 2
1609783f28cSLouis Dionne   if (__len == 2) {
1618ed702b8SKonstantin Varlamov     _Ops::iter_swap(__first, __last);
162134723edSLouis Dionne     return __last;
163134723edSLouis Dionne   }
1649783f28cSLouis Dionne   if (__len == 3) {
165134723edSLouis Dionne     _BidirectionalIterator __m = __first;
1669783f28cSLouis Dionne     if (__pred(*++__m)) {
1678ed702b8SKonstantin Varlamov       _Ops::iter_swap(__first, __m);
1688ed702b8SKonstantin Varlamov       _Ops::iter_swap(__m, __last);
169134723edSLouis Dionne       return __last;
170134723edSLouis Dionne     }
1718ed702b8SKonstantin Varlamov     _Ops::iter_swap(__m, __last);
1728ed702b8SKonstantin Varlamov     _Ops::iter_swap(__first, __m);
173134723edSLouis Dionne     return __m;
174134723edSLouis Dionne   }
1759783f28cSLouis Dionne   if (__len <= __p.second) { // The buffer is big enough to use
176134723edSLouis Dionne     typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
177134723edSLouis Dionne     __destruct_n __d(0);
178134723edSLouis Dionne     unique_ptr<value_type, __destruct_n&> __h(__p.first, __d);
179134723edSLouis Dionne     // Move the falses into the temporary buffer, and the trues to the front of the line
180134723edSLouis Dionne     // Update __first to always point to the end of the trues
181134723edSLouis Dionne     value_type* __t = __p.first;
1828ed702b8SKonstantin Varlamov     ::new ((void*)__t) value_type(_Ops::__iter_move(__first));
183134723edSLouis Dionne     __d.template __incr<value_type>();
184134723edSLouis Dionne     ++__t;
185134723edSLouis Dionne     _BidirectionalIterator __i = __first;
1869783f28cSLouis Dionne     while (++__i != __last) {
1879783f28cSLouis Dionne       if (__pred(*__i)) {
1888ed702b8SKonstantin Varlamov         *__first = _Ops::__iter_move(__i);
189134723edSLouis Dionne         ++__first;
1909783f28cSLouis Dionne       } else {
1918ed702b8SKonstantin Varlamov         ::new ((void*)__t) value_type(_Ops::__iter_move(__i));
192134723edSLouis Dionne         __d.template __incr<value_type>();
193134723edSLouis Dionne         ++__t;
194134723edSLouis Dionne       }
195134723edSLouis Dionne     }
196134723edSLouis Dionne     // move *__last, known to be true
1978ed702b8SKonstantin Varlamov     *__first = _Ops::__iter_move(__i);
198134723edSLouis Dionne     __i      = ++__first;
199134723edSLouis Dionne     // All trues now at start of range, all falses in buffer
200134723edSLouis Dionne     // Move falses back into range, but don't mess up __first which points to first false
201134723edSLouis Dionne     for (value_type* __t2 = __p.first; __t2 < __t; ++__t2, (void)++__i)
2028ed702b8SKonstantin Varlamov       *__i = _Ops::__iter_move(__t2);
203134723edSLouis Dionne     // __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer
204134723edSLouis Dionne     return __first;
205134723edSLouis Dionne   }
206134723edSLouis Dionne   // Else not enough buffer, do in place
207134723edSLouis Dionne   // __len >= 4
208134723edSLouis Dionne   _BidirectionalIterator __m = __first;
209134723edSLouis Dionne   _Distance __len2           = __len / 2; // __len2 >= 2
2108ed702b8SKonstantin Varlamov   _Ops::advance(__m, __len2);
211134723edSLouis Dionne   // recurse on [__first, __m-1], except reduce __m-1 until *(__m-1) is true, *__first know to be false
212134723edSLouis Dionne   // F????????????????T
213134723edSLouis Dionne   // f       m        l
214134723edSLouis Dionne   _BidirectionalIterator __m1          = __m;
215134723edSLouis Dionne   _BidirectionalIterator __first_false = __first;
216134723edSLouis Dionne   _Distance __len_half                 = __len2;
2179783f28cSLouis Dionne   while (!__pred(*--__m1)) {
218134723edSLouis Dionne     if (__m1 == __first)
219134723edSLouis Dionne       goto __first_half_done;
220134723edSLouis Dionne     --__len_half;
221134723edSLouis Dionne   }
222134723edSLouis Dionne   // F???TFFF?????????T
223134723edSLouis Dionne   // f   m1  m        l
2249783f28cSLouis Dionne   __first_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(__first, __m1, __pred, __len_half, __p, __bit);
225134723edSLouis Dionne __first_half_done:
226134723edSLouis Dionne   // TTTFFFFF?????????T
227134723edSLouis Dionne   // f  ff   m        l
228134723edSLouis Dionne   // recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true
229134723edSLouis Dionne   __m1                                  = __m;
230134723edSLouis Dionne   _BidirectionalIterator __second_false = __last;
231134723edSLouis Dionne   ++__second_false;
232134723edSLouis Dionne   __len_half = __len - __len2;
2339783f28cSLouis Dionne   while (__pred(*__m1)) {
234134723edSLouis Dionne     if (++__m1 == __last)
235134723edSLouis Dionne       goto __second_half_done;
236134723edSLouis Dionne     --__len_half;
237134723edSLouis Dionne   }
238134723edSLouis Dionne   // TTTFFFFFTTTF?????T
239134723edSLouis Dionne   // f  ff   m  m1    l
2409783f28cSLouis Dionne   __second_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(__m1, __last, __pred, __len_half, __p, __bit);
241134723edSLouis Dionne __second_half_done:
242134723edSLouis Dionne   // TTTFFFFFTTTTTFFFFF
243134723edSLouis Dionne   // f  ff   m    sf  l
24436c746caSKonstantin Varlamov   return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false).first;
245134723edSLouis Dionne   // TTTTTTTTFFFFFFFFFF
246134723edSLouis Dionne   //         |
247134723edSLouis Dionne }
248134723edSLouis Dionne 
2498ed702b8SKonstantin Varlamov template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator>
2509783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _BidirectionalIterator __stable_partition_impl(
2519783f28cSLouis Dionne     _BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred, bidirectional_iterator_tag) {
252134723edSLouis Dionne   typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
253134723edSLouis Dionne   typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
254134723edSLouis Dionne   const difference_type __alloc_limit = 4; // might want to make this a function of trivial assignment
255134723edSLouis Dionne   // Either prove all true and return __first or point to first false
2569783f28cSLouis Dionne   while (true) {
257134723edSLouis Dionne     if (__first == __last)
258134723edSLouis Dionne       return __first;
259134723edSLouis Dionne     if (!__pred(*__first))
260134723edSLouis Dionne       break;
261134723edSLouis Dionne     ++__first;
262134723edSLouis Dionne   }
263134723edSLouis Dionne   // __first points to first false, everything prior to __first is already set.
264134723edSLouis Dionne   // Either prove [__first, __last) is all false and return __first, or point __last to last true
2659783f28cSLouis Dionne   do {
266134723edSLouis Dionne     if (__first == --__last)
267134723edSLouis Dionne       return __first;
268134723edSLouis Dionne   } while (!__pred(*__last));
269134723edSLouis Dionne   // We now have a reduced range [__first, __last]
270134723edSLouis Dionne   // *__first is known to be false
271134723edSLouis Dionne   // *__last is known to be true
272134723edSLouis Dionne   // __len >= 2
2738ed702b8SKonstantin Varlamov   difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last) + 1;
27494e7c0b0SA. Jiang   __unique_temporary_buffer<value_type> __unique_buf;
275f13e1a65SLouis Dionne   pair<value_type*, ptrdiff_t> __p(0, 0);
2769783f28cSLouis Dionne   if (__len >= __alloc_limit) {
27794e7c0b0SA. Jiang     __unique_buf = std::__allocate_unique_temporary_buffer<value_type>(__len);
27894e7c0b0SA. Jiang     __p.first    = __unique_buf.get();
27994e7c0b0SA. Jiang     __p.second   = __unique_buf.get_deleter().__count_;
280f13e1a65SLouis Dionne   }
2818ed702b8SKonstantin Varlamov   return std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
282f13e1a65SLouis Dionne       std::move(__first), std::move(__last), __pred, __len, __p, bidirectional_iterator_tag());
2838ed702b8SKonstantin Varlamov }
2848ed702b8SKonstantin Varlamov 
2858ed702b8SKonstantin Varlamov template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _IterCategory>
2869783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition(
2878ed702b8SKonstantin Varlamov     _ForwardIterator __first, _ForwardIterator __last, _Predicate&& __pred, _IterCategory __iter_category) {
2885fab33afSNikolas Klauser   return std::__stable_partition_impl<_AlgPolicy, __remove_cvref_t<_Predicate>&>(
2898ed702b8SKonstantin Varlamov       std::move(__first), std::move(__last), __pred, __iter_category);
290134723edSLouis Dionne }
291134723edSLouis Dionne 
292134723edSLouis Dionne template <class _ForwardIterator, class _Predicate>
2939783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
2949783f28cSLouis Dionne stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
2958ed702b8SKonstantin Varlamov   using _IterCategory = typename iterator_traits<_ForwardIterator>::iterator_category;
2968ed702b8SKonstantin Varlamov   return std::__stable_partition<_ClassicAlgPolicy, _Predicate&>(
2978ed702b8SKonstantin Varlamov       std::move(__first), std::move(__last), __pred, _IterCategory());
298134723edSLouis Dionne }
299134723edSLouis Dionne 
300134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD
301134723edSLouis Dionne 
3027b462251SLouis Dionne _LIBCPP_POP_MACROS
3037b462251SLouis Dionne 
304134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_STABLE_PARTITION_H
305