xref: /openbsd-src/gnu/llvm/libcxx/include/__algorithm/stable_partition.h (revision 4bdff4bed0e3d54e55670334c7d0077db4170f86)
176d0caaeSpatrick //===----------------------------------------------------------------------===//
276d0caaeSpatrick //
376d0caaeSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
476d0caaeSpatrick // See https://llvm.org/LICENSE.txt for license information.
576d0caaeSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
676d0caaeSpatrick //
776d0caaeSpatrick //===----------------------------------------------------------------------===//
876d0caaeSpatrick 
976d0caaeSpatrick #ifndef _LIBCPP___ALGORITHM_STABLE_PARTITION_H
1076d0caaeSpatrick #define _LIBCPP___ALGORITHM_STABLE_PARTITION_H
1176d0caaeSpatrick 
12*4bdff4beSrobert #include <__algorithm/iterator_operations.h>
1376d0caaeSpatrick #include <__algorithm/rotate.h>
14*4bdff4beSrobert #include <__config>
15*4bdff4beSrobert #include <__iterator/advance.h>
16*4bdff4beSrobert #include <__iterator/distance.h>
1776d0caaeSpatrick #include <__iterator/iterator_traits.h>
18*4bdff4beSrobert #include <__memory/destruct_n.h>
19*4bdff4beSrobert #include <__memory/temporary_buffer.h>
20*4bdff4beSrobert #include <__memory/unique_ptr.h>
21*4bdff4beSrobert #include <__utility/move.h>
22*4bdff4beSrobert #include <__utility/pair.h>
23*4bdff4beSrobert #include <new>
24*4bdff4beSrobert #include <type_traits>
2576d0caaeSpatrick 
2676d0caaeSpatrick #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2776d0caaeSpatrick #  pragma GCC system_header
2876d0caaeSpatrick #endif
2976d0caaeSpatrick 
3076d0caaeSpatrick _LIBCPP_BEGIN_NAMESPACE_STD
3176d0caaeSpatrick 
32*4bdff4beSrobert template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _Distance, class _Pair>
33*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI _ForwardIterator
__stable_partition_impl(_ForwardIterator __first,_ForwardIterator __last,_Predicate __pred,_Distance __len,_Pair __p,forward_iterator_tag __fit)34*4bdff4beSrobert __stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
3576d0caaeSpatrick                    _Distance __len, _Pair __p, forward_iterator_tag __fit)
3676d0caaeSpatrick {
37*4bdff4beSrobert     using _Ops = _IterOps<_AlgPolicy>;
38*4bdff4beSrobert 
3976d0caaeSpatrick     // *__first is known to be false
4076d0caaeSpatrick     // __len >= 1
4176d0caaeSpatrick     if (__len == 1)
4276d0caaeSpatrick         return __first;
4376d0caaeSpatrick     if (__len == 2)
4476d0caaeSpatrick     {
4576d0caaeSpatrick         _ForwardIterator __m = __first;
4676d0caaeSpatrick         if (__pred(*++__m))
4776d0caaeSpatrick         {
48*4bdff4beSrobert             _Ops::iter_swap(__first, __m);
4976d0caaeSpatrick             return __m;
5076d0caaeSpatrick         }
5176d0caaeSpatrick         return __first;
5276d0caaeSpatrick     }
5376d0caaeSpatrick     if (__len <= __p.second)
5476d0caaeSpatrick     {   // The buffer is big enough to use
5576d0caaeSpatrick         typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
5676d0caaeSpatrick         __destruct_n __d(0);
5776d0caaeSpatrick         unique_ptr<value_type, __destruct_n&> __h(__p.first, __d);
5876d0caaeSpatrick         // Move the falses into the temporary buffer, and the trues to the front of the line
5976d0caaeSpatrick         // Update __first to always point to the end of the trues
6076d0caaeSpatrick         value_type* __t = __p.first;
61*4bdff4beSrobert         ::new ((void*)__t) value_type(_Ops::__iter_move(__first));
6276d0caaeSpatrick         __d.template __incr<value_type>();
6376d0caaeSpatrick         ++__t;
6476d0caaeSpatrick         _ForwardIterator __i = __first;
6576d0caaeSpatrick         while (++__i != __last)
6676d0caaeSpatrick         {
6776d0caaeSpatrick             if (__pred(*__i))
6876d0caaeSpatrick             {
69*4bdff4beSrobert                 *__first = _Ops::__iter_move(__i);
7076d0caaeSpatrick                 ++__first;
7176d0caaeSpatrick             }
7276d0caaeSpatrick             else
7376d0caaeSpatrick             {
74*4bdff4beSrobert                 ::new ((void*)__t) value_type(_Ops::__iter_move(__i));
7576d0caaeSpatrick                 __d.template __incr<value_type>();
7676d0caaeSpatrick                 ++__t;
7776d0caaeSpatrick             }
7876d0caaeSpatrick         }
7976d0caaeSpatrick         // All trues now at start of range, all falses in buffer
8076d0caaeSpatrick         // Move falses back into range, but don't mess up __first which points to first false
8176d0caaeSpatrick         __i = __first;
8276d0caaeSpatrick         for (value_type* __t2 = __p.first; __t2 < __t; ++__t2, (void) ++__i)
83*4bdff4beSrobert             *__i = _Ops::__iter_move(__t2);
8476d0caaeSpatrick         // __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer
8576d0caaeSpatrick         return __first;
8676d0caaeSpatrick     }
8776d0caaeSpatrick     // Else not enough buffer, do in place
8876d0caaeSpatrick     // __len >= 3
8976d0caaeSpatrick     _ForwardIterator __m = __first;
9076d0caaeSpatrick     _Distance __len2 = __len / 2;  // __len2 >= 2
91*4bdff4beSrobert     _Ops::advance(__m, __len2);
9276d0caaeSpatrick     // recurse on [__first, __m), *__first know to be false
9376d0caaeSpatrick     // F?????????????????
9476d0caaeSpatrick     // f       m         l
95*4bdff4beSrobert     _ForwardIterator __first_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
96*4bdff4beSrobert         __first, __m, __pred, __len2, __p, __fit);
9776d0caaeSpatrick     // TTTFFFFF??????????
9876d0caaeSpatrick     // f  ff   m         l
9976d0caaeSpatrick     // recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true
10076d0caaeSpatrick     _ForwardIterator __m1 = __m;
10176d0caaeSpatrick     _ForwardIterator __second_false = __last;
10276d0caaeSpatrick     _Distance __len_half = __len - __len2;
10376d0caaeSpatrick     while (__pred(*__m1))
10476d0caaeSpatrick     {
10576d0caaeSpatrick         if (++__m1 == __last)
10676d0caaeSpatrick             goto __second_half_done;
10776d0caaeSpatrick         --__len_half;
10876d0caaeSpatrick     }
10976d0caaeSpatrick     // TTTFFFFFTTTF??????
11076d0caaeSpatrick     // f  ff   m  m1     l
111*4bdff4beSrobert     __second_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
112*4bdff4beSrobert         __m1, __last, __pred, __len_half, __p, __fit);
11376d0caaeSpatrick __second_half_done:
11476d0caaeSpatrick     // TTTFFFFFTTTTTFFFFF
11576d0caaeSpatrick     // f  ff   m    sf   l
116*4bdff4beSrobert     return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false).first;
11776d0caaeSpatrick     // TTTTTTTTFFFFFFFFFF
11876d0caaeSpatrick     //         |
11976d0caaeSpatrick }
12076d0caaeSpatrick 
121*4bdff4beSrobert template <class _AlgPolicy, class _Predicate, class _ForwardIterator>
122*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI _ForwardIterator
__stable_partition_impl(_ForwardIterator __first,_ForwardIterator __last,_Predicate __pred,forward_iterator_tag)123*4bdff4beSrobert __stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
12476d0caaeSpatrick                    forward_iterator_tag)
12576d0caaeSpatrick {
12676d0caaeSpatrick     const unsigned __alloc_limit = 3;  // might want to make this a function of trivial assignment
12776d0caaeSpatrick     // Either prove all true and return __first or point to first false
12876d0caaeSpatrick     while (true)
12976d0caaeSpatrick     {
13076d0caaeSpatrick         if (__first == __last)
13176d0caaeSpatrick             return __first;
13276d0caaeSpatrick         if (!__pred(*__first))
13376d0caaeSpatrick             break;
13476d0caaeSpatrick         ++__first;
13576d0caaeSpatrick     }
13676d0caaeSpatrick     // We now have a reduced range [__first, __last)
13776d0caaeSpatrick     // *__first is known to be false
13876d0caaeSpatrick     typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type;
13976d0caaeSpatrick     typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
140*4bdff4beSrobert     difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last);
14176d0caaeSpatrick     pair<value_type*, ptrdiff_t> __p(0, 0);
14276d0caaeSpatrick     unique_ptr<value_type, __return_temporary_buffer> __h;
14376d0caaeSpatrick     if (__len >= __alloc_limit)
14476d0caaeSpatrick     {
145*4bdff4beSrobert // TODO: Remove the use of std::get_temporary_buffer
146*4bdff4beSrobert _LIBCPP_SUPPRESS_DEPRECATED_PUSH
14776d0caaeSpatrick         __p = _VSTD::get_temporary_buffer<value_type>(__len);
148*4bdff4beSrobert _LIBCPP_SUPPRESS_DEPRECATED_POP
14976d0caaeSpatrick         __h.reset(__p.first);
15076d0caaeSpatrick     }
151*4bdff4beSrobert     return std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
152*4bdff4beSrobert         std::move(__first), std::move(__last), __pred, __len, __p, forward_iterator_tag());
15376d0caaeSpatrick }
15476d0caaeSpatrick 
155*4bdff4beSrobert template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator, class _Distance, class _Pair>
15676d0caaeSpatrick _BidirectionalIterator
__stable_partition_impl(_BidirectionalIterator __first,_BidirectionalIterator __last,_Predicate __pred,_Distance __len,_Pair __p,bidirectional_iterator_tag __bit)157*4bdff4beSrobert __stable_partition_impl(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred,
15876d0caaeSpatrick                    _Distance __len, _Pair __p, bidirectional_iterator_tag __bit)
15976d0caaeSpatrick {
160*4bdff4beSrobert     using _Ops = _IterOps<_AlgPolicy>;
161*4bdff4beSrobert 
16276d0caaeSpatrick     // *__first is known to be false
16376d0caaeSpatrick     // *__last is known to be true
16476d0caaeSpatrick     // __len >= 2
16576d0caaeSpatrick     if (__len == 2)
16676d0caaeSpatrick     {
167*4bdff4beSrobert         _Ops::iter_swap(__first, __last);
16876d0caaeSpatrick         return __last;
16976d0caaeSpatrick     }
17076d0caaeSpatrick     if (__len == 3)
17176d0caaeSpatrick     {
17276d0caaeSpatrick         _BidirectionalIterator __m = __first;
17376d0caaeSpatrick         if (__pred(*++__m))
17476d0caaeSpatrick         {
175*4bdff4beSrobert             _Ops::iter_swap(__first, __m);
176*4bdff4beSrobert             _Ops::iter_swap(__m, __last);
17776d0caaeSpatrick             return __last;
17876d0caaeSpatrick         }
179*4bdff4beSrobert         _Ops::iter_swap(__m, __last);
180*4bdff4beSrobert         _Ops::iter_swap(__first, __m);
18176d0caaeSpatrick         return __m;
18276d0caaeSpatrick     }
18376d0caaeSpatrick     if (__len <= __p.second)
18476d0caaeSpatrick     {   // The buffer is big enough to use
18576d0caaeSpatrick         typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
18676d0caaeSpatrick         __destruct_n __d(0);
18776d0caaeSpatrick         unique_ptr<value_type, __destruct_n&> __h(__p.first, __d);
18876d0caaeSpatrick         // Move the falses into the temporary buffer, and the trues to the front of the line
18976d0caaeSpatrick         // Update __first to always point to the end of the trues
19076d0caaeSpatrick         value_type* __t = __p.first;
191*4bdff4beSrobert         ::new ((void*)__t) value_type(_Ops::__iter_move(__first));
19276d0caaeSpatrick         __d.template __incr<value_type>();
19376d0caaeSpatrick         ++__t;
19476d0caaeSpatrick         _BidirectionalIterator __i = __first;
19576d0caaeSpatrick         while (++__i != __last)
19676d0caaeSpatrick         {
19776d0caaeSpatrick             if (__pred(*__i))
19876d0caaeSpatrick             {
199*4bdff4beSrobert                 *__first = _Ops::__iter_move(__i);
20076d0caaeSpatrick                 ++__first;
20176d0caaeSpatrick             }
20276d0caaeSpatrick             else
20376d0caaeSpatrick             {
204*4bdff4beSrobert                 ::new ((void*)__t) value_type(_Ops::__iter_move(__i));
20576d0caaeSpatrick                 __d.template __incr<value_type>();
20676d0caaeSpatrick                 ++__t;
20776d0caaeSpatrick             }
20876d0caaeSpatrick         }
20976d0caaeSpatrick         // move *__last, known to be true
210*4bdff4beSrobert         *__first = _Ops::__iter_move(__i);
21176d0caaeSpatrick         __i = ++__first;
21276d0caaeSpatrick         // All trues now at start of range, all falses in buffer
21376d0caaeSpatrick         // Move falses back into range, but don't mess up __first which points to first false
21476d0caaeSpatrick         for (value_type* __t2 = __p.first; __t2 < __t; ++__t2, (void) ++__i)
215*4bdff4beSrobert             *__i = _Ops::__iter_move(__t2);
21676d0caaeSpatrick         // __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer
21776d0caaeSpatrick         return __first;
21876d0caaeSpatrick     }
21976d0caaeSpatrick     // Else not enough buffer, do in place
22076d0caaeSpatrick     // __len >= 4
22176d0caaeSpatrick     _BidirectionalIterator __m = __first;
22276d0caaeSpatrick     _Distance __len2 = __len / 2;  // __len2 >= 2
223*4bdff4beSrobert     _Ops::advance(__m, __len2);
22476d0caaeSpatrick     // recurse on [__first, __m-1], except reduce __m-1 until *(__m-1) is true, *__first know to be false
22576d0caaeSpatrick     // F????????????????T
22676d0caaeSpatrick     // f       m        l
22776d0caaeSpatrick     _BidirectionalIterator __m1 = __m;
22876d0caaeSpatrick     _BidirectionalIterator __first_false = __first;
22976d0caaeSpatrick     _Distance __len_half = __len2;
23076d0caaeSpatrick     while (!__pred(*--__m1))
23176d0caaeSpatrick     {
23276d0caaeSpatrick         if (__m1 == __first)
23376d0caaeSpatrick             goto __first_half_done;
23476d0caaeSpatrick         --__len_half;
23576d0caaeSpatrick     }
23676d0caaeSpatrick     // F???TFFF?????????T
23776d0caaeSpatrick     // f   m1  m        l
238*4bdff4beSrobert     __first_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
239*4bdff4beSrobert         __first, __m1, __pred, __len_half, __p, __bit);
24076d0caaeSpatrick __first_half_done:
24176d0caaeSpatrick     // TTTFFFFF?????????T
24276d0caaeSpatrick     // f  ff   m        l
24376d0caaeSpatrick     // recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true
24476d0caaeSpatrick     __m1 = __m;
24576d0caaeSpatrick     _BidirectionalIterator __second_false = __last;
24676d0caaeSpatrick     ++__second_false;
24776d0caaeSpatrick     __len_half = __len - __len2;
24876d0caaeSpatrick     while (__pred(*__m1))
24976d0caaeSpatrick     {
25076d0caaeSpatrick         if (++__m1 == __last)
25176d0caaeSpatrick             goto __second_half_done;
25276d0caaeSpatrick         --__len_half;
25376d0caaeSpatrick     }
25476d0caaeSpatrick     // TTTFFFFFTTTF?????T
25576d0caaeSpatrick     // f  ff   m  m1    l
256*4bdff4beSrobert     __second_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
257*4bdff4beSrobert         __m1, __last, __pred, __len_half, __p, __bit);
25876d0caaeSpatrick __second_half_done:
25976d0caaeSpatrick     // TTTFFFFFTTTTTFFFFF
26076d0caaeSpatrick     // f  ff   m    sf  l
261*4bdff4beSrobert     return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false).first;
26276d0caaeSpatrick     // TTTTTTTTFFFFFFFFFF
26376d0caaeSpatrick     //         |
26476d0caaeSpatrick }
26576d0caaeSpatrick 
266*4bdff4beSrobert template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator>
267*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI _BidirectionalIterator
__stable_partition_impl(_BidirectionalIterator __first,_BidirectionalIterator __last,_Predicate __pred,bidirectional_iterator_tag)268*4bdff4beSrobert __stable_partition_impl(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred,
26976d0caaeSpatrick                    bidirectional_iterator_tag)
27076d0caaeSpatrick {
27176d0caaeSpatrick     typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
27276d0caaeSpatrick     typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
27376d0caaeSpatrick     const difference_type __alloc_limit = 4;  // might want to make this a function of trivial assignment
27476d0caaeSpatrick     // Either prove all true and return __first or point to first false
27576d0caaeSpatrick     while (true)
27676d0caaeSpatrick     {
27776d0caaeSpatrick         if (__first == __last)
27876d0caaeSpatrick             return __first;
27976d0caaeSpatrick         if (!__pred(*__first))
28076d0caaeSpatrick             break;
28176d0caaeSpatrick         ++__first;
28276d0caaeSpatrick     }
28376d0caaeSpatrick     // __first points to first false, everything prior to __first is already set.
28476d0caaeSpatrick     // Either prove [__first, __last) is all false and return __first, or point __last to last true
28576d0caaeSpatrick     do
28676d0caaeSpatrick     {
28776d0caaeSpatrick         if (__first == --__last)
28876d0caaeSpatrick             return __first;
28976d0caaeSpatrick     } while (!__pred(*__last));
29076d0caaeSpatrick     // We now have a reduced range [__first, __last]
29176d0caaeSpatrick     // *__first is known to be false
29276d0caaeSpatrick     // *__last is known to be true
29376d0caaeSpatrick     // __len >= 2
294*4bdff4beSrobert     difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last) + 1;
29576d0caaeSpatrick     pair<value_type*, ptrdiff_t> __p(0, 0);
29676d0caaeSpatrick     unique_ptr<value_type, __return_temporary_buffer> __h;
29776d0caaeSpatrick     if (__len >= __alloc_limit)
29876d0caaeSpatrick     {
299*4bdff4beSrobert // TODO: Remove the use of std::get_temporary_buffer
300*4bdff4beSrobert _LIBCPP_SUPPRESS_DEPRECATED_PUSH
30176d0caaeSpatrick         __p = _VSTD::get_temporary_buffer<value_type>(__len);
302*4bdff4beSrobert _LIBCPP_SUPPRESS_DEPRECATED_POP
30376d0caaeSpatrick         __h.reset(__p.first);
30476d0caaeSpatrick     }
305*4bdff4beSrobert     return std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
306*4bdff4beSrobert         std::move(__first), std::move(__last), __pred, __len, __p, bidirectional_iterator_tag());
307*4bdff4beSrobert }
308*4bdff4beSrobert 
309*4bdff4beSrobert template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _IterCategory>
310*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI
__stable_partition(_ForwardIterator __first,_ForwardIterator __last,_Predicate && __pred,_IterCategory __iter_category)311*4bdff4beSrobert _ForwardIterator __stable_partition(
312*4bdff4beSrobert     _ForwardIterator __first, _ForwardIterator __last, _Predicate&& __pred, _IterCategory __iter_category) {
313*4bdff4beSrobert   return std::__stable_partition_impl<_AlgPolicy, __remove_cvref_t<_Predicate>&>(
314*4bdff4beSrobert       std::move(__first), std::move(__last), __pred, __iter_category);
31576d0caaeSpatrick }
31676d0caaeSpatrick 
31776d0caaeSpatrick template <class _ForwardIterator, class _Predicate>
31876d0caaeSpatrick inline _LIBCPP_INLINE_VISIBILITY
31976d0caaeSpatrick _ForwardIterator
stable_partition(_ForwardIterator __first,_ForwardIterator __last,_Predicate __pred)32076d0caaeSpatrick stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred)
32176d0caaeSpatrick {
322*4bdff4beSrobert   using _IterCategory = typename iterator_traits<_ForwardIterator>::iterator_category;
323*4bdff4beSrobert   return std::__stable_partition<_ClassicAlgPolicy, _Predicate&>(
324*4bdff4beSrobert       std::move(__first), std::move(__last), __pred, _IterCategory());
32576d0caaeSpatrick }
32676d0caaeSpatrick 
32776d0caaeSpatrick _LIBCPP_END_NAMESPACE_STD
32876d0caaeSpatrick 
32976d0caaeSpatrick #endif // _LIBCPP___ALGORITHM_STABLE_PARTITION_H
330