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>
29 template<typename Unsigned>
30 inline Unsigned gcd(Unsigned x, Unsigned y)
32 if(0 == ((x &(x-1)) | (y & (y-1)))){
47 //Modified version from "An Optimal In-Place Array Rotation Algorithm", Ching-Kuang Shene
48 template<typename Unsigned>
49 Unsigned gcd(Unsigned x, Unsigned y)
51 if(0 == ((x &(x-1)) | (y & (y-1)))){
56 while((!(x&1)) & (!(y&1))){
73 template<typename RandIt>
74 RandIt rotate_gcd(RandIt first, RandIt middle, RandIt last)
76 typedef typename iterator_traits<RandIt>::size_type size_type;
77 typedef typename iterator_traits<RandIt>::value_type value_type;
83 const size_type middle_pos = size_type(middle - first);
84 RandIt ret = last - middle_pos;
86 boost::adl_move_swap_ranges(first, middle, middle);
89 const size_type length = size_type(last - first);
90 for( RandIt it_i(first), it_gcd(it_i + gcd(length, middle_pos))
93 value_type temp(boost::move(*it_i));
95 RandIt it_k = it_j+middle_pos;
97 *it_j = boost::move(*it_k);
99 size_type const left = size_type(last - it_j);
100 it_k = left > middle_pos ? it_j + middle_pos : first + (middle_pos - left);
101 } while(it_k != it_i);
102 *it_j = boost::move(temp);
108 template <class RandIt, class T, class Compare>
110 (RandIt first, const RandIt last, const T& key, Compare comp)
112 typedef typename iterator_traits
113 <RandIt>::size_type size_type;
114 size_type len = size_type(last - first);
118 size_type step = len >> 1;
122 if (comp(*middle, key)) {
133 template <class RandIt, class T, class Compare>
135 (RandIt first, const RandIt last, const T& key, Compare comp)
137 typedef typename iterator_traits
138 <RandIt>::size_type size_type;
139 size_type len = size_type(last - first);
143 size_type step = len >> 1;
147 if (!comp(key, *middle)) {
159 template<class RandIt, class Compare, class Op>
160 void op_merge_left( RandIt buf_first
167 for(RandIt first2=last1; first2 != last2; ++buf_first){
169 op(forward_t(), first2, last2, buf_first);
172 else if(comp(*first2, *first1)){
173 op(first2, buf_first);
177 op(first1, buf_first);
181 if(buf_first != first1){//In case all remaining elements are in the same place
182 //(e.g. buffer is exactly the size of the second half
183 //and all elements from the second half are less)
184 op(forward_t(), first1, last1, buf_first);
188 // [buf_first, first1) -> buffer
189 // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
190 // Elements from buffer are moved to [last2 - (first1-buf_first), last2)
191 // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
192 template<class RandIt, class Compare>
194 (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
196 op_merge_left(buf_first, first1, last1, last2, comp, move_op());
199 // [buf_first, first1) -> buffer
200 // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
201 // Elements from buffer are swapped to [last2 - (first1-buf_first), last2)
202 // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
203 template<class RandIt, class Compare>
205 (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
207 op_merge_left(buf_first, first1, last1, last2, comp, swap_op());
210 template<class RandIt, class Compare, class Op>
212 (RandIt const first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp, Op op)
214 RandIt const first2 = last1;
215 while(first1 != last1){
217 op(backward_t(), first1, last1, buf_last);
223 if(comp(*last2, *last1)){
232 if(last2 != buf_last){ //In case all remaining elements are in the same place
233 //(e.g. buffer is exactly the size of the first half
234 //and all elements from the second half are less)
235 op(backward_t(), first2, last2, buf_last);
239 // [last2, buf_last) - buffer
240 // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
241 // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
242 template<class RandIt, class Compare>
244 (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
246 op_merge_right(first1, last1, last2, buf_last, comp, move_op());
249 // [last2, buf_last) - buffer
250 // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
251 // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
252 template<class RandIt, class Compare>
253 void swap_merge_right
254 (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
256 op_merge_right(first1, last1, last2, buf_last, comp, swap_op());
259 template <class BidirIt, class Distance, class Compare>
260 void merge_bufferless_ONlogN_recursive
261 (BidirIt first, BidirIt middle, BidirIt last, Distance len1, Distance len2, Compare comp)
263 typedef typename iterator_traits<BidirIt>::size_type size_type;
265 //#define MERGE_BUFFERLESS_RECURSIVE_OPT
266 #ifndef MERGE_BUFFERLESS_RECURSIVE_OPT
275 if ((len1 | len2) == 1) {
276 if (comp(*middle, *first))
277 adl_move_swap(*first, *middle);
288 BidirIt middle_prev = middle; --middle_prev;
289 if(!comp(*middle, *middle_prev))
293 if (comp(*middle, *first))
300 if (len1 == 1 && len2 == 1) {
301 //comp(*middle, *first) == true already tested in the loop
302 adl_move_swap(*first, *middle);
307 BidirIt first_cut = first;
308 BidirIt second_cut = middle;
314 second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
315 len22 = size_type(second_cut - middle);
320 first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
321 len11 = size_type(first_cut - first);
323 BidirIt new_middle = rotate_gcd(first_cut, middle, second_cut);
325 //Avoid one recursive call doing a manual tail call elimination on the biggest range
326 const Distance len_internal = len11+len22;
327 if( len_internal < (len1 + len2 - len_internal) ) {
328 merge_bufferless_ONlogN_recursive(first, first_cut, new_middle, len11, len22, comp);
329 //merge_bufferless_recursive(new_middle, second_cut, last, len1 - len11, len2 - len22, comp);
336 //merge_bufferless_recursive(first, first_cut, new_middle, len11, len22, comp);
337 merge_bufferless_ONlogN_recursive(new_middle, second_cut, last, len1 - len11, len2 - len22, comp);
347 template<class BidirIt, class Compare>
348 void merge_bufferless_ONlogN(BidirIt first, BidirIt middle, BidirIt last, Compare comp)
350 merge_bufferless_ONlogN_recursive
351 (first, middle, last, middle - first, last - middle, comp);
354 //Complexity: min(len1,len2)^2 + max(len1,len2)
355 template<class RandIt, class Compare>
356 void merge_bufferless_ON2(RandIt first, RandIt middle, RandIt last, Compare comp)
358 if((middle - first) < (last - middle)){
359 while(first != middle){
360 RandIt const old_last1 = middle;
361 middle = boost::movelib::lower_bound(middle, last, *first, comp);
362 first = rotate_gcd(first, old_last1, middle);
368 } while(first != middle && !comp(*middle, *first));
372 while(middle != last){
373 RandIt p = boost::movelib::upper_bound(first, middle, last[-1], comp);
374 last = rotate_gcd(p, middle, last);
382 } while(middle != last && !comp(last[-1], *p));
387 template<class RandIt, class Compare>
388 void merge_bufferless(RandIt first, RandIt middle, RandIt last, Compare comp)
390 //#define BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
391 #ifdef BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
392 merge_bufferless_ONlogN(first, middle, last, comp);
394 merge_bufferless_ON2(first, middle, last, comp);
395 #endif //BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
398 // [r_first, r_last) are already in the right part of the destination range.
399 template <class Compare, class InputIterator, class InputOutIterator, class Op>
400 void op_merge_with_right_placed
401 ( InputIterator first, InputIterator last
402 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
403 , Compare comp, Op op)
405 BOOST_ASSERT((last - first) == (r_first - dest_first));
406 while ( first != last ) {
407 if (r_first == r_last) {
408 InputOutIterator end = op(forward_t(), first, last, dest_first);
409 BOOST_ASSERT(end == r_last);
413 else if (comp(*r_first, *first)) {
414 op(r_first, dest_first);
418 op(first, dest_first);
423 // Remaining [r_first, r_last) already in the correct place
426 template <class Compare, class InputIterator, class InputOutIterator>
427 void swap_merge_with_right_placed
428 ( InputIterator first, InputIterator last
429 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
432 op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, swap_op());
435 // [first, last) are already in the right part of the destination range.
436 template <class Compare, class Op, class BidirIterator, class BidirOutIterator>
437 void op_merge_with_left_placed
438 ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
439 , BidirIterator const r_first, BidirIterator r_last
440 , Compare comp, Op op)
442 BOOST_ASSERT((dest_last - last) == (r_last - r_first));
443 while( r_first != r_last ) {
445 BidirOutIterator res = op(backward_t(), r_first, r_last, dest_last);
446 BOOST_ASSERT(last == res);
452 if(comp(*r_last, *last)){
460 op(r_last, dest_last);
463 // Remaining [first, last) already in the correct place
468 // [irst, last) are already in the right part of the destination range.
469 template <class Compare, class BidirIterator, class BidirOutIterator>
470 void merge_with_left_placed
471 ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
472 , BidirIterator const r_first, BidirIterator r_last
475 op_merge_with_left_placed(first, last, dest_last, r_first, r_last, comp, move_op());
478 // [r_first, r_last) are already in the right part of the destination range.
479 template <class Compare, class InputIterator, class InputOutIterator>
480 void merge_with_right_placed
481 ( InputIterator first, InputIterator last
482 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
485 op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, move_op());
488 // [r_first, r_last) are already in the right part of the destination range.
489 // [dest_first, r_first) is uninitialized memory
490 template <class Compare, class InputIterator, class InputOutIterator>
491 void uninitialized_merge_with_right_placed
492 ( InputIterator first, InputIterator last
493 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
496 BOOST_ASSERT((last - first) == (r_first - dest_first));
497 typedef typename iterator_traits<InputOutIterator>::value_type value_type;
498 InputOutIterator const original_r_first = r_first;
500 destruct_n<value_type, InputOutIterator> d(dest_first);
502 while ( first != last && dest_first != original_r_first ) {
503 if (r_first == r_last) {
504 for(; dest_first != original_r_first; ++dest_first, ++first){
505 ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
509 InputOutIterator end = ::boost::move(first, last, original_r_first);
510 BOOST_ASSERT(end == r_last);
514 else if (comp(*r_first, *first)) {
515 ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*r_first));
520 ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
527 merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp);
531 // [r_first, r_last) are already in the right part of the destination range.
532 // [dest_first, r_first) is uninitialized memory
533 template <class Compare, class BidirOutIterator, class BidirIterator>
534 void uninitialized_merge_with_left_placed
535 ( BidirOutIterator dest_first, BidirOutIterator r_first, BidirOutIterator r_last
536 , BidirIterator first, BidirIterator last
539 BOOST_ASSERT((last - first) == (r_last - r_first));
540 typedef typename iterator_traits<BidirOutIterator>::value_type value_type;
541 BidirOutIterator const original_r_last = r_last;
543 destruct_n<value_type> d(&*dest_last);
545 while ( first != last && dest_first != original_r_first ) {
546 if (r_first == r_last) {
547 for(; dest_first != original_r_first; ++dest_first, ++first){
548 ::new(&*dest_first) value_type(::boost::move(*first));
552 BidirOutIterator end = ::boost::move(first, last, original_r_first);
553 BOOST_ASSERT(end == r_last);
557 else if (comp(*r_first, *first)) {
558 ::new(&*dest_first) value_type(::boost::move(*r_first));
563 ::new(&*dest_first) value_type(::boost::move(*first));
570 merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp);
574 } //namespace movelib {
575 } //namespace boost {
577 #endif //#define BOOST_MOVE_MERGE_HPP