1 //////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Ion Gaztanaga 2015-2016.
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
8 // See http://www.boost.org/libs/move for documentation.
10 //////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_MOVE_MERGE_HPP
12 #define BOOST_MOVE_MERGE_HPP
14 #include <boost/move/algo/move.hpp>
15 #include <boost/move/adl_move_swap.hpp>
16 #include <boost/move/algo/detail/basic_op.hpp>
17 #include <boost/move/detail/iterator_traits.hpp>
18 #include <boost/move/detail/destruct_n.hpp>
19 #include <boost/move/algo/predicate.hpp>
20 #include <boost/move/detail/iterator_to_raw_pointer.hpp>
21 #include <boost/assert.hpp>
27 template<class T, class RandRawIt = T*, class SizeType = typename iterator_traits<RandRawIt>::size_type>
30 adaptive_xbuf(const adaptive_xbuf &);
31 adaptive_xbuf & operator=(const adaptive_xbuf &);
33 #if !defined(UINTPTR_MAX)
34 typedef std::size_t uintptr_t;
38 typedef RandRawIt iterator;
39 typedef SizeType size_type;
42 : m_ptr(), m_size(0), m_capacity(0)
45 adaptive_xbuf(RandRawIt raw_memory, size_type capacity)
46 : m_ptr(raw_memory), m_size(0), m_capacity(capacity)
49 template<class RandIt>
50 void move_assign(RandIt first, size_type n)
53 boost::move(first, first+n, m_ptr);
54 size_type size = m_size;
61 RandRawIt result = boost::move(first, first+m_size, m_ptr);
62 boost::uninitialized_move(first+m_size, first+n, result);
67 template<class RandIt>
68 void push_back(RandIt first, size_type n)
70 BOOST_ASSERT(m_capacity - m_size >= n);
71 boost::uninitialized_move(first, first+n, m_ptr+m_size);
75 template<class RandIt>
76 iterator add(RandIt it)
78 BOOST_ASSERT(m_size < m_capacity);
79 RandRawIt p_ret = m_ptr + m_size;
80 ::new(&*p_ret) T(::boost::move(*it));
85 template<class RandIt>
86 void insert(iterator pos, RandIt it)
88 if(pos == (m_ptr + m_size)){
92 this->add(m_ptr+m_size-1);
94 boost::move_backward(pos, m_ptr+m_size-2, m_ptr+m_size-1);
95 *pos = boost::move(*it);
99 void set_size(size_type size)
104 void shrink_to_fit(size_type const size)
107 for(size_type szt_i = size; szt_i != m_size; ++szt_i){
114 void initialize_until(size_type const size, T &t)
116 BOOST_ASSERT(m_size < m_capacity);
120 ::new((void*)&m_ptr[m_size]) T(::boost::move(t));
122 for(; m_size != size; ++m_size){
123 ::new((void*)&m_ptr[m_size]) T(::boost::move(m_ptr[m_size-1]));
125 t = ::boost::move(m_ptr[m_size-1]);
141 static bool is_raw_ptr(RIt)
146 static bool is_raw_ptr(T*)
153 bool supports_aligned_trailing(size_type size, size_type trail_count) const
155 if(this->is_raw_ptr(this->data()) && m_capacity){
156 uintptr_t u_addr_sz = uintptr_t(&*(this->data()+size));
157 uintptr_t u_addr_cp = uintptr_t(&*(this->data()+this->capacity()));
158 u_addr_sz = ((u_addr_sz + sizeof(U)-1)/sizeof(U))*sizeof(U);
159 return (u_addr_cp >= u_addr_sz) && ((u_addr_cp - u_addr_sz)/sizeof(U) >= trail_count);
165 U *aligned_trailing() const
167 return this->aligned_trailing<U>(this->size());
171 U *aligned_trailing(size_type pos) const
173 uintptr_t u_addr = uintptr_t(&*(this->data()+pos));
174 u_addr = ((u_addr + sizeof(U)-1)/sizeof(U))*sizeof(U);
183 size_type capacity() const
184 { return m_capacity; }
186 iterator data() const
189 iterator begin() const
193 { return m_ptr+m_size; }
195 size_type size() const
203 this->shrink_to_fit(0u);
209 size_type m_capacity;
212 template<class Iterator, class SizeType, class Op>
215 range_xbuf(const range_xbuf &);
216 range_xbuf & operator=(const range_xbuf &);
219 typedef SizeType size_type;
220 typedef Iterator iterator;
222 range_xbuf(Iterator first, Iterator last)
223 : m_first(first), m_last(first), m_cap(last)
226 template<class RandIt>
227 void move_assign(RandIt first, size_type n)
229 BOOST_ASSERT(size_type(n) <= size_type(m_cap-m_first));
230 m_last = Op()(forward_t(), first, first+n, m_first);
236 size_type capacity() const
237 { return m_cap-m_first; }
239 Iterator data() const
245 size_type size() const
246 { return m_last-m_first; }
249 { return m_first == m_last; }
256 template<class RandIt>
257 iterator add(RandIt it)
259 Iterator pos(m_last);
260 *pos = boost::move(*it);
265 void set_size(size_type size)
272 Iterator const m_first;
274 Iterator const m_cap;
282 template<typename Unsigned>
283 inline Unsigned gcd(Unsigned x, Unsigned y)
285 if(0 == ((x &(x-1)) | (y & (y-1)))){
286 return x < y ? x : y;
300 //Modified version from "An Optimal In-Place Array Rotation Algorithm", Ching-Kuang Shene
301 template<typename Unsigned>
302 Unsigned gcd(Unsigned x, Unsigned y)
304 if(0 == ((x &(x-1)) | (y & (y-1)))){
305 return x < y ? x : y;
309 while((!(x&1)) & (!(y&1))){
310 z <<=1, x>>=1, y>>=1;
326 template<typename RandIt>
327 RandIt rotate_gcd(RandIt first, RandIt middle, RandIt last)
329 typedef typename iterator_traits<RandIt>::size_type size_type;
330 typedef typename iterator_traits<RandIt>::value_type value_type;
336 const size_type middle_pos = size_type(middle - first);
337 RandIt ret = last - middle_pos;
339 boost::adl_move_swap_ranges(first, middle, middle);
342 const size_type length = size_type(last - first);
343 for( RandIt it_i(first), it_gcd(it_i + gcd(length, middle_pos))
346 value_type temp(boost::move(*it_i));
348 RandIt it_k = it_j+middle_pos;
350 *it_j = boost::move(*it_k);
352 size_type const left = size_type(last - it_j);
353 it_k = left > middle_pos ? it_j + middle_pos : first + (middle_pos - left);
354 } while(it_k != it_i);
355 *it_j = boost::move(temp);
361 template <class RandIt, class T, class Compare>
363 (RandIt first, const RandIt last, const T& key, Compare comp)
365 typedef typename iterator_traits
366 <RandIt>::size_type size_type;
367 size_type len = size_type(last - first);
371 size_type step = len >> 1;
375 if (comp(*middle, key)) {
386 template <class RandIt, class T, class Compare>
388 (RandIt first, const RandIt last, const T& key, Compare comp)
390 typedef typename iterator_traits
391 <RandIt>::size_type size_type;
392 size_type len = size_type(last - first);
396 size_type step = len >> 1;
400 if (!comp(key, *middle)) {
412 template<class RandIt, class Compare, class Op>
413 void op_merge_left( RandIt buf_first
420 for(RandIt first2=last1; first2 != last2; ++buf_first){
422 op(forward_t(), first2, last2, buf_first);
425 else if(comp(*first2, *first1)){
426 op(first2, buf_first);
430 op(first1, buf_first);
434 if(buf_first != first1){//In case all remaining elements are in the same place
435 //(e.g. buffer is exactly the size of the second half
436 //and all elements from the second half are less)
437 op(forward_t(), first1, last1, buf_first);
441 // [buf_first, first1) -> buffer
442 // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
443 // Elements from buffer are moved to [last2 - (first1-buf_first), last2)
444 // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
445 template<class RandIt, class Compare>
447 (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
449 op_merge_left(buf_first, first1, last1, last2, comp, move_op());
452 // [buf_first, first1) -> buffer
453 // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
454 // Elements from buffer are swapped to [last2 - (first1-buf_first), last2)
455 // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
456 template<class RandIt, class Compare>
458 (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
460 op_merge_left(buf_first, first1, last1, last2, comp, swap_op());
463 template<class RandIt, class Compare, class Op>
465 (RandIt const first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp, Op op)
467 RandIt const first2 = last1;
468 while(first1 != last1){
470 op(backward_t(), first1, last1, buf_last);
476 if(comp(*last2, *last1)){
485 if(last2 != buf_last){ //In case all remaining elements are in the same place
486 //(e.g. buffer is exactly the size of the first half
487 //and all elements from the second half are less)
488 op(backward_t(), first2, last2, buf_last);
492 // [last2, buf_last) - buffer
493 // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
494 // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
495 template<class RandIt, class Compare>
497 (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
499 op_merge_right(first1, last1, last2, buf_last, comp, move_op());
502 // [last2, buf_last) - buffer
503 // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
504 // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
505 template<class RandIt, class Compare>
506 void swap_merge_right
507 (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
509 op_merge_right(first1, last1, last2, buf_last, comp, swap_op());
512 ///////////////////////////////////////////////////////////////////////////////
516 ///////////////////////////////////////////////////////////////////////////////
517 template<class RandIt, class Compare, class Op, class Buf>
518 void op_buffered_merge
519 ( RandIt first, RandIt const middle, RandIt last
520 , Compare comp, Op op
523 if(first != middle && middle != last && comp(*middle, middle[-1])){
524 typedef typename iterator_traits<RandIt>::size_type size_type;
525 size_type const len1 = size_type(middle-first);
526 size_type const len2 = size_type(last-middle);
528 first = boost::movelib::upper_bound(first, middle, *middle, comp);
529 xbuf.move_assign(first, size_type(middle-first));
530 op_merge_with_right_placed
531 (xbuf.data(), xbuf.end(), first, middle, last, comp, op);
534 last = boost::movelib::lower_bound(middle, last, middle[-1], comp);
535 xbuf.move_assign(middle, size_type(last-middle));
536 op_merge_with_left_placed
537 (first, middle, last, xbuf.data(), xbuf.end(), comp, op);
542 template<class RandIt, class Compare, class XBuf>
544 ( RandIt first, RandIt const middle, RandIt last
548 op_buffered_merge(first, middle, last, comp, move_op(), xbuf);
551 //Complexity: min(len1,len2)^2 + max(len1,len2)
552 template<class RandIt, class Compare>
553 void merge_bufferless_ON2(RandIt first, RandIt middle, RandIt last, Compare comp)
555 if((middle - first) < (last - middle)){
556 while(first != middle){
557 RandIt const old_last1 = middle;
558 middle = boost::movelib::lower_bound(middle, last, *first, comp);
559 first = rotate_gcd(first, old_last1, middle);
565 } while(first != middle && !comp(*middle, *first));
569 while(middle != last){
570 RandIt p = boost::movelib::upper_bound(first, middle, last[-1], comp);
571 last = rotate_gcd(p, middle, last);
579 } while(middle != last && !comp(last[-1], *p));
584 static const std::size_t MergeBufferlessONLogNRotationThreshold = 16u;
586 template <class RandIt, class Compare>
587 void merge_bufferless_ONlogN_recursive
588 ( RandIt first, RandIt middle, RandIt last
589 , typename iterator_traits<RandIt>::size_type len1
590 , typename iterator_traits<RandIt>::size_type len2
593 typedef typename iterator_traits<RandIt>::size_type size_type;
603 else if (size_type(len1 | len2) == 1u) {
604 if (comp(*middle, *first))
605 adl_move_swap(*first, *middle);
608 else if(size_type(len1+len2) < MergeBufferlessONLogNRotationThreshold){
609 merge_bufferless_ON2(first, middle, last, comp);
613 RandIt first_cut = first;
614 RandIt second_cut = middle;
620 second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
621 len22 = size_type(second_cut - middle);
626 first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
627 len11 = size_type(first_cut - first);
629 RandIt new_middle = rotate_gcd(first_cut, middle, second_cut);
631 //Avoid one recursive call doing a manual tail call elimination on the biggest range
632 const size_type len_internal = len11+len22;
633 if( len_internal < (len1 + len2 - len_internal) ) {
634 merge_bufferless_ONlogN_recursive(first, first_cut, new_middle, len11, len22, comp);
641 merge_bufferless_ONlogN_recursive(new_middle, second_cut, last, len1 - len11, len2 - len22, comp);
652 template<class RandIt, class Compare>
653 void merge_bufferless_ONlogN(RandIt first, RandIt middle, RandIt last, Compare comp)
655 typedef typename iterator_traits<RandIt>::size_type size_type;
656 merge_bufferless_ONlogN_recursive
657 (first, middle, last, size_type(middle - first), size_type(last - middle), comp);
660 template<class RandIt, class Compare>
661 void merge_bufferless(RandIt first, RandIt middle, RandIt last, Compare comp)
663 #define BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
664 #ifdef BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
665 merge_bufferless_ONlogN(first, middle, last, comp);
667 merge_bufferless_ON2(first, middle, last, comp);
668 #endif //BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
671 // [r_first, r_last) are already in the right part of the destination range.
672 template <class Compare, class InputIterator, class InputOutIterator, class Op>
673 void op_merge_with_right_placed
674 ( InputIterator first, InputIterator last
675 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
676 , Compare comp, Op op)
678 BOOST_ASSERT((last - first) == (r_first - dest_first));
679 while ( first != last ) {
680 if (r_first == r_last) {
681 InputOutIterator end = op(forward_t(), first, last, dest_first);
682 BOOST_ASSERT(end == r_last);
686 else if (comp(*r_first, *first)) {
687 op(r_first, dest_first);
691 op(first, dest_first);
696 // Remaining [r_first, r_last) already in the correct place
699 template <class Compare, class InputIterator, class InputOutIterator>
700 void swap_merge_with_right_placed
701 ( InputIterator first, InputIterator last
702 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
705 op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, swap_op());
708 // [first, last) are already in the right part of the destination range.
709 template <class Compare, class Op, class BidirIterator, class BidirOutIterator>
710 void op_merge_with_left_placed
711 ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
712 , BidirIterator const r_first, BidirIterator r_last
713 , Compare comp, Op op)
715 BOOST_ASSERT((dest_last - last) == (r_last - r_first));
716 while( r_first != r_last ) {
718 BidirOutIterator res = op(backward_t(), r_first, r_last, dest_last);
719 BOOST_ASSERT(last == res);
725 if(comp(*r_last, *last)){
733 op(r_last, dest_last);
736 // Remaining [first, last) already in the correct place
741 // [first, last) are already in the right part of the destination range.
742 template <class Compare, class BidirIterator, class BidirOutIterator>
743 void merge_with_left_placed
744 ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
745 , BidirIterator const r_first, BidirIterator r_last
748 op_merge_with_left_placed(first, last, dest_last, r_first, r_last, comp, move_op());
751 // [r_first, r_last) are already in the right part of the destination range.
752 template <class Compare, class InputIterator, class InputOutIterator>
753 void merge_with_right_placed
754 ( InputIterator first, InputIterator last
755 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
758 op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, move_op());
761 // [r_first, r_last) are already in the right part of the destination range.
762 // [dest_first, r_first) is uninitialized memory
763 template <class Compare, class InputIterator, class InputOutIterator>
764 void uninitialized_merge_with_right_placed
765 ( InputIterator first, InputIterator last
766 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
769 BOOST_ASSERT((last - first) == (r_first - dest_first));
770 typedef typename iterator_traits<InputOutIterator>::value_type value_type;
771 InputOutIterator const original_r_first = r_first;
773 destruct_n<value_type, InputOutIterator> d(dest_first);
775 while ( first != last && dest_first != original_r_first ) {
776 if (r_first == r_last) {
777 for(; dest_first != original_r_first; ++dest_first, ++first){
778 ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
782 InputOutIterator end = ::boost::move(first, last, original_r_first);
783 BOOST_ASSERT(end == r_last);
787 else if (comp(*r_first, *first)) {
788 ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*r_first));
793 ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
800 merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp);
804 // [r_first, r_last) are already in the right part of the destination range.
805 // [dest_first, r_first) is uninitialized memory
806 template <class Compare, class BidirOutIterator, class BidirIterator>
807 void uninitialized_merge_with_left_placed
808 ( BidirOutIterator dest_first, BidirOutIterator r_first, BidirOutIterator r_last
809 , BidirIterator first, BidirIterator last
812 BOOST_ASSERT((last - first) == (r_last - r_first));
813 typedef typename iterator_traits<BidirOutIterator>::value_type value_type;
814 BidirOutIterator const original_r_last = r_last;
816 destruct_n<value_type> d(&*dest_last);
818 while ( first != last && dest_first != original_r_first ) {
819 if (r_first == r_last) {
820 for(; dest_first != original_r_first; ++dest_first, ++first){
821 ::new(&*dest_first) value_type(::boost::move(*first));
825 BidirOutIterator end = ::boost::move(first, last, original_r_first);
826 BOOST_ASSERT(end == r_last);
830 else if (comp(*r_first, *first)) {
831 ::new(&*dest_first) value_type(::boost::move(*r_first));
836 ::new(&*dest_first) value_type(::boost::move(*first));
843 merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp);
848 /// This is a helper function for the merge routines.
849 template<typename BidirectionalIterator1, typename BidirectionalIterator2>
850 BidirectionalIterator1
851 rotate_adaptive(BidirectionalIterator1 first,
852 BidirectionalIterator1 middle,
853 BidirectionalIterator1 last,
854 typename iterator_traits<BidirectionalIterator1>::size_type len1,
855 typename iterator_traits<BidirectionalIterator1>::size_type len2,
856 BidirectionalIterator2 buffer,
857 typename iterator_traits<BidirectionalIterator1>::size_type buffer_size)
859 if (len1 > len2 && len2 <= buffer_size)
861 if(len2) //Protect against self-move ranges
863 BidirectionalIterator2 buffer_end = boost::move(middle, last, buffer);
864 boost::move_backward(first, middle, last);
865 return boost::move(buffer, buffer_end, first);
870 else if (len1 <= buffer_size)
872 if(len1) //Protect against self-move ranges
874 BidirectionalIterator2 buffer_end = boost::move(first, middle, buffer);
875 BidirectionalIterator1 ret = boost::move(middle, last, first);
876 boost::move(buffer, buffer_end, ret);
883 return rotate_gcd(first, middle, last);
886 template<typename BidirectionalIterator,
887 typename Pointer, typename Compare>
888 void merge_adaptive_ONlogN_recursive
889 (BidirectionalIterator first,
890 BidirectionalIterator middle,
891 BidirectionalIterator last,
892 typename iterator_traits<BidirectionalIterator>::size_type len1,
893 typename iterator_traits<BidirectionalIterator>::size_type len2,
895 typename iterator_traits<BidirectionalIterator>::size_type buffer_size,
898 typedef typename iterator_traits<BidirectionalIterator>::size_type size_type;
900 if (!len2 || !len1) {
903 else if (len1 <= buffer_size || len2 <= buffer_size)
905 range_xbuf<Pointer, size_type, move_op> rxbuf(buffer, buffer + buffer_size);
906 buffered_merge(first, middle, last, comp, rxbuf);
908 else if (size_type(len1 + len2) == 2u) {
909 if (comp(*middle, *first))
910 adl_move_swap(*first, *middle);
913 else if (size_type(len1 + len2) < MergeBufferlessONLogNRotationThreshold) {
914 merge_bufferless_ON2(first, middle, last, comp);
917 BidirectionalIterator first_cut = first;
918 BidirectionalIterator second_cut = middle;
921 if (len1 > len2) //(len1 < len2)
925 second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
926 len22 = second_cut - middle;
932 first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
933 len11 = first_cut - first;
936 BidirectionalIterator new_middle
937 = rotate_adaptive(first_cut, middle, second_cut,
938 size_type(len1 - len11), len22, buffer,
940 merge_adaptive_ONlogN_recursive(first, first_cut, new_middle, len11,
941 len22, buffer, buffer_size, comp);
942 merge_adaptive_ONlogN_recursive(new_middle, second_cut, last,
943 len1 - len11, len2 - len22, buffer, buffer_size, comp);
947 template<typename BidirectionalIterator, typename Compare, typename RandRawIt>
948 void merge_adaptive_ONlogN(BidirectionalIterator first,
949 BidirectionalIterator middle,
950 BidirectionalIterator last,
952 RandRawIt uninitialized,
953 typename iterator_traits<BidirectionalIterator>::size_type uninitialized_len)
955 typedef typename iterator_traits<BidirectionalIterator>::value_type value_type;
956 typedef typename iterator_traits<BidirectionalIterator>::size_type size_type;
958 if (first == middle || middle == last)
961 if(uninitialized_len)
963 const size_type len1 = size_type(middle - first);
964 const size_type len2 = size_type(last - middle);
966 ::boost::movelib::adaptive_xbuf<value_type, RandRawIt> xbuf(uninitialized, uninitialized_len);
967 xbuf.initialize_until(uninitialized_len, *first);
968 merge_adaptive_ONlogN_recursive(first, middle, last, len1, len2, xbuf.begin(), uninitialized_len, comp);
972 merge_bufferless(first, middle, last, comp);
977 } //namespace movelib {
978 } //namespace boost {
980 #endif //#define BOOST_MOVE_MERGE_HPP