Path: blob/main/contrib/llvm-project/libcxx/include/__algorithm/inplace_merge.h
35234 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef _LIBCPP___ALGORITHM_INPLACE_MERGE_H9#define _LIBCPP___ALGORITHM_INPLACE_MERGE_H1011#include <__algorithm/comp.h>12#include <__algorithm/comp_ref_type.h>13#include <__algorithm/iterator_operations.h>14#include <__algorithm/lower_bound.h>15#include <__algorithm/min.h>16#include <__algorithm/move.h>17#include <__algorithm/rotate.h>18#include <__algorithm/upper_bound.h>19#include <__config>20#include <__functional/identity.h>21#include <__iterator/advance.h>22#include <__iterator/distance.h>23#include <__iterator/iterator_traits.h>24#include <__iterator/reverse_iterator.h>25#include <__memory/destruct_n.h>26#include <__memory/temporary_buffer.h>27#include <__memory/unique_ptr.h>28#include <__utility/pair.h>29#include <new>3031#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)32# pragma GCC system_header33#endif3435_LIBCPP_PUSH_MACROS36#include <__undef_macros>3738_LIBCPP_BEGIN_NAMESPACE_STD3940template <class _Predicate>41class __invert // invert the sense of a comparison42{43private:44_Predicate __p_;4546public:47_LIBCPP_HIDE_FROM_ABI __invert() {}4849_LIBCPP_HIDE_FROM_ABI explicit __invert(_Predicate __p) : __p_(__p) {}5051template <class _T1>52_LIBCPP_HIDE_FROM_ABI bool operator()(const _T1& __x) {53return !__p_(__x);54}5556template <class _T1, class _T2>57_LIBCPP_HIDE_FROM_ABI bool operator()(const _T1& __x, const _T2& __y) {58return __p_(__y, __x);59}60};6162template <class _AlgPolicy,63class _Compare,64class _InputIterator1,65class _Sent1,66class _InputIterator2,67class _Sent2,68class _OutputIterator>69_LIBCPP_HIDE_FROM_ABI void __half_inplace_merge(70_InputIterator1 __first1,71_Sent1 __last1,72_InputIterator2 __first2,73_Sent2 __last2,74_OutputIterator __result,75_Compare&& __comp) {76for (; __first1 != __last1; ++__result) {77if (__first2 == __last2) {78std::__move<_AlgPolicy>(__first1, __last1, __result);79return;80}8182if (__comp(*__first2, *__first1)) {83*__result = _IterOps<_AlgPolicy>::__iter_move(__first2);84++__first2;85} else {86*__result = _IterOps<_AlgPolicy>::__iter_move(__first1);87++__first1;88}89}90// __first2 through __last2 are already in the right spot.91}9293template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>94_LIBCPP_HIDE_FROM_ABI void __buffered_inplace_merge(95_BidirectionalIterator __first,96_BidirectionalIterator __middle,97_BidirectionalIterator __last,98_Compare&& __comp,99typename iterator_traits<_BidirectionalIterator>::difference_type __len1,100typename iterator_traits<_BidirectionalIterator>::difference_type __len2,101typename iterator_traits<_BidirectionalIterator>::value_type* __buff) {102typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;103__destruct_n __d(0);104unique_ptr<value_type, __destruct_n&> __h2(__buff, __d);105if (__len1 <= __len2) {106value_type* __p = __buff;107for (_BidirectionalIterator __i = __first; __i != __middle;108__d.template __incr<value_type>(), (void)++__i, (void)++__p)109::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));110std::__half_inplace_merge<_AlgPolicy>(__buff, __p, __middle, __last, __first, __comp);111} else {112value_type* __p = __buff;113for (_BidirectionalIterator __i = __middle; __i != __last;114__d.template __incr<value_type>(), (void)++__i, (void)++__p)115::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));116typedef reverse_iterator<_BidirectionalIterator> _RBi;117typedef reverse_iterator<value_type*> _Rv;118typedef __invert<_Compare> _Inverted;119std::__half_inplace_merge<_AlgPolicy>(120_Rv(__p), _Rv(__buff), _RBi(__middle), _RBi(__first), _RBi(__last), _Inverted(__comp));121}122}123124template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>125void __inplace_merge(126_BidirectionalIterator __first,127_BidirectionalIterator __middle,128_BidirectionalIterator __last,129_Compare&& __comp,130typename iterator_traits<_BidirectionalIterator>::difference_type __len1,131typename iterator_traits<_BidirectionalIterator>::difference_type __len2,132typename iterator_traits<_BidirectionalIterator>::value_type* __buff,133ptrdiff_t __buff_size) {134using _Ops = _IterOps<_AlgPolicy>;135136typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;137while (true) {138// if __middle == __last, we're done139if (__len2 == 0)140return;141if (__len1 <= __buff_size || __len2 <= __buff_size)142return std::__buffered_inplace_merge<_AlgPolicy>(__first, __middle, __last, __comp, __len1, __len2, __buff);143// shrink [__first, __middle) as much as possible (with no moves), returning if it shrinks to 0144for (; true; ++__first, (void)--__len1) {145if (__len1 == 0)146return;147if (__comp(*__middle, *__first))148break;149}150// __first < __middle < __last151// *__first > *__middle152// partition [__first, __m1) [__m1, __middle) [__middle, __m2) [__m2, __last) such that153// all elements in:154// [__first, __m1) <= [__middle, __m2)155// [__middle, __m2) < [__m1, __middle)156// [__m1, __middle) <= [__m2, __last)157// and __m1 or __m2 is in the middle of its range158_BidirectionalIterator __m1; // "median" of [__first, __middle)159_BidirectionalIterator __m2; // "median" of [__middle, __last)160difference_type __len11; // distance(__first, __m1)161difference_type __len21; // distance(__middle, __m2)162// binary search smaller range163if (__len1 < __len2) { // __len >= 1, __len2 >= 2164__len21 = __len2 / 2;165__m2 = __middle;166_Ops::advance(__m2, __len21);167__m1 = std::__upper_bound<_AlgPolicy>(__first, __middle, *__m2, __comp, std::__identity());168__len11 = _Ops::distance(__first, __m1);169} else {170if (__len1 == 1) { // __len1 >= __len2 && __len2 > 0, therefore __len2 == 1171// It is known *__first > *__middle172_Ops::iter_swap(__first, __middle);173return;174}175// __len1 >= 2, __len2 >= 1176__len11 = __len1 / 2;177__m1 = __first;178_Ops::advance(__m1, __len11);179__m2 = std::lower_bound(__middle, __last, *__m1, __comp);180__len21 = _Ops::distance(__middle, __m2);181}182difference_type __len12 = __len1 - __len11; // distance(__m1, __middle)183difference_type __len22 = __len2 - __len21; // distance(__m2, __last)184// [__first, __m1) [__m1, __middle) [__middle, __m2) [__m2, __last)185// swap middle two partitions186__middle = std::__rotate<_AlgPolicy>(__m1, __middle, __m2).first;187// __len12 and __len21 now have swapped meanings188// merge smaller range with recursive call and larger with tail recursion elimination189if (__len11 + __len21 < __len12 + __len22) {190std::__inplace_merge<_AlgPolicy>(__first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);191__first = __middle;192__middle = __m2;193__len1 = __len12;194__len2 = __len22;195} else {196std::__inplace_merge<_AlgPolicy>(__middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);197__last = __middle;198__middle = __m1;199__len1 = __len11;200__len2 = __len21;201}202}203}204205template <class _AlgPolicy, class _BidirectionalIterator, class _Compare>206_LIBCPP_HIDE_FROM_ABI void __inplace_merge(207_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare&& __comp) {208typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;209typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;210difference_type __len1 = _IterOps<_AlgPolicy>::distance(__first, __middle);211difference_type __len2 = _IterOps<_AlgPolicy>::distance(__middle, __last);212difference_type __buf_size = std::min(__len1, __len2);213// TODO: Remove the use of std::get_temporary_buffer214_LIBCPP_SUPPRESS_DEPRECATED_PUSH215pair<value_type*, ptrdiff_t> __buf = std::get_temporary_buffer<value_type>(__buf_size);216_LIBCPP_SUPPRESS_DEPRECATED_POP217unique_ptr<value_type, __return_temporary_buffer> __h(__buf.first);218return std::__inplace_merge<_AlgPolicy>(219std::move(__first), std::move(__middle), std::move(__last), __comp, __len1, __len2, __buf.first, __buf.second);220}221222template <class _BidirectionalIterator, class _Compare>223inline _LIBCPP_HIDE_FROM_ABI void inplace_merge(224_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare __comp) {225std::__inplace_merge<_ClassicAlgPolicy>(226std::move(__first), std::move(__middle), std::move(__last), static_cast<__comp_ref_type<_Compare> >(__comp));227}228229template <class _BidirectionalIterator>230inline _LIBCPP_HIDE_FROM_ABI void231inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last) {232std::inplace_merge(std::move(__first), std::move(__middle), std::move(__last), __less<>());233}234235_LIBCPP_END_NAMESPACE_STD236237_LIBCPP_POP_MACROS238239#endif // _LIBCPP___ALGORITHM_INPLACE_MERGE_H240241242