1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef _LIBCPP___ALGORITHM_STABLE_PARTITION_H
10 #define _LIBCPP___ALGORITHM_STABLE_PARTITION_H
12 #include <__algorithm/iterator_operations.h>
13 #include <__algorithm/rotate.h>
15 #include <__cstddef/ptrdiff_t.h>
16 #include <__iterator/advance.h>
17 #include <__iterator/distance.h>
18 #include <__iterator/iterator_traits.h>
19 #include <__memory/destruct_n.h>
20 #include <__memory/unique_ptr.h>
21 #include <__memory/unique_temporary_buffer.h>
22 #include <__type_traits/remove_cvref.h>
23 #include <__utility/move.h>
24 #include <__utility/pair.h>
27 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
28 # pragma GCC system_header
32 #include <__undef_macros>
34 _LIBCPP_BEGIN_NAMESPACE_STD
36 template <class _AlgPolicy
, class _Predicate
, class _ForwardIterator
, class _Distance
, class _Pair
>
37 _LIBCPP_HIDE_FROM_ABI _ForwardIterator
__stable_partition_impl(
38 _ForwardIterator __first
,
39 _ForwardIterator __last
,
43 forward_iterator_tag __fit
) {
44 using _Ops
= _IterOps
<_AlgPolicy
>;
46 // *__first is known to be false
51 _ForwardIterator __m
= __first
;
53 _Ops::iter_swap(__first
, __m
);
58 if (__len
<= __p
.second
) { // The buffer is big enough to use
59 typedef typename iterator_traits
<_ForwardIterator
>::value_type value_type
;
61 unique_ptr
<value_type
, __destruct_n
&> __h(__p
.first
, __d
);
62 // Move the falses into the temporary buffer, and the trues to the front of the line
63 // Update __first to always point to the end of the trues
64 value_type
* __t
= __p
.first
;
65 ::new ((void*)__t
) value_type(_Ops::__iter_move(__first
));
66 __d
.template __incr
<value_type
>();
68 _ForwardIterator __i
= __first
;
69 while (++__i
!= __last
) {
71 *__first
= _Ops::__iter_move(__i
);
74 ::new ((void*)__t
) value_type(_Ops::__iter_move(__i
));
75 __d
.template __incr
<value_type
>();
79 // All trues now at start of range, all falses in buffer
80 // Move falses back into range, but don't mess up __first which points to first false
82 for (value_type
* __t2
= __p
.first
; __t2
< __t
; ++__t2
, (void)++__i
)
83 *__i
= _Ops::__iter_move(__t2
);
84 // __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer
87 // Else not enough buffer, do in place
89 _ForwardIterator __m
= __first
;
90 _Distance __len2
= __len
/ 2; // __len2 >= 2
91 _Ops::advance(__m
, __len2
);
92 // recurse on [__first, __m), *__first know to be false
95 _ForwardIterator __first_false
=
96 std::__stable_partition_impl
<_AlgPolicy
, _Predicate
&>(__first
, __m
, __pred
, __len2
, __p
, __fit
);
99 // recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true
100 _ForwardIterator __m1
= __m
;
101 _ForwardIterator __second_false
= __last
;
102 _Distance __len_half
= __len
- __len2
;
103 while (__pred(*__m1
)) {
104 if (++__m1
== __last
)
105 goto __second_half_done
;
108 // TTTFFFFFTTTF??????
110 __second_false
= std::__stable_partition_impl
<_AlgPolicy
, _Predicate
&>(__m1
, __last
, __pred
, __len_half
, __p
, __fit
);
112 // TTTFFFFFTTTTTFFFFF
114 return std::__rotate
<_AlgPolicy
>(__first_false
, __m
, __second_false
).first
;
115 // TTTTTTTTFFFFFFFFFF
119 template <class _AlgPolicy
, class _Predicate
, class _ForwardIterator
>
120 _LIBCPP_HIDE_FROM_ABI _ForwardIterator
121 __stable_partition_impl(_ForwardIterator __first
, _ForwardIterator __last
, _Predicate __pred
, forward_iterator_tag
) {
122 typedef typename iterator_traits
<_ForwardIterator
>::difference_type difference_type
;
123 typedef typename iterator_traits
<_ForwardIterator
>::value_type value_type
;
125 const difference_type __alloc_limit
= 3; // might want to make this a function of trivial assignment
126 // Either prove all true and return __first or point to first false
128 if (__first
== __last
)
130 if (!__pred(*__first
))
134 // We now have a reduced range [__first, __last)
135 // *__first is known to be false
136 difference_type __len
= _IterOps
<_AlgPolicy
>::distance(__first
, __last
);
137 __unique_temporary_buffer
<value_type
> __unique_buf
;
138 pair
<value_type
*, ptrdiff_t> __p(0, 0);
139 if (__len
>= __alloc_limit
) {
140 __unique_buf
= std::__allocate_unique_temporary_buffer
<value_type
>(__len
);
141 __p
.first
= __unique_buf
.get();
142 __p
.second
= __unique_buf
.get_deleter().__count_
;
144 return std::__stable_partition_impl
<_AlgPolicy
, _Predicate
&>(
145 std::move(__first
), std::move(__last
), __pred
, __len
, __p
, forward_iterator_tag());
148 template <class _AlgPolicy
, class _Predicate
, class _BidirectionalIterator
, class _Distance
, class _Pair
>
149 _BidirectionalIterator
__stable_partition_impl(
150 _BidirectionalIterator __first
,
151 _BidirectionalIterator __last
,
155 bidirectional_iterator_tag __bit
) {
156 using _Ops
= _IterOps
<_AlgPolicy
>;
158 // *__first is known to be false
159 // *__last is known to be true
162 _Ops::iter_swap(__first
, __last
);
166 _BidirectionalIterator __m
= __first
;
167 if (__pred(*++__m
)) {
168 _Ops::iter_swap(__first
, __m
);
169 _Ops::iter_swap(__m
, __last
);
172 _Ops::iter_swap(__m
, __last
);
173 _Ops::iter_swap(__first
, __m
);
176 if (__len
<= __p
.second
) { // The buffer is big enough to use
177 typedef typename iterator_traits
<_BidirectionalIterator
>::value_type value_type
;
179 unique_ptr
<value_type
, __destruct_n
&> __h(__p
.first
, __d
);
180 // Move the falses into the temporary buffer, and the trues to the front of the line
181 // Update __first to always point to the end of the trues
182 value_type
* __t
= __p
.first
;
183 ::new ((void*)__t
) value_type(_Ops::__iter_move(__first
));
184 __d
.template __incr
<value_type
>();
186 _BidirectionalIterator __i
= __first
;
187 while (++__i
!= __last
) {
189 *__first
= _Ops::__iter_move(__i
);
192 ::new ((void*)__t
) value_type(_Ops::__iter_move(__i
));
193 __d
.template __incr
<value_type
>();
197 // move *__last, known to be true
198 *__first
= _Ops::__iter_move(__i
);
200 // All trues now at start of range, all falses in buffer
201 // Move falses back into range, but don't mess up __first which points to first false
202 for (value_type
* __t2
= __p
.first
; __t2
< __t
; ++__t2
, (void)++__i
)
203 *__i
= _Ops::__iter_move(__t2
);
204 // __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer
207 // Else not enough buffer, do in place
209 _BidirectionalIterator __m
= __first
;
210 _Distance __len2
= __len
/ 2; // __len2 >= 2
211 _Ops::advance(__m
, __len2
);
212 // recurse on [__first, __m-1], except reduce __m-1 until *(__m-1) is true, *__first know to be false
213 // F????????????????T
215 _BidirectionalIterator __m1
= __m
;
216 _BidirectionalIterator __first_false
= __first
;
217 _Distance __len_half
= __len2
;
218 while (!__pred(*--__m1
)) {
220 goto __first_half_done
;
223 // F???TFFF?????????T
225 __first_false
= std::__stable_partition_impl
<_AlgPolicy
, _Predicate
&>(__first
, __m1
, __pred
, __len_half
, __p
, __bit
);
227 // TTTFFFFF?????????T
229 // recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true
231 _BidirectionalIterator __second_false
= __last
;
233 __len_half
= __len
- __len2
;
234 while (__pred(*__m1
)) {
235 if (++__m1
== __last
)
236 goto __second_half_done
;
239 // TTTFFFFFTTTF?????T
241 __second_false
= std::__stable_partition_impl
<_AlgPolicy
, _Predicate
&>(__m1
, __last
, __pred
, __len_half
, __p
, __bit
);
243 // TTTFFFFFTTTTTFFFFF
245 return std::__rotate
<_AlgPolicy
>(__first_false
, __m
, __second_false
).first
;
246 // TTTTTTTTFFFFFFFFFF
250 template <class _AlgPolicy
, class _Predicate
, class _BidirectionalIterator
>
251 _LIBCPP_HIDE_FROM_ABI _BidirectionalIterator
__stable_partition_impl(
252 _BidirectionalIterator __first
, _BidirectionalIterator __last
, _Predicate __pred
, bidirectional_iterator_tag
) {
253 typedef typename iterator_traits
<_BidirectionalIterator
>::difference_type difference_type
;
254 typedef typename iterator_traits
<_BidirectionalIterator
>::value_type value_type
;
255 const difference_type __alloc_limit
= 4; // might want to make this a function of trivial assignment
256 // Either prove all true and return __first or point to first false
258 if (__first
== __last
)
260 if (!__pred(*__first
))
264 // __first points to first false, everything prior to __first is already set.
265 // Either prove [__first, __last) is all false and return __first, or point __last to last true
267 if (__first
== --__last
)
269 } while (!__pred(*__last
));
270 // We now have a reduced range [__first, __last]
271 // *__first is known to be false
272 // *__last is known to be true
274 difference_type __len
= _IterOps
<_AlgPolicy
>::distance(__first
, __last
) + 1;
275 __unique_temporary_buffer
<value_type
> __unique_buf
;
276 pair
<value_type
*, ptrdiff_t> __p(0, 0);
277 if (__len
>= __alloc_limit
) {
278 __unique_buf
= std::__allocate_unique_temporary_buffer
<value_type
>(__len
);
279 __p
.first
= __unique_buf
.get();
280 __p
.second
= __unique_buf
.get_deleter().__count_
;
282 return std::__stable_partition_impl
<_AlgPolicy
, _Predicate
&>(
283 std::move(__first
), std::move(__last
), __pred
, __len
, __p
, bidirectional_iterator_tag());
286 template <class _AlgPolicy
, class _Predicate
, class _ForwardIterator
, class _IterCategory
>
287 _LIBCPP_HIDE_FROM_ABI _ForwardIterator
__stable_partition(
288 _ForwardIterator __first
, _ForwardIterator __last
, _Predicate
&& __pred
, _IterCategory __iter_category
) {
289 return std::__stable_partition_impl
<_AlgPolicy
, __remove_cvref_t
<_Predicate
>&>(
290 std::move(__first
), std::move(__last
), __pred
, __iter_category
);
293 template <class _ForwardIterator
, class _Predicate
>
294 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
295 stable_partition(_ForwardIterator __first
, _ForwardIterator __last
, _Predicate __pred
) {
296 using _IterCategory
= typename iterator_traits
<_ForwardIterator
>::iterator_category
;
297 return std::__stable_partition
<_ClassicAlgPolicy
, _Predicate
&>(
298 std::move(__first
), std::move(__last
), __pred
, _IterCategory());
301 _LIBCPP_END_NAMESPACE_STD
305 #endif // _LIBCPP___ALGORITHM_STABLE_PARTITION_H