xref: /openbsd-src/gnu/llvm/libcxx/include/__algorithm/inplace_merge.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_INPLACE_MERGE_H
1076d0caaeSpatrick #define _LIBCPP___ALGORITHM_INPLACE_MERGE_H
1176d0caaeSpatrick 
1276d0caaeSpatrick #include <__algorithm/comp.h>
13*4bdff4beSrobert #include <__algorithm/comp_ref_type.h>
14*4bdff4beSrobert #include <__algorithm/iterator_operations.h>
1576d0caaeSpatrick #include <__algorithm/lower_bound.h>
1676d0caaeSpatrick #include <__algorithm/min.h>
1776d0caaeSpatrick #include <__algorithm/move.h>
1876d0caaeSpatrick #include <__algorithm/rotate.h>
1976d0caaeSpatrick #include <__algorithm/upper_bound.h>
20*4bdff4beSrobert #include <__config>
21*4bdff4beSrobert #include <__functional/identity.h>
22*4bdff4beSrobert #include <__iterator/advance.h>
23*4bdff4beSrobert #include <__iterator/distance.h>
2476d0caaeSpatrick #include <__iterator/iterator_traits.h>
25*4bdff4beSrobert #include <__iterator/reverse_iterator.h>
26*4bdff4beSrobert #include <__memory/destruct_n.h>
27*4bdff4beSrobert #include <__memory/temporary_buffer.h>
28*4bdff4beSrobert #include <__memory/unique_ptr.h>
29*4bdff4beSrobert #include <__utility/pair.h>
30*4bdff4beSrobert #include <new>
3176d0caaeSpatrick 
3276d0caaeSpatrick #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
3376d0caaeSpatrick #  pragma GCC system_header
3476d0caaeSpatrick #endif
3576d0caaeSpatrick 
3676d0caaeSpatrick _LIBCPP_PUSH_MACROS
3776d0caaeSpatrick #include <__undef_macros>
3876d0caaeSpatrick 
3976d0caaeSpatrick _LIBCPP_BEGIN_NAMESPACE_STD
4076d0caaeSpatrick 
4176d0caaeSpatrick template <class _Predicate>
4276d0caaeSpatrick class __invert // invert the sense of a comparison
4376d0caaeSpatrick {
4476d0caaeSpatrick private:
4576d0caaeSpatrick     _Predicate __p_;
4676d0caaeSpatrick public:
__invert()4776d0caaeSpatrick     _LIBCPP_INLINE_VISIBILITY __invert() {}
4876d0caaeSpatrick 
4976d0caaeSpatrick     _LIBCPP_INLINE_VISIBILITY
__invert(_Predicate __p)5076d0caaeSpatrick     explicit __invert(_Predicate __p) : __p_(__p) {}
5176d0caaeSpatrick 
5276d0caaeSpatrick     template <class _T1>
5376d0caaeSpatrick     _LIBCPP_INLINE_VISIBILITY
operator()5476d0caaeSpatrick     bool operator()(const _T1& __x) {return !__p_(__x);}
5576d0caaeSpatrick 
5676d0caaeSpatrick     template <class _T1, class _T2>
5776d0caaeSpatrick     _LIBCPP_INLINE_VISIBILITY
operator()5876d0caaeSpatrick     bool operator()(const _T1& __x, const _T2& __y) {return __p_(__y, __x);}
5976d0caaeSpatrick };
6076d0caaeSpatrick 
61*4bdff4beSrobert template <class _AlgPolicy, class _Compare, class _InputIterator1, class _Sent1,
62*4bdff4beSrobert           class _InputIterator2, class _Sent2, class _OutputIterator>
63*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI
__half_inplace_merge(_InputIterator1 __first1,_Sent1 __last1,_InputIterator2 __first2,_Sent2 __last2,_OutputIterator __result,_Compare && __comp)64*4bdff4beSrobert void __half_inplace_merge(_InputIterator1 __first1, _Sent1 __last1,
65*4bdff4beSrobert                           _InputIterator2 __first2, _Sent2 __last2,
66*4bdff4beSrobert                           _OutputIterator __result, _Compare&& __comp)
6776d0caaeSpatrick {
6876d0caaeSpatrick     for (; __first1 != __last1; ++__result)
6976d0caaeSpatrick     {
7076d0caaeSpatrick         if (__first2 == __last2)
7176d0caaeSpatrick         {
72*4bdff4beSrobert             std::__move<_AlgPolicy>(__first1, __last1, __result);
7376d0caaeSpatrick             return;
7476d0caaeSpatrick         }
7576d0caaeSpatrick 
7676d0caaeSpatrick         if (__comp(*__first2, *__first1))
7776d0caaeSpatrick         {
78*4bdff4beSrobert             *__result = _IterOps<_AlgPolicy>::__iter_move(__first2);
7976d0caaeSpatrick             ++__first2;
8076d0caaeSpatrick         }
8176d0caaeSpatrick         else
8276d0caaeSpatrick         {
83*4bdff4beSrobert             *__result = _IterOps<_AlgPolicy>::__iter_move(__first1);
8476d0caaeSpatrick             ++__first1;
8576d0caaeSpatrick         }
8676d0caaeSpatrick     }
8776d0caaeSpatrick     // __first2 through __last2 are already in the right spot.
8876d0caaeSpatrick }
8976d0caaeSpatrick 
90*4bdff4beSrobert template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
91*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI
__buffered_inplace_merge(_BidirectionalIterator __first,_BidirectionalIterator __middle,_BidirectionalIterator __last,_Compare && __comp,typename iterator_traits<_BidirectionalIterator>::difference_type __len1,typename iterator_traits<_BidirectionalIterator>::difference_type __len2,typename iterator_traits<_BidirectionalIterator>::value_type * __buff)92*4bdff4beSrobert void __buffered_inplace_merge(
93*4bdff4beSrobert     _BidirectionalIterator __first,
94*4bdff4beSrobert     _BidirectionalIterator __middle,
95*4bdff4beSrobert     _BidirectionalIterator __last,
96*4bdff4beSrobert     _Compare&& __comp,
97*4bdff4beSrobert     typename iterator_traits<_BidirectionalIterator>::difference_type __len1,
9876d0caaeSpatrick     typename iterator_traits<_BidirectionalIterator>::difference_type __len2,
99*4bdff4beSrobert     typename iterator_traits<_BidirectionalIterator>::value_type* __buff) {
10076d0caaeSpatrick   typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
10176d0caaeSpatrick     __destruct_n __d(0);
10276d0caaeSpatrick     unique_ptr<value_type, __destruct_n&> __h2(__buff, __d);
10376d0caaeSpatrick     if (__len1 <= __len2)
10476d0caaeSpatrick     {
10576d0caaeSpatrick         value_type* __p = __buff;
10676d0caaeSpatrick         for (_BidirectionalIterator __i = __first; __i != __middle; __d.template __incr<value_type>(), (void) ++__i, (void) ++__p)
107*4bdff4beSrobert             ::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
108*4bdff4beSrobert         std::__half_inplace_merge<_AlgPolicy>(__buff, __p, __middle, __last, __first, __comp);
10976d0caaeSpatrick     }
11076d0caaeSpatrick     else
11176d0caaeSpatrick     {
11276d0caaeSpatrick         value_type* __p = __buff;
11376d0caaeSpatrick         for (_BidirectionalIterator __i = __middle; __i != __last; __d.template __incr<value_type>(), (void) ++__i, (void) ++__p)
114*4bdff4beSrobert             ::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
115*4bdff4beSrobert         typedef __unconstrained_reverse_iterator<_BidirectionalIterator> _RBi;
116*4bdff4beSrobert         typedef __unconstrained_reverse_iterator<value_type*> _Rv;
11776d0caaeSpatrick         typedef __invert<_Compare> _Inverted;
118*4bdff4beSrobert         std::__half_inplace_merge<_AlgPolicy>(_Rv(__p), _Rv(__buff),
11976d0caaeSpatrick                                     _RBi(__middle), _RBi(__first),
12076d0caaeSpatrick                                     _RBi(__last), _Inverted(__comp));
12176d0caaeSpatrick     }
12276d0caaeSpatrick }
12376d0caaeSpatrick 
124*4bdff4beSrobert template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
__inplace_merge(_BidirectionalIterator __first,_BidirectionalIterator __middle,_BidirectionalIterator __last,_Compare && __comp,typename iterator_traits<_BidirectionalIterator>::difference_type __len1,typename iterator_traits<_BidirectionalIterator>::difference_type __len2,typename iterator_traits<_BidirectionalIterator>::value_type * __buff,ptrdiff_t __buff_size)125*4bdff4beSrobert void __inplace_merge(
126*4bdff4beSrobert     _BidirectionalIterator __first,
127*4bdff4beSrobert     _BidirectionalIterator __middle,
128*4bdff4beSrobert     _BidirectionalIterator __last,
129*4bdff4beSrobert     _Compare&& __comp,
130*4bdff4beSrobert     typename iterator_traits<_BidirectionalIterator>::difference_type __len1,
13176d0caaeSpatrick     typename iterator_traits<_BidirectionalIterator>::difference_type __len2,
132*4bdff4beSrobert     typename iterator_traits<_BidirectionalIterator>::value_type* __buff,
133*4bdff4beSrobert     ptrdiff_t __buff_size) {
134*4bdff4beSrobert     using _Ops = _IterOps<_AlgPolicy>;
135*4bdff4beSrobert 
13676d0caaeSpatrick     typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
13776d0caaeSpatrick     while (true)
13876d0caaeSpatrick     {
13976d0caaeSpatrick         // if __middle == __last, we're done
14076d0caaeSpatrick         if (__len2 == 0)
14176d0caaeSpatrick             return;
14276d0caaeSpatrick         if (__len1 <= __buff_size || __len2 <= __buff_size)
143*4bdff4beSrobert             return std::__buffered_inplace_merge<_AlgPolicy>
14476d0caaeSpatrick                    (__first, __middle, __last, __comp, __len1, __len2, __buff);
14576d0caaeSpatrick         // shrink [__first, __middle) as much as possible (with no moves), returning if it shrinks to 0
14676d0caaeSpatrick         for (; true; ++__first, (void) --__len1)
14776d0caaeSpatrick         {
14876d0caaeSpatrick             if (__len1 == 0)
14976d0caaeSpatrick                 return;
15076d0caaeSpatrick             if (__comp(*__middle, *__first))
15176d0caaeSpatrick                 break;
15276d0caaeSpatrick         }
15376d0caaeSpatrick         // __first < __middle < __last
15476d0caaeSpatrick         // *__first > *__middle
15576d0caaeSpatrick         // partition [__first, __m1) [__m1, __middle) [__middle, __m2) [__m2, __last) such that
15676d0caaeSpatrick         //     all elements in:
15776d0caaeSpatrick         //         [__first, __m1)  <= [__middle, __m2)
15876d0caaeSpatrick         //         [__middle, __m2) <  [__m1, __middle)
15976d0caaeSpatrick         //         [__m1, __middle) <= [__m2, __last)
16076d0caaeSpatrick         //     and __m1 or __m2 is in the middle of its range
16176d0caaeSpatrick         _BidirectionalIterator __m1;  // "median" of [__first, __middle)
16276d0caaeSpatrick         _BidirectionalIterator __m2;  // "median" of [__middle, __last)
16376d0caaeSpatrick         difference_type __len11;      // distance(__first, __m1)
16476d0caaeSpatrick         difference_type __len21;      // distance(__middle, __m2)
16576d0caaeSpatrick         // binary search smaller range
16676d0caaeSpatrick         if (__len1 < __len2)
16776d0caaeSpatrick         {   // __len >= 1, __len2 >= 2
16876d0caaeSpatrick             __len21 = __len2 / 2;
16976d0caaeSpatrick             __m2 = __middle;
170*4bdff4beSrobert             _Ops::advance(__m2, __len21);
171*4bdff4beSrobert             __m1 = std::__upper_bound<_AlgPolicy>(__first, __middle, *__m2, __comp, std::__identity());
172*4bdff4beSrobert             __len11 = _Ops::distance(__first, __m1);
17376d0caaeSpatrick         }
17476d0caaeSpatrick         else
17576d0caaeSpatrick         {
17676d0caaeSpatrick             if (__len1 == 1)
17776d0caaeSpatrick             {   // __len1 >= __len2 && __len2 > 0, therefore __len2 == 1
17876d0caaeSpatrick                 // It is known *__first > *__middle
179*4bdff4beSrobert               _Ops::iter_swap(__first, __middle);
18076d0caaeSpatrick                 return;
18176d0caaeSpatrick             }
18276d0caaeSpatrick             // __len1 >= 2, __len2 >= 1
18376d0caaeSpatrick             __len11 = __len1 / 2;
18476d0caaeSpatrick             __m1 = __first;
185*4bdff4beSrobert             _Ops::advance(__m1, __len11);
186*4bdff4beSrobert             __m2 = std::lower_bound(__middle, __last, *__m1, __comp);
187*4bdff4beSrobert             __len21 = _Ops::distance(__middle, __m2);
18876d0caaeSpatrick         }
18976d0caaeSpatrick         difference_type __len12 = __len1 - __len11;  // distance(__m1, __middle)
19076d0caaeSpatrick         difference_type __len22 = __len2 - __len21;  // distance(__m2, __last)
19176d0caaeSpatrick         // [__first, __m1) [__m1, __middle) [__middle, __m2) [__m2, __last)
19276d0caaeSpatrick         // swap middle two partitions
193*4bdff4beSrobert         __middle = std::__rotate<_AlgPolicy>(__m1, __middle, __m2).first;
19476d0caaeSpatrick         // __len12 and __len21 now have swapped meanings
19576d0caaeSpatrick         // merge smaller range with recursive call and larger with tail recursion elimination
19676d0caaeSpatrick         if (__len11 + __len21 < __len12 + __len22)
19776d0caaeSpatrick         {
198*4bdff4beSrobert             std::__inplace_merge<_AlgPolicy>(
199*4bdff4beSrobert                 __first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);
20076d0caaeSpatrick             __first = __middle;
20176d0caaeSpatrick             __middle = __m2;
20276d0caaeSpatrick             __len1 = __len12;
20376d0caaeSpatrick             __len2 = __len22;
20476d0caaeSpatrick         }
20576d0caaeSpatrick         else
20676d0caaeSpatrick         {
207*4bdff4beSrobert             std::__inplace_merge<_AlgPolicy>(
208*4bdff4beSrobert                 __middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);
20976d0caaeSpatrick             __last = __middle;
21076d0caaeSpatrick             __middle = __m1;
21176d0caaeSpatrick             __len1 = __len11;
21276d0caaeSpatrick             __len2 = __len21;
21376d0caaeSpatrick         }
21476d0caaeSpatrick     }
21576d0caaeSpatrick }
21676d0caaeSpatrick 
217*4bdff4beSrobert template <class _AlgPolicy, class _BidirectionalIterator, class _Compare>
218*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI
21976d0caaeSpatrick void
__inplace_merge(_BidirectionalIterator __first,_BidirectionalIterator __middle,_BidirectionalIterator __last,_Compare && __comp)220*4bdff4beSrobert __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
221*4bdff4beSrobert               _Compare&& __comp)
22276d0caaeSpatrick {
22376d0caaeSpatrick     typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
22476d0caaeSpatrick     typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
225*4bdff4beSrobert     difference_type __len1 = _IterOps<_AlgPolicy>::distance(__first, __middle);
226*4bdff4beSrobert     difference_type __len2 = _IterOps<_AlgPolicy>::distance(__middle, __last);
22776d0caaeSpatrick     difference_type __buf_size = _VSTD::min(__len1, __len2);
228*4bdff4beSrobert // TODO: Remove the use of std::get_temporary_buffer
229*4bdff4beSrobert _LIBCPP_SUPPRESS_DEPRECATED_PUSH
23076d0caaeSpatrick     pair<value_type*, ptrdiff_t> __buf = _VSTD::get_temporary_buffer<value_type>(__buf_size);
231*4bdff4beSrobert _LIBCPP_SUPPRESS_DEPRECATED_POP
23276d0caaeSpatrick     unique_ptr<value_type, __return_temporary_buffer> __h(__buf.first);
233*4bdff4beSrobert     return std::__inplace_merge<_AlgPolicy>(
234*4bdff4beSrobert         std::move(__first), std::move(__middle), std::move(__last), __comp, __len1, __len2, __buf.first, __buf.second);
235*4bdff4beSrobert }
236*4bdff4beSrobert 
237*4bdff4beSrobert template <class _BidirectionalIterator, class _Compare>
inplace_merge(_BidirectionalIterator __first,_BidirectionalIterator __middle,_BidirectionalIterator __last,_Compare __comp)238*4bdff4beSrobert inline _LIBCPP_HIDE_FROM_ABI void inplace_merge(
239*4bdff4beSrobert     _BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare __comp) {
240*4bdff4beSrobert   std::__inplace_merge<_ClassicAlgPolicy>(
241*4bdff4beSrobert       std::move(__first), std::move(__middle), std::move(__last), static_cast<__comp_ref_type<_Compare> >(__comp));
24276d0caaeSpatrick }
24376d0caaeSpatrick 
24476d0caaeSpatrick template <class _BidirectionalIterator>
245*4bdff4beSrobert inline _LIBCPP_HIDE_FROM_ABI
24676d0caaeSpatrick void
inplace_merge(_BidirectionalIterator __first,_BidirectionalIterator __middle,_BidirectionalIterator __last)24776d0caaeSpatrick inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last)
24876d0caaeSpatrick {
249*4bdff4beSrobert     std::inplace_merge(std::move(__first), std::move(__middle), std::move(__last),
25076d0caaeSpatrick                         __less<typename iterator_traits<_BidirectionalIterator>::value_type>());
25176d0caaeSpatrick }
25276d0caaeSpatrick 
25376d0caaeSpatrick _LIBCPP_END_NAMESPACE_STD
25476d0caaeSpatrick 
25576d0caaeSpatrick _LIBCPP_POP_MACROS
25676d0caaeSpatrick 
25776d0caaeSpatrick #endif // _LIBCPP___ALGORITHM_INPLACE_MERGE_H
258