| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // (C) Copyright Ion Gaztanaga 2015-2016. |
| // Distributed under the Boost Software License, Version 1.0. |
| // (See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| // |
| // See http://www.boost.org/libs/move for documentation. |
| // |
| ////////////////////////////////////////////////////////////////////////////// |
| #ifndef BOOST_MOVE_MERGE_HPP |
| #define BOOST_MOVE_MERGE_HPP |
| |
| #include <boost/move/algo/move.hpp> |
| #include <boost/move/adl_move_swap.hpp> |
| #include <boost/move/algo/detail/basic_op.hpp> |
| #include <boost/move/detail/iterator_traits.hpp> |
| #include <boost/move/detail/destruct_n.hpp> |
| #include <boost/move/algo/predicate.hpp> |
| #include <boost/move/detail/iterator_to_raw_pointer.hpp> |
| #include <boost/assert.hpp> |
| |
| namespace boost { |
| namespace movelib { |
| |
| // @cond |
| |
| /* |
| template<typename Unsigned> |
| inline Unsigned gcd(Unsigned x, Unsigned y) |
| { |
| if(0 == ((x &(x-1)) | (y & (y-1)))){ |
| return x < y ? x : y; |
| } |
| else{ |
| do |
| { |
| Unsigned t = x % y; |
| x = y; |
| y = t; |
| } while (y); |
| return x; |
| } |
| } |
| */ |
| |
| //Modified version from "An Optimal In-Place Array Rotation Algorithm", Ching-Kuang Shene |
| template<typename Unsigned> |
| Unsigned gcd(Unsigned x, Unsigned y) |
| { |
| if(0 == ((x &(x-1)) | (y & (y-1)))){ |
| return x < y ? x : y; |
| } |
| else{ |
| Unsigned z = 1; |
| while((!(x&1)) & (!(y&1))){ |
| z <<=1, x>>=1, y>>=1; |
| } |
| while(x && y){ |
| if(!(x&1)) |
| x >>=1; |
| else if(!(y&1)) |
| y >>=1; |
| else if(x >=y) |
| x = (x-y) >> 1; |
| else |
| y = (y-x) >> 1; |
| } |
| return z*(x+y); |
| } |
| } |
| |
| template<typename RandIt> |
| RandIt rotate_gcd(RandIt first, RandIt middle, RandIt last) |
| { |
| typedef typename iterator_traits<RandIt>::size_type size_type; |
| typedef typename iterator_traits<RandIt>::value_type value_type; |
| |
| if(first == middle) |
| return last; |
| if(middle == last) |
| return first; |
| const size_type middle_pos = size_type(middle - first); |
| RandIt ret = last - middle_pos; |
| if (middle == ret){ |
| boost::adl_move_swap_ranges(first, middle, middle); |
| } |
| else{ |
| const size_type length = size_type(last - first); |
| for( RandIt it_i(first), it_gcd(it_i + gcd(length, middle_pos)) |
| ; it_i != it_gcd |
| ; ++it_i){ |
| value_type temp(boost::move(*it_i)); |
| RandIt it_j = it_i; |
| RandIt it_k = it_j+middle_pos; |
| do{ |
| *it_j = boost::move(*it_k); |
| it_j = it_k; |
| size_type const left = size_type(last - it_j); |
| it_k = left > middle_pos ? it_j + middle_pos : first + (middle_pos - left); |
| } while(it_k != it_i); |
| *it_j = boost::move(temp); |
| } |
| } |
| return ret; |
| } |
| |
| template <class RandIt, class T, class Compare> |
| RandIt lower_bound |
| (RandIt first, const RandIt last, const T& key, Compare comp) |
| { |
| typedef typename iterator_traits |
| <RandIt>::size_type size_type; |
| size_type len = size_type(last - first); |
| RandIt middle; |
| |
| while (len) { |
| size_type step = len >> 1; |
| middle = first; |
| middle += step; |
| |
| if (comp(*middle, key)) { |
| first = ++middle; |
| len -= step + 1; |
| } |
| else{ |
| len = step; |
| } |
| } |
| return first; |
| } |
| |
| template <class RandIt, class T, class Compare> |
| RandIt upper_bound |
| (RandIt first, const RandIt last, const T& key, Compare comp) |
| { |
| typedef typename iterator_traits |
| <RandIt>::size_type size_type; |
| size_type len = size_type(last - first); |
| RandIt middle; |
| |
| while (len) { |
| size_type step = len >> 1; |
| middle = first; |
| middle += step; |
| |
| if (!comp(key, *middle)) { |
| first = ++middle; |
| len -= step + 1; |
| } |
| else{ |
| len = step; |
| } |
| } |
| return first; |
| } |
| |
| |
| template<class RandIt, class Compare, class Op> |
| void op_merge_left( RandIt buf_first |
| , RandIt first1 |
| , RandIt const last1 |
| , RandIt const last2 |
| , Compare comp |
| , Op op) |
| { |
| for(RandIt first2=last1; first2 != last2; ++buf_first){ |
| if(first1 == last1){ |
| op(forward_t(), first2, last2, buf_first); |
| return; |
| } |
| else if(comp(*first2, *first1)){ |
| op(first2, buf_first); |
| ++first2; |
| } |
| else{ |
| op(first1, buf_first); |
| ++first1; |
| } |
| } |
| if(buf_first != first1){//In case all remaining elements are in the same place |
| //(e.g. buffer is exactly the size of the second half |
| //and all elements from the second half are less) |
| op(forward_t(), first1, last1, buf_first); |
| } |
| } |
| |
| // [buf_first, first1) -> buffer |
| // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1)) |
| // Elements from buffer are moved to [last2 - (first1-buf_first), last2) |
| // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs |
| template<class RandIt, class Compare> |
| void merge_left |
| (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp) |
| { |
| op_merge_left(buf_first, first1, last1, last2, comp, move_op()); |
| } |
| |
| // [buf_first, first1) -> buffer |
| // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1)) |
| // Elements from buffer are swapped to [last2 - (first1-buf_first), last2) |
| // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs |
| template<class RandIt, class Compare> |
| void swap_merge_left |
| (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp) |
| { |
| op_merge_left(buf_first, first1, last1, last2, comp, swap_op()); |
| } |
| |
| template<class RandIt, class Compare, class Op> |
| void op_merge_right |
| (RandIt const first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp, Op op) |
| { |
| RandIt const first2 = last1; |
| while(first1 != last1){ |
| if(last2 == first2){ |
| op(backward_t(), first1, last1, buf_last); |
| return; |
| } |
| --last2; |
| --last1; |
| --buf_last; |
| if(comp(*last2, *last1)){ |
| op(last1, buf_last); |
| ++last2; |
| } |
| else{ |
| op(last2, buf_last); |
| ++last1; |
| } |
| } |
| if(last2 != buf_last){ //In case all remaining elements are in the same place |
| //(e.g. buffer is exactly the size of the first half |
| //and all elements from the second half are less) |
| op(backward_t(), first2, last2, buf_last); |
| } |
| } |
| |
| // [last2, buf_last) - buffer |
| // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last) |
| // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs |
| template<class RandIt, class Compare> |
| void merge_right |
| (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp) |
| { |
| op_merge_right(first1, last1, last2, buf_last, comp, move_op()); |
| } |
| |
| // [last2, buf_last) - buffer |
| // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last) |
| // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs |
| template<class RandIt, class Compare> |
| void swap_merge_right |
| (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp) |
| { |
| op_merge_right(first1, last1, last2, buf_last, comp, swap_op()); |
| } |
| |
| //Complexity: min(len1,len2)^2 + max(len1,len2) |
| template<class RandIt, class Compare> |
| void merge_bufferless_ON2(RandIt first, RandIt middle, RandIt last, Compare comp) |
| { |
| if((middle - first) < (last - middle)){ |
| while(first != middle){ |
| RandIt const old_last1 = middle; |
| middle = boost::movelib::lower_bound(middle, last, *first, comp); |
| first = rotate_gcd(first, old_last1, middle); |
| if(middle == last){ |
| break; |
| } |
| do{ |
| ++first; |
| } while(first != middle && !comp(*middle, *first)); |
| } |
| } |
| else{ |
| while(middle != last){ |
| RandIt p = boost::movelib::upper_bound(first, middle, last[-1], comp); |
| last = rotate_gcd(p, middle, last); |
| middle = p; |
| if(middle == first){ |
| break; |
| } |
| --p; |
| do{ |
| --last; |
| } while(middle != last && !comp(last[-1], *p)); |
| } |
| } |
| } |
| |
| static const std::size_t MergeBufferlessONLogNRotationThreshold = 32; |
| |
| template <class RandIt, class Distance, class Compare> |
| void merge_bufferless_ONlogN_recursive |
| (RandIt first, RandIt middle, RandIt last, Distance len1, Distance len2, Compare comp) |
| { |
| typedef typename iterator_traits<RandIt>::size_type size_type; |
| |
| while(1) { |
| //trivial cases |
| if (!len2) { |
| return; |
| } |
| else if (!len1) { |
| return; |
| } |
| else if (size_type(len1 | len2) == 1u) { |
| if (comp(*middle, *first)) |
| adl_move_swap(*first, *middle); |
| return; |
| } |
| else if(size_type(len1+len2) < MergeBufferlessONLogNRotationThreshold){ |
| merge_bufferless_ON2(first, middle, last, comp); |
| return; |
| } |
| |
| RandIt first_cut = first; |
| RandIt second_cut = middle; |
| Distance len11 = 0; |
| Distance len22 = 0; |
| if (len1 > len2) { |
| len11 = len1 / 2; |
| first_cut += len11; |
| second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp); |
| len22 = size_type(second_cut - middle); |
| } |
| else { |
| len22 = len2 / 2; |
| second_cut += len22; |
| first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp); |
| len11 = size_type(first_cut - first); |
| } |
| RandIt new_middle = rotate_gcd(first_cut, middle, second_cut); |
| |
| //Avoid one recursive call doing a manual tail call elimination on the biggest range |
| const Distance len_internal = len11+len22; |
| if( len_internal < (len1 + len2 - len_internal) ) { |
| merge_bufferless_ONlogN_recursive(first, first_cut, new_middle, len11, len22, comp); |
| first = new_middle; |
| middle = second_cut; |
| len1 -= len11; |
| len2 -= len22; |
| } |
| else { |
| merge_bufferless_ONlogN_recursive(new_middle, second_cut, last, len1 - len11, len2 - len22, comp); |
| middle = first_cut; |
| last = new_middle; |
| len1 = len11; |
| len2 = len22; |
| } |
| } |
| } |
| |
| //Complexity: NlogN |
| template<class RandIt, class Compare> |
| void merge_bufferless_ONlogN(RandIt first, RandIt middle, RandIt last, Compare comp) |
| { |
| merge_bufferless_ONlogN_recursive |
| (first, middle, last, middle - first, last - middle, comp); |
| } |
| |
| template<class RandIt, class Compare> |
| void merge_bufferless(RandIt first, RandIt middle, RandIt last, Compare comp) |
| { |
| #define BOOST_ADAPTIVE_MERGE_NLOGN_MERGE |
| #ifdef BOOST_ADAPTIVE_MERGE_NLOGN_MERGE |
| merge_bufferless_ONlogN(first, middle, last, comp); |
| #else |
| merge_bufferless_ON2(first, middle, last, comp); |
| #endif //BOOST_ADAPTIVE_MERGE_NLOGN_MERGE |
| } |
| |
| // [r_first, r_last) are already in the right part of the destination range. |
| template <class Compare, class InputIterator, class InputOutIterator, class Op> |
| void op_merge_with_right_placed |
| ( InputIterator first, InputIterator last |
| , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last |
| , Compare comp, Op op) |
| { |
| BOOST_ASSERT((last - first) == (r_first - dest_first)); |
| while ( first != last ) { |
| if (r_first == r_last) { |
| InputOutIterator end = op(forward_t(), first, last, dest_first); |
| BOOST_ASSERT(end == r_last); |
| (void)end; |
| return; |
| } |
| else if (comp(*r_first, *first)) { |
| op(r_first, dest_first); |
| ++r_first; |
| } |
| else { |
| op(first, dest_first); |
| ++first; |
| } |
| ++dest_first; |
| } |
| // Remaining [r_first, r_last) already in the correct place |
| } |
| |
| template <class Compare, class InputIterator, class InputOutIterator> |
| void swap_merge_with_right_placed |
| ( InputIterator first, InputIterator last |
| , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last |
| , Compare comp) |
| { |
| op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, swap_op()); |
| } |
| |
| // [first, last) are already in the right part of the destination range. |
| template <class Compare, class Op, class BidirIterator, class BidirOutIterator> |
| void op_merge_with_left_placed |
| ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last |
| , BidirIterator const r_first, BidirIterator r_last |
| , Compare comp, Op op) |
| { |
| BOOST_ASSERT((dest_last - last) == (r_last - r_first)); |
| while( r_first != r_last ) { |
| if(first == last) { |
| BidirOutIterator res = op(backward_t(), r_first, r_last, dest_last); |
| BOOST_ASSERT(last == res); |
| (void)res; |
| return; |
| } |
| --r_last; |
| --last; |
| if(comp(*r_last, *last)){ |
| ++r_last; |
| --dest_last; |
| op(last, dest_last); |
| } |
| else{ |
| ++last; |
| --dest_last; |
| op(r_last, dest_last); |
| } |
| } |
| // Remaining [first, last) already in the correct place |
| } |
| |
| // @endcond |
| |
| // [irst, last) are already in the right part of the destination range. |
| template <class Compare, class BidirIterator, class BidirOutIterator> |
| void merge_with_left_placed |
| ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last |
| , BidirIterator const r_first, BidirIterator r_last |
| , Compare comp) |
| { |
| op_merge_with_left_placed(first, last, dest_last, r_first, r_last, comp, move_op()); |
| } |
| |
| // [r_first, r_last) are already in the right part of the destination range. |
| template <class Compare, class InputIterator, class InputOutIterator> |
| void merge_with_right_placed |
| ( InputIterator first, InputIterator last |
| , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last |
| , Compare comp) |
| { |
| op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, move_op()); |
| } |
| |
| // [r_first, r_last) are already in the right part of the destination range. |
| // [dest_first, r_first) is uninitialized memory |
| template <class Compare, class InputIterator, class InputOutIterator> |
| void uninitialized_merge_with_right_placed |
| ( InputIterator first, InputIterator last |
| , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last |
| , Compare comp) |
| { |
| BOOST_ASSERT((last - first) == (r_first - dest_first)); |
| typedef typename iterator_traits<InputOutIterator>::value_type value_type; |
| InputOutIterator const original_r_first = r_first; |
| |
| destruct_n<value_type, InputOutIterator> d(dest_first); |
| |
| while ( first != last && dest_first != original_r_first ) { |
| if (r_first == r_last) { |
| for(; dest_first != original_r_first; ++dest_first, ++first){ |
| ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first)); |
| d.incr(); |
| } |
| d.release(); |
| InputOutIterator end = ::boost::move(first, last, original_r_first); |
| BOOST_ASSERT(end == r_last); |
| (void)end; |
| return; |
| } |
| else if (comp(*r_first, *first)) { |
| ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*r_first)); |
| d.incr(); |
| ++r_first; |
| } |
| else { |
| ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first)); |
| d.incr(); |
| ++first; |
| } |
| ++dest_first; |
| } |
| d.release(); |
| merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp); |
| } |
| |
| /* |
| // [r_first, r_last) are already in the right part of the destination range. |
| // [dest_first, r_first) is uninitialized memory |
| template <class Compare, class BidirOutIterator, class BidirIterator> |
| void uninitialized_merge_with_left_placed |
| ( BidirOutIterator dest_first, BidirOutIterator r_first, BidirOutIterator r_last |
| , BidirIterator first, BidirIterator last |
| , Compare comp) |
| { |
| BOOST_ASSERT((last - first) == (r_last - r_first)); |
| typedef typename iterator_traits<BidirOutIterator>::value_type value_type; |
| BidirOutIterator const original_r_last = r_last; |
| |
| destruct_n<value_type> d(&*dest_last); |
| |
| while ( first != last && dest_first != original_r_first ) { |
| if (r_first == r_last) { |
| for(; dest_first != original_r_first; ++dest_first, ++first){ |
| ::new(&*dest_first) value_type(::boost::move(*first)); |
| d.incr(); |
| } |
| d.release(); |
| BidirOutIterator end = ::boost::move(first, last, original_r_first); |
| BOOST_ASSERT(end == r_last); |
| (void)end; |
| return; |
| } |
| else if (comp(*r_first, *first)) { |
| ::new(&*dest_first) value_type(::boost::move(*r_first)); |
| d.incr(); |
| ++r_first; |
| } |
| else { |
| ::new(&*dest_first) value_type(::boost::move(*first)); |
| d.incr(); |
| ++first; |
| } |
| ++dest_first; |
| } |
| d.release(); |
| merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp); |
| } |
| */ |
| |
| } //namespace movelib { |
| } //namespace boost { |
| |
| #endif //#define BOOST_MOVE_MERGE_HPP |