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 <__iterator/advance.h>
16 #include <__iterator/distance.h>
17 #include <__iterator/iterator_traits.h>
18 #include <__memory/destruct_n.h>
19 #include <__memory/temporary_buffer.h>
20 #include <__memory/unique_ptr.h>
21 #include <__utility/move.h>
22 #include <__utility/pair.h>
25 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26 # pragma GCC system_header
30 #include <__undef_macros>
32 _LIBCPP_BEGIN_NAMESPACE_STD
34 template <class _AlgPolicy
, class _Predicate
, class _ForwardIterator
, class _Distance
, class _Pair
>
35 _LIBCPP_HIDE_FROM_ABI _ForwardIterator
__stable_partition_impl(
36 _ForwardIterator __first
,
37 _ForwardIterator __last
,
41 forward_iterator_tag __fit
) {
42 using _Ops
= _IterOps
<_AlgPolicy
>;
44 // *__first is known to be false
49 _ForwardIterator __m
= __first
;
51 _Ops::iter_swap(__first
, __m
);
56 if (__len
<= __p
.second
) { // The buffer is big enough to use
57 typedef typename iterator_traits
<_ForwardIterator
>::value_type value_type
;
59 unique_ptr
<value_type
, __destruct_n
&> __h(__p
.first
, __d
);
60 // Move the falses into the temporary buffer, and the trues to the front of the line
61 // Update __first to always point to the end of the trues
62 value_type
* __t
= __p
.first
;
63 ::new ((void*)__t
) value_type(_Ops::__iter_move(__first
));
64 __d
.template __incr
<value_type
>();
66 _ForwardIterator __i
= __first
;
67 while (++__i
!= __last
) {
69 *__first
= _Ops::__iter_move(__i
);
72 ::new ((void*)__t
) value_type(_Ops::__iter_move(__i
));
73 __d
.template __incr
<value_type
>();
77 // All trues now at start of range, all falses in buffer
78 // Move falses back into range, but don't mess up __first which points to first false
80 for (value_type
* __t2
= __p
.first
; __t2
< __t
; ++__t2
, (void)++__i
)
81 *__i
= _Ops::__iter_move(__t2
);
82 // __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer
85 // Else not enough buffer, do in place
87 _ForwardIterator __m
= __first
;
88 _Distance __len2
= __len
/ 2; // __len2 >= 2
89 _Ops::advance(__m
, __len2
);
90 // recurse on [__first, __m), *__first know to be false
93 _ForwardIterator __first_false
=
94 std::__stable_partition_impl
<_AlgPolicy
, _Predicate
&>(__first
, __m
, __pred
, __len2
, __p
, __fit
);
97 // recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true
98 _ForwardIterator __m1
= __m
;
99 _ForwardIterator __second_false
= __last
;
100 _Distance __len_half
= __len
- __len2
;
101 while (__pred(*__m1
)) {
102 if (++__m1
== __last
)
103 goto __second_half_done
;
106 // TTTFFFFFTTTF??????
108 __second_false
= std::__stable_partition_impl
<_AlgPolicy
, _Predicate
&>(__m1
, __last
, __pred
, __len_half
, __p
, __fit
);
110 // TTTFFFFFTTTTTFFFFF
112 return std::__rotate
<_AlgPolicy
>(__first_false
, __m
, __second_false
).first
;
113 // TTTTTTTTFFFFFFFFFF
117 template <class _AlgPolicy
, class _Predicate
, class _ForwardIterator
>
118 _LIBCPP_HIDE_FROM_ABI _ForwardIterator
119 __stable_partition_impl(_ForwardIterator __first
, _ForwardIterator __last
, _Predicate __pred
, forward_iterator_tag
) {
120 typedef typename iterator_traits
<_ForwardIterator
>::difference_type difference_type
;
121 typedef typename iterator_traits
<_ForwardIterator
>::value_type value_type
;
123 const difference_type __alloc_limit
= 3; // might want to make this a function of trivial assignment
124 // Either prove all true and return __first or point to first false
126 if (__first
== __last
)
128 if (!__pred(*__first
))
132 // We now have a reduced range [__first, __last)
133 // *__first is known to be false
134 difference_type __len
= _IterOps
<_AlgPolicy
>::distance(__first
, __last
);
135 pair
<value_type
*, ptrdiff_t> __p(0, 0);
136 unique_ptr
<value_type
, __return_temporary_buffer
> __h
;
137 if (__len
>= __alloc_limit
) {
138 // TODO: Remove the use of std::get_temporary_buffer
139 _LIBCPP_SUPPRESS_DEPRECATED_PUSH
140 __p
= std::get_temporary_buffer
<value_type
>(__len
);
141 _LIBCPP_SUPPRESS_DEPRECATED_POP
142 __h
.reset(__p
.first
);
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 pair
<value_type
*, ptrdiff_t> __p(0, 0);
276 unique_ptr
<value_type
, __return_temporary_buffer
> __h
;
277 if (__len
>= __alloc_limit
) {
278 // TODO: Remove the use of std::get_temporary_buffer
279 _LIBCPP_SUPPRESS_DEPRECATED_PUSH
280 __p
= std::get_temporary_buffer
<value_type
>(__len
);
281 _LIBCPP_SUPPRESS_DEPRECATED_POP
282 __h
.reset(__p
.first
);
284 return std::__stable_partition_impl
<_AlgPolicy
, _Predicate
&>(
285 std::move(__first
), std::move(__last
), __pred
, __len
, __p
, bidirectional_iterator_tag());
288 template <class _AlgPolicy
, class _Predicate
, class _ForwardIterator
, class _IterCategory
>
289 _LIBCPP_HIDE_FROM_ABI _ForwardIterator
__stable_partition(
290 _ForwardIterator __first
, _ForwardIterator __last
, _Predicate
&& __pred
, _IterCategory __iter_category
) {
291 return std::__stable_partition_impl
<_AlgPolicy
, __remove_cvref_t
<_Predicate
>&>(
292 std::move(__first
), std::move(__last
), __pred
, __iter_category
);
295 template <class _ForwardIterator
, class _Predicate
>
296 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
297 stable_partition(_ForwardIterator __first
, _ForwardIterator __last
, _Predicate __pred
) {
298 using _IterCategory
= typename iterator_traits
<_ForwardIterator
>::iterator_category
;
299 return std::__stable_partition
<_ClassicAlgPolicy
, _Predicate
&>(
300 std::move(__first
), std::move(__last
), __pred
, _IterCategory());
303 _LIBCPP_END_NAMESPACE_STD
307 #endif // _LIBCPP___ALGORITHM_STABLE_PARTITION_H