1 //////////////////////////////////////////////////////////////////////////////
2 //
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)
7 //
8 // See http://www.boost.org/libs/move for documentation.
9 //
10 //////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_MOVE_MERGE_HPP
12 #define BOOST_MOVE_MERGE_HPP
13 
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>
22 
23 namespace boost {
24 namespace movelib {
25 
26 // @cond
27 
28 /*
29 template<typename Unsigned>
30 inline Unsigned gcd(Unsigned x, Unsigned y)
31 {
32    if(0 == ((x &(x-1)) | (y & (y-1)))){
33       return x < y ? x : y;
34    }
35    else{
36       do
37       {
38          Unsigned t = x % y;
39          x = y;
40          y = t;
41       } while (y);
42       return x;
43    }
44 }
45 */
46 
47 //Modified version from "An Optimal In-Place Array Rotation Algorithm", Ching-Kuang Shene
48 template<typename Unsigned>
gcd(Unsigned x,Unsigned y)49 Unsigned gcd(Unsigned x, Unsigned y)
50 {
51    if(0 == ((x &(x-1)) | (y & (y-1)))){
52       return x < y ? x : y;
53    }
54    else{
55       Unsigned z = 1;
56       while((!(x&1)) & (!(y&1))){
57          z <<=1, x>>=1, y>>=1;
58       }
59       while(x && y){
60          if(!(x&1))
61             x >>=1;
62          else if(!(y&1))
63             y >>=1;
64          else if(x >=y)
65             x = (x-y) >> 1;
66          else
67             y = (y-x) >> 1;
68       }
69       return z*(x+y);
70    }
71 }
72 
73 template<typename RandIt>
rotate_gcd(RandIt first,RandIt middle,RandIt last)74 RandIt rotate_gcd(RandIt first, RandIt middle, RandIt last)
75 {
76    typedef typename iterator_traits<RandIt>::size_type size_type;
77    typedef typename iterator_traits<RandIt>::value_type value_type;
78 
79    if(first == middle)
80       return last;
81    if(middle == last)
82       return first;
83    const size_type middle_pos = size_type(middle - first);
84    RandIt ret = last - middle_pos;
85    if (middle == ret){
86       boost::adl_move_swap_ranges(first, middle, middle);
87    }
88    else{
89       const size_type length = size_type(last - first);
90       for( RandIt it_i(first), it_gcd(it_i + gcd(length, middle_pos))
91          ; it_i != it_gcd
92          ; ++it_i){
93          value_type temp(boost::move(*it_i));
94          RandIt it_j = it_i;
95          RandIt it_k = it_j+middle_pos;
96          do{
97             *it_j = boost::move(*it_k);
98             it_j = 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);
103       }
104    }
105    return ret;
106 }
107 
108 template <class RandIt, class T, class Compare>
lower_bound(RandIt first,const RandIt last,const T & key,Compare comp)109 RandIt lower_bound
110    (RandIt first, const RandIt last, const T& key, Compare comp)
111 {
112    typedef typename iterator_traits
113       <RandIt>::size_type size_type;
114    size_type len = size_type(last - first);
115    RandIt middle;
116 
117    while (len) {
118       size_type step = len >> 1;
119       middle = first;
120       middle += step;
121 
122       if (comp(*middle, key)) {
123          first = ++middle;
124          len -= step + 1;
125       }
126       else{
127          len = step;
128       }
129    }
130    return first;
131 }
132 
133 template <class RandIt, class T, class Compare>
upper_bound(RandIt first,const RandIt last,const T & key,Compare comp)134 RandIt upper_bound
135    (RandIt first, const RandIt last, const T& key, Compare comp)
136 {
137    typedef typename iterator_traits
138       <RandIt>::size_type size_type;
139    size_type len = size_type(last - first);
140    RandIt middle;
141 
142    while (len) {
143       size_type step = len >> 1;
144       middle = first;
145       middle += step;
146 
147       if (!comp(key, *middle)) {
148          first = ++middle;
149          len -= step + 1;
150       }
151       else{
152          len = step;
153       }
154    }
155    return first;
156 }
157 
158 
159 template<class RandIt, class Compare, class Op>
op_merge_left(RandIt buf_first,RandIt first1,RandIt const last1,RandIt const last2,Compare comp,Op op)160 void op_merge_left( RandIt buf_first
161                     , RandIt first1
162                     , RandIt const last1
163                     , RandIt const last2
164                     , Compare comp
165                     , Op op)
166 {
167    for(RandIt first2=last1; first2 != last2; ++buf_first){
168       if(first1 == last1){
169          op(forward_t(), first2, last2, buf_first);
170          return;
171       }
172       else if(comp(*first2, *first1)){
173          op(first2, buf_first);
174          ++first2;
175       }
176       else{
177          op(first1, buf_first);
178          ++first1;
179       }
180    }
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);
185    }
186 }
187 
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>
merge_left(RandIt buf_first,RandIt first1,RandIt const last1,RandIt const last2,Compare comp)193 void merge_left
194    (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
195 {
196    op_merge_left(buf_first, first1, last1, last2, comp, move_op());
197 }
198 
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>
swap_merge_left(RandIt buf_first,RandIt first1,RandIt const last1,RandIt const last2,Compare comp)204 void swap_merge_left
205    (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
206 {
207    op_merge_left(buf_first, first1, last1, last2, comp, swap_op());
208 }
209 
210 template<class RandIt, class Compare, class Op>
op_merge_right(RandIt const first1,RandIt last1,RandIt last2,RandIt buf_last,Compare comp,Op op)211 void op_merge_right
212    (RandIt const first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp, Op op)
213 {
214    RandIt const first2 = last1;
215    while(first1 != last1){
216       if(last2 == first2){
217          op(backward_t(), first1, last1, buf_last);
218          return;
219       }
220       --last2;
221       --last1;
222       --buf_last;
223       if(comp(*last2, *last1)){
224          op(last1, buf_last);
225          ++last2;
226       }
227       else{
228          op(last2, buf_last);
229          ++last1;
230       }
231    }
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);
236    }
237 }
238 
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>
merge_right(RandIt first1,RandIt last1,RandIt last2,RandIt buf_last,Compare comp)243 void merge_right
244    (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
245 {
246    op_merge_right(first1, last1, last2, buf_last, comp, move_op());
247 }
248 
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>
swap_merge_right(RandIt first1,RandIt last1,RandIt last2,RandIt buf_last,Compare comp)253 void swap_merge_right
254    (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
255 {
256    op_merge_right(first1, last1, last2, buf_last, comp, swap_op());
257 }
258 
259 template <class BidirIt, class Distance, class Compare>
merge_bufferless_ONlogN_recursive(BidirIt first,BidirIt middle,BidirIt last,Distance len1,Distance len2,Compare comp)260 void merge_bufferless_ONlogN_recursive
261    (BidirIt first, BidirIt middle, BidirIt last, Distance len1, Distance len2, Compare comp)
262 {
263    typedef typename iterator_traits<BidirIt>::size_type size_type;
264    while(1) {
265       //#define MERGE_BUFFERLESS_RECURSIVE_OPT
266       #ifndef MERGE_BUFFERLESS_RECURSIVE_OPT
267       if (len2  == 0) {
268          return;
269       }
270 
271       if (!len1) {
272          return;
273       }
274 
275       if ((len1 | len2) == 1) {
276          if (comp(*middle, *first))
277             adl_move_swap(*first, *middle);
278          return;
279       }
280       #else
281       if (len2  == 0) {
282          return;
283       }
284 
285       if (!len1) {
286          return;
287       }
288       BidirIt middle_prev = middle; --middle_prev;
289       if(!comp(*middle, *middle_prev))
290          return;
291 
292       while(true) {
293          if (comp(*middle, *first))
294             break;
295          ++first;
296          if(--len1 == 1)
297             break;
298       }
299 
300       if (len1 == 1 && len2 == 1) {
301          //comp(*middle, *first) == true already tested in the loop
302          adl_move_swap(*first, *middle);
303          return;
304       }
305       #endif
306 
307       BidirIt first_cut = first;
308       BidirIt second_cut = middle;
309       Distance len11 = 0;
310       Distance len22 = 0;
311       if (len1 > len2) {
312          len11 = len1 / 2;
313          first_cut +=  len11;
314          second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
315          len22 = size_type(second_cut - middle);
316       }
317       else {
318          len22 = len2 / 2;
319          second_cut += len22;
320          first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
321          len11 = size_type(first_cut - first);
322       }
323       BidirIt new_middle = rotate_gcd(first_cut, middle, second_cut);
324 
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);
330          first = new_middle;
331          middle = second_cut;
332          len1 -= len11;
333          len2 -= len22;
334       }
335       else {
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);
338          middle = first_cut;
339          last = new_middle;
340          len1 = len11;
341          len2 = len22;
342       }
343    }
344 }
345 
346 //Complexity: NlogN
347 template<class BidirIt, class Compare>
merge_bufferless_ONlogN(BidirIt first,BidirIt middle,BidirIt last,Compare comp)348 void merge_bufferless_ONlogN(BidirIt first, BidirIt middle, BidirIt last, Compare comp)
349 {
350    merge_bufferless_ONlogN_recursive
351       (first, middle, last, middle - first, last - middle, comp);
352 }
353 
354 //Complexity: min(len1,len2)^2 + max(len1,len2)
355 template<class RandIt, class Compare>
merge_bufferless_ON2(RandIt first,RandIt middle,RandIt last,Compare comp)356 void merge_bufferless_ON2(RandIt first, RandIt middle, RandIt last, Compare comp)
357 {
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);
363          if(middle == last){
364             break;
365          }
366          do{
367             ++first;
368          } while(first != middle && !comp(*middle, *first));
369       }
370    }
371    else{
372       while(middle != last){
373          RandIt p = boost::movelib::upper_bound(first, middle, last[-1], comp);
374          last = rotate_gcd(p, middle, last);
375          middle = p;
376          if(middle == first){
377             break;
378          }
379          --p;
380          do{
381             --last;
382          } while(middle != last && !comp(last[-1], *p));
383       }
384    }
385 }
386 
387 template<class RandIt, class Compare>
merge_bufferless(RandIt first,RandIt middle,RandIt last,Compare comp)388 void merge_bufferless(RandIt first, RandIt middle, RandIt last, Compare comp)
389 {
390    //#define BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
391    #ifdef BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
392    merge_bufferless_ONlogN(first, middle, last, comp);
393    #else
394    merge_bufferless_ON2(first, middle, last, comp);
395    #endif   //BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
396 }
397 
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>
op_merge_with_right_placed(InputIterator first,InputIterator last,InputOutIterator dest_first,InputOutIterator r_first,InputOutIterator r_last,Compare comp,Op 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)
404 {
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);
410          (void)end;
411          return;
412       }
413       else if (comp(*r_first, *first)) {
414          op(r_first, dest_first);
415          ++r_first;
416       }
417       else {
418          op(first, dest_first);
419          ++first;
420       }
421       ++dest_first;
422    }
423    // Remaining [r_first, r_last) already in the correct place
424 }
425 
426 template <class Compare, class InputIterator, class InputOutIterator>
swap_merge_with_right_placed(InputIterator first,InputIterator last,InputOutIterator dest_first,InputOutIterator r_first,InputOutIterator r_last,Compare comp)427 void swap_merge_with_right_placed
428    ( InputIterator first, InputIterator last
429    , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
430    , Compare comp)
431 {
432    op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, swap_op());
433 }
434 
435 // [first, last) are already in the right part of the destination range.
436 template <class Compare, class Op, class BidirIterator, class BidirOutIterator>
op_merge_with_left_placed(BidirOutIterator const first,BidirOutIterator last,BidirOutIterator dest_last,BidirIterator const r_first,BidirIterator r_last,Compare comp,Op op)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)
441 {
442    BOOST_ASSERT((dest_last - last) == (r_last - r_first));
443    while( r_first != r_last ) {
444       if(first == last) {
445          BidirOutIterator res = op(backward_t(), r_first, r_last, dest_last);
446          BOOST_ASSERT(last == res);
447          (void)res;
448          return;
449       }
450       --r_last;
451       --last;
452       if(comp(*r_last, *last)){
453          ++r_last;
454          --dest_last;
455          op(last, dest_last);
456       }
457       else{
458          ++last;
459          --dest_last;
460          op(r_last, dest_last);
461       }
462    }
463    // Remaining [first, last) already in the correct place
464 }
465 
466 // @endcond
467 
468 // [irst, last) are already in the right part of the destination range.
469 template <class Compare, class BidirIterator, class BidirOutIterator>
merge_with_left_placed(BidirOutIterator const first,BidirOutIterator last,BidirOutIterator dest_last,BidirIterator const r_first,BidirIterator r_last,Compare comp)470 void merge_with_left_placed
471    ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
472    , BidirIterator const r_first, BidirIterator r_last
473    , Compare comp)
474 {
475    op_merge_with_left_placed(first, last, dest_last, r_first, r_last, comp, move_op());
476 }
477 
478 // [r_first, r_last) are already in the right part of the destination range.
479 template <class Compare, class InputIterator, class InputOutIterator>
merge_with_right_placed(InputIterator first,InputIterator last,InputOutIterator dest_first,InputOutIterator r_first,InputOutIterator r_last,Compare comp)480 void merge_with_right_placed
481    ( InputIterator first, InputIterator last
482    , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
483    , Compare comp)
484 {
485    op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, move_op());
486 }
487 
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>
uninitialized_merge_with_right_placed(InputIterator first,InputIterator last,InputOutIterator dest_first,InputOutIterator r_first,InputOutIterator r_last,Compare comp)491 void uninitialized_merge_with_right_placed
492    ( InputIterator first, InputIterator last
493    , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
494    , Compare comp)
495 {
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;
499 
500    destruct_n<value_type, InputOutIterator> d(dest_first);
501 
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));
506             d.incr();
507          }
508          d.release();
509          InputOutIterator end = ::boost::move(first, last, original_r_first);
510          BOOST_ASSERT(end == r_last);
511          (void)end;
512          return;
513       }
514       else if (comp(*r_first, *first)) {
515          ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*r_first));
516          d.incr();
517          ++r_first;
518       }
519       else {
520          ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
521          d.incr();
522          ++first;
523       }
524       ++dest_first;
525    }
526    d.release();
527    merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp);
528 }
529 
530 /*
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
537    , Compare comp)
538 {
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;
542 
543    destruct_n<value_type> d(&*dest_last);
544 
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));
549             d.incr();
550          }
551          d.release();
552          BidirOutIterator end = ::boost::move(first, last, original_r_first);
553          BOOST_ASSERT(end == r_last);
554          (void)end;
555          return;
556       }
557       else if (comp(*r_first, *first)) {
558          ::new(&*dest_first) value_type(::boost::move(*r_first));
559          d.incr();
560          ++r_first;
561       }
562       else {
563          ::new(&*dest_first) value_type(::boost::move(*first));
564          d.incr();
565          ++first;
566       }
567       ++dest_first;
568    }
569    d.release();
570    merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp);
571 }
572 */
573 
574 }  //namespace movelib {
575 }  //namespace boost {
576 
577 #endif   //#define BOOST_MOVE_MERGE_HPP
578