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/core/ignore_unused.hpp>
15 #include <boost/move/algo/move.hpp>
16 #include <boost/move/adl_move_swap.hpp>
17 #include <boost/move/algo/detail/basic_op.hpp>
18 #include <boost/move/detail/iterator_traits.hpp>
19 #include <boost/move/detail/destruct_n.hpp>
20 #include <boost/move/algo/predicate.hpp>
21 #include <boost/move/detail/iterator_to_raw_pointer.hpp>
22 #include <boost/assert.hpp>
23 #include <cstddef>
24
25 namespace boost {
26 namespace movelib {
27
28 template<class T, class RandRawIt = T*, class SizeType = typename iterator_traits<RandRawIt>::size_type>
29 class adaptive_xbuf
30 {
31 adaptive_xbuf(const adaptive_xbuf &);
32 adaptive_xbuf & operator=(const adaptive_xbuf &);
33
34 #if !defined(UINTPTR_MAX)
35 typedef std::size_t uintptr_t;
36 #endif
37
38 public:
39 typedef RandRawIt iterator;
40 typedef SizeType size_type;
41
adaptive_xbuf()42 adaptive_xbuf()
43 : m_ptr(), m_size(0), m_capacity(0)
44 {}
45
adaptive_xbuf(RandRawIt raw_memory,size_type capacity)46 adaptive_xbuf(RandRawIt raw_memory, size_type capacity)
47 : m_ptr(raw_memory), m_size(0), m_capacity(capacity)
48 {}
49
50 template<class RandIt>
move_assign(RandIt first,size_type n)51 void move_assign(RandIt first, size_type n)
52 {
53 if(n <= m_size){
54 boost::move(first, first+n, m_ptr);
55 size_type size = m_size;
56 while(size-- != n){
57 m_ptr[size].~T();
58 }
59 m_size = n;
60 }
61 else{
62 RandRawIt result = boost::move(first, first+m_size, m_ptr);
63 boost::uninitialized_move(first+m_size, first+n, result);
64 m_size = n;
65 }
66 }
67
68 template<class RandIt>
push_back(RandIt first,size_type n)69 void push_back(RandIt first, size_type n)
70 {
71 BOOST_ASSERT(m_capacity - m_size >= n);
72 boost::uninitialized_move(first, first+n, m_ptr+m_size);
73 m_size += n;
74 }
75
76 template<class RandIt>
add(RandIt it)77 iterator add(RandIt it)
78 {
79 BOOST_ASSERT(m_size < m_capacity);
80 RandRawIt p_ret = m_ptr + m_size;
81 ::new(&*p_ret) T(::boost::move(*it));
82 ++m_size;
83 return p_ret;
84 }
85
86 template<class RandIt>
insert(iterator pos,RandIt it)87 void insert(iterator pos, RandIt it)
88 {
89 if(pos == (m_ptr + m_size)){
90 this->add(it);
91 }
92 else{
93 this->add(m_ptr+m_size-1);
94 //m_size updated
95 boost::move_backward(pos, m_ptr+m_size-2, m_ptr+m_size-1);
96 *pos = boost::move(*it);
97 }
98 }
99
set_size(size_type size)100 void set_size(size_type size)
101 {
102 m_size = size;
103 }
104
shrink_to_fit(size_type const size)105 void shrink_to_fit(size_type const size)
106 {
107 if(m_size > size){
108 for(size_type szt_i = size; szt_i != m_size; ++szt_i){
109 m_ptr[szt_i].~T();
110 }
111 m_size = size;
112 }
113 }
114
initialize_until(size_type const size,T & t)115 void initialize_until(size_type const size, T &t)
116 {
117 BOOST_ASSERT(m_size < m_capacity);
118 if(m_size < size){
119 BOOST_TRY
120 {
121 ::new((void*)&m_ptr[m_size]) T(::boost::move(t));
122 ++m_size;
123 for(; m_size != size; ++m_size){
124 ::new((void*)&m_ptr[m_size]) T(::boost::move(m_ptr[m_size-1]));
125 }
126 t = ::boost::move(m_ptr[m_size-1]);
127 }
128 BOOST_CATCH(...)
129 {
130 while(m_size)
131 {
132 --m_size;
133 m_ptr[m_size].~T();
134 }
135 }
136 BOOST_CATCH_END
137 }
138 }
139
140 private:
141 template<class RIt>
is_raw_ptr(RIt)142 static bool is_raw_ptr(RIt)
143 {
144 return false;
145 }
146
is_raw_ptr(T *)147 static bool is_raw_ptr(T*)
148 {
149 return true;
150 }
151
152 public:
153 template<class U>
supports_aligned_trailing(size_type size,size_type trail_count) const154 bool supports_aligned_trailing(size_type size, size_type trail_count) const
155 {
156 if(this->is_raw_ptr(this->data()) && m_capacity){
157 uintptr_t u_addr_sz = uintptr_t(&*(this->data()+size));
158 uintptr_t u_addr_cp = uintptr_t(&*(this->data()+this->capacity()));
159 u_addr_sz = ((u_addr_sz + sizeof(U)-1)/sizeof(U))*sizeof(U);
160 return (u_addr_cp >= u_addr_sz) && ((u_addr_cp - u_addr_sz)/sizeof(U) >= trail_count);
161 }
162 return false;
163 }
164
165 template<class U>
aligned_trailing() const166 U *aligned_trailing() const
167 {
168 return this->aligned_trailing<U>(this->size());
169 }
170
171 template<class U>
aligned_trailing(size_type pos) const172 U *aligned_trailing(size_type pos) const
173 {
174 uintptr_t u_addr = uintptr_t(&*(this->data()+pos));
175 u_addr = ((u_addr + sizeof(U)-1)/sizeof(U))*sizeof(U);
176 return (U*)u_addr;
177 }
178
~adaptive_xbuf()179 ~adaptive_xbuf()
180 {
181 this->clear();
182 }
183
capacity() const184 size_type capacity() const
185 { return m_capacity; }
186
data() const187 iterator data() const
188 { return m_ptr; }
189
begin() const190 iterator begin() const
191 { return m_ptr; }
192
end() const193 iterator end() const
194 { return m_ptr+m_size; }
195
size() const196 size_type size() const
197 { return m_size; }
198
empty() const199 bool empty() const
200 { return !m_size; }
201
clear()202 void clear()
203 {
204 this->shrink_to_fit(0u);
205 }
206
207 private:
208 RandRawIt m_ptr;
209 size_type m_size;
210 size_type m_capacity;
211 };
212
213 template<class Iterator, class SizeType, class Op>
214 class range_xbuf
215 {
216 range_xbuf(const range_xbuf &);
217 range_xbuf & operator=(const range_xbuf &);
218
219 public:
220 typedef SizeType size_type;
221 typedef Iterator iterator;
222
range_xbuf(Iterator first,Iterator last)223 range_xbuf(Iterator first, Iterator last)
224 : m_first(first), m_last(first), m_cap(last)
225 {}
226
227 template<class RandIt>
move_assign(RandIt first,size_type n)228 void move_assign(RandIt first, size_type n)
229 {
230 BOOST_ASSERT(size_type(n) <= size_type(m_cap-m_first));
231 m_last = Op()(forward_t(), first, first+n, m_first);
232 }
233
~range_xbuf()234 ~range_xbuf()
235 {}
236
capacity() const237 size_type capacity() const
238 { return m_cap-m_first; }
239
data() const240 Iterator data() const
241 { return m_first; }
242
end() const243 Iterator end() const
244 { return m_last; }
245
size() const246 size_type size() const
247 { return m_last-m_first; }
248
empty() const249 bool empty() const
250 { return m_first == m_last; }
251
clear()252 void clear()
253 {
254 m_last = m_first;
255 }
256
257 template<class RandIt>
add(RandIt it)258 iterator add(RandIt it)
259 {
260 Iterator pos(m_last);
261 *pos = boost::move(*it);
262 ++m_last;
263 return pos;
264 }
265
set_size(size_type size)266 void set_size(size_type size)
267 {
268 m_last = m_first;
269 m_last += size;
270 }
271
272 private:
273 Iterator const m_first;
274 Iterator m_last;
275 Iterator const m_cap;
276 };
277
278
279
280 // @cond
281
282 /*
283 template<typename Unsigned>
284 inline Unsigned gcd(Unsigned x, Unsigned y)
285 {
286 if(0 == ((x &(x-1)) | (y & (y-1)))){
287 return x < y ? x : y;
288 }
289 else{
290 do
291 {
292 Unsigned t = x % y;
293 x = y;
294 y = t;
295 } while (y);
296 return x;
297 }
298 }
299 */
300
301 //Modified version from "An Optimal In-Place Array Rotation Algorithm", Ching-Kuang Shene
302 template<typename Unsigned>
gcd(Unsigned x,Unsigned y)303 Unsigned gcd(Unsigned x, Unsigned y)
304 {
305 if(0 == ((x &(x-1)) | (y & (y-1)))){
306 return x < y ? x : y;
307 }
308 else{
309 Unsigned z = 1;
310 while((!(x&1)) & (!(y&1))){
311 z <<=1, x>>=1, y>>=1;
312 }
313 while(x && y){
314 if(!(x&1))
315 x >>=1;
316 else if(!(y&1))
317 y >>=1;
318 else if(x >=y)
319 x = (x-y) >> 1;
320 else
321 y = (y-x) >> 1;
322 }
323 return z*(x+y);
324 }
325 }
326
327 template<typename RandIt>
rotate_gcd(RandIt first,RandIt middle,RandIt last)328 RandIt rotate_gcd(RandIt first, RandIt middle, RandIt last)
329 {
330 typedef typename iterator_traits<RandIt>::size_type size_type;
331 typedef typename iterator_traits<RandIt>::value_type value_type;
332
333 if(first == middle)
334 return last;
335 if(middle == last)
336 return first;
337 const size_type middle_pos = size_type(middle - first);
338 RandIt ret = last - middle_pos;
339 if (middle == ret){
340 boost::adl_move_swap_ranges(first, middle, middle);
341 }
342 else{
343 const size_type length = size_type(last - first);
344 for( RandIt it_i(first), it_gcd(it_i + gcd(length, middle_pos))
345 ; it_i != it_gcd
346 ; ++it_i){
347 value_type temp(boost::move(*it_i));
348 RandIt it_j = it_i;
349 RandIt it_k = it_j+middle_pos;
350 do{
351 *it_j = boost::move(*it_k);
352 it_j = it_k;
353 size_type const left = size_type(last - it_j);
354 it_k = left > middle_pos ? it_j + middle_pos : first + (middle_pos - left);
355 } while(it_k != it_i);
356 *it_j = boost::move(temp);
357 }
358 }
359 return ret;
360 }
361
362 template <class RandIt, class T, class Compare>
lower_bound(RandIt first,const RandIt last,const T & key,Compare comp)363 RandIt lower_bound
364 (RandIt first, const RandIt last, const T& key, Compare comp)
365 {
366 typedef typename iterator_traits
367 <RandIt>::size_type size_type;
368 size_type len = size_type(last - first);
369 RandIt middle;
370
371 while (len) {
372 size_type step = len >> 1;
373 middle = first;
374 middle += step;
375
376 if (comp(*middle, key)) {
377 first = ++middle;
378 len -= step + 1;
379 }
380 else{
381 len = step;
382 }
383 }
384 return first;
385 }
386
387 template <class RandIt, class T, class Compare>
upper_bound(RandIt first,const RandIt last,const T & key,Compare comp)388 RandIt upper_bound
389 (RandIt first, const RandIt last, const T& key, Compare comp)
390 {
391 typedef typename iterator_traits
392 <RandIt>::size_type size_type;
393 size_type len = size_type(last - first);
394 RandIt middle;
395
396 while (len) {
397 size_type step = len >> 1;
398 middle = first;
399 middle += step;
400
401 if (!comp(key, *middle)) {
402 first = ++middle;
403 len -= step + 1;
404 }
405 else{
406 len = step;
407 }
408 }
409 return first;
410 }
411
412
413 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)414 void op_merge_left( RandIt buf_first
415 , RandIt first1
416 , RandIt const last1
417 , RandIt const last2
418 , Compare comp
419 , Op op)
420 {
421 for(RandIt first2=last1; first2 != last2; ++buf_first){
422 if(first1 == last1){
423 op(forward_t(), first2, last2, buf_first);
424 return;
425 }
426 else if(comp(*first2, *first1)){
427 op(first2, buf_first);
428 ++first2;
429 }
430 else{
431 op(first1, buf_first);
432 ++first1;
433 }
434 }
435 if(buf_first != first1){//In case all remaining elements are in the same place
436 //(e.g. buffer is exactly the size of the second half
437 //and all elements from the second half are less)
438 op(forward_t(), first1, last1, buf_first);
439 }
440 }
441
442 // [buf_first, first1) -> buffer
443 // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
444 // Elements from buffer are moved to [last2 - (first1-buf_first), last2)
445 // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
446 template<class RandIt, class Compare>
merge_left(RandIt buf_first,RandIt first1,RandIt const last1,RandIt const last2,Compare comp)447 void merge_left
448 (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
449 {
450 op_merge_left(buf_first, first1, last1, last2, comp, move_op());
451 }
452
453 // [buf_first, first1) -> buffer
454 // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
455 // Elements from buffer are swapped to [last2 - (first1-buf_first), last2)
456 // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
457 template<class RandIt, class Compare>
swap_merge_left(RandIt buf_first,RandIt first1,RandIt const last1,RandIt const last2,Compare comp)458 void swap_merge_left
459 (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
460 {
461 op_merge_left(buf_first, first1, last1, last2, comp, swap_op());
462 }
463
464 template<class RandIt, class Compare, class Op>
op_merge_right(RandIt const first1,RandIt last1,RandIt last2,RandIt buf_last,Compare comp,Op op)465 void op_merge_right
466 (RandIt const first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp, Op op)
467 {
468 RandIt const first2 = last1;
469 while(first1 != last1){
470 if(last2 == first2){
471 op(backward_t(), first1, last1, buf_last);
472 return;
473 }
474 --last2;
475 --last1;
476 --buf_last;
477 if(comp(*last2, *last1)){
478 op(last1, buf_last);
479 ++last2;
480 }
481 else{
482 op(last2, buf_last);
483 ++last1;
484 }
485 }
486 if(last2 != buf_last){ //In case all remaining elements are in the same place
487 //(e.g. buffer is exactly the size of the first half
488 //and all elements from the second half are less)
489 op(backward_t(), first2, last2, buf_last);
490 }
491 }
492
493 // [last2, buf_last) - buffer
494 // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
495 // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
496 template<class RandIt, class Compare>
merge_right(RandIt first1,RandIt last1,RandIt last2,RandIt buf_last,Compare comp)497 void merge_right
498 (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
499 {
500 op_merge_right(first1, last1, last2, buf_last, comp, move_op());
501 }
502
503 // [last2, buf_last) - buffer
504 // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
505 // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
506 template<class RandIt, class Compare>
swap_merge_right(RandIt first1,RandIt last1,RandIt last2,RandIt buf_last,Compare comp)507 void swap_merge_right
508 (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
509 {
510 op_merge_right(first1, last1, last2, buf_last, comp, swap_op());
511 }
512
513 ///////////////////////////////////////////////////////////////////////////////
514 //
515 // BUFFERED MERGE
516 //
517 ///////////////////////////////////////////////////////////////////////////////
518 template<class RandIt, class Compare, class Op, class Buf>
op_buffered_merge(RandIt first,RandIt const middle,RandIt last,Compare comp,Op op,Buf & xbuf)519 void op_buffered_merge
520 ( RandIt first, RandIt const middle, RandIt last
521 , Compare comp, Op op
522 , Buf &xbuf)
523 {
524 if(first != middle && middle != last && comp(*middle, middle[-1])){
525 typedef typename iterator_traits<RandIt>::size_type size_type;
526 size_type const len1 = size_type(middle-first);
527 size_type const len2 = size_type(last-middle);
528 if(len1 <= len2){
529 first = boost::movelib::upper_bound(first, middle, *middle, comp);
530 xbuf.move_assign(first, size_type(middle-first));
531 op_merge_with_right_placed
532 (xbuf.data(), xbuf.end(), first, middle, last, comp, op);
533 }
534 else{
535 last = boost::movelib::lower_bound(middle, last, middle[-1], comp);
536 xbuf.move_assign(middle, size_type(last-middle));
537 op_merge_with_left_placed
538 (first, middle, last, xbuf.data(), xbuf.end(), comp, op);
539 }
540 }
541 }
542
543 template<class RandIt, class Compare, class XBuf>
buffered_merge(RandIt first,RandIt const middle,RandIt last,Compare comp,XBuf & xbuf)544 void buffered_merge
545 ( RandIt first, RandIt const middle, RandIt last
546 , Compare comp
547 , XBuf &xbuf)
548 {
549 op_buffered_merge(first, middle, last, comp, move_op(), xbuf);
550 }
551
552 //Complexity: min(len1,len2)^2 + max(len1,len2)
553 template<class RandIt, class Compare>
merge_bufferless_ON2(RandIt first,RandIt middle,RandIt last,Compare comp)554 void merge_bufferless_ON2(RandIt first, RandIt middle, RandIt last, Compare comp)
555 {
556 if((middle - first) < (last - middle)){
557 while(first != middle){
558 RandIt const old_last1 = middle;
559 middle = boost::movelib::lower_bound(middle, last, *first, comp);
560 first = rotate_gcd(first, old_last1, middle);
561 if(middle == last){
562 break;
563 }
564 do{
565 ++first;
566 } while(first != middle && !comp(*middle, *first));
567 }
568 }
569 else{
570 while(middle != last){
571 RandIt p = boost::movelib::upper_bound(first, middle, last[-1], comp);
572 last = rotate_gcd(p, middle, last);
573 middle = p;
574 if(middle == first){
575 break;
576 }
577 --p;
578 do{
579 --last;
580 } while(middle != last && !comp(last[-1], *p));
581 }
582 }
583 }
584
585 static const std::size_t MergeBufferlessONLogNRotationThreshold = 16u;
586
587 template <class RandIt, class Compare>
merge_bufferless_ONlogN_recursive(RandIt first,RandIt middle,RandIt last,typename iterator_traits<RandIt>::size_type len1,typename iterator_traits<RandIt>::size_type len2,Compare comp)588 void merge_bufferless_ONlogN_recursive
589 ( RandIt first, RandIt middle, RandIt last
590 , typename iterator_traits<RandIt>::size_type len1
591 , typename iterator_traits<RandIt>::size_type len2
592 , Compare comp)
593 {
594 typedef typename iterator_traits<RandIt>::size_type size_type;
595
596 while(1) {
597 //trivial cases
598 if (!len2) {
599 return;
600 }
601 else if (!len1) {
602 return;
603 }
604 else if (size_type(len1 | len2) == 1u) {
605 if (comp(*middle, *first))
606 adl_move_swap(*first, *middle);
607 return;
608 }
609 else if(size_type(len1+len2) < MergeBufferlessONLogNRotationThreshold){
610 merge_bufferless_ON2(first, middle, last, comp);
611 return;
612 }
613
614 RandIt first_cut = first;
615 RandIt second_cut = middle;
616 size_type len11 = 0;
617 size_type len22 = 0;
618 if (len1 > len2) {
619 len11 = len1 / 2;
620 first_cut += len11;
621 second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
622 len22 = size_type(second_cut - middle);
623 }
624 else {
625 len22 = len2 / 2;
626 second_cut += len22;
627 first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
628 len11 = size_type(first_cut - first);
629 }
630 RandIt new_middle = rotate_gcd(first_cut, middle, second_cut);
631
632 //Avoid one recursive call doing a manual tail call elimination on the biggest range
633 const size_type len_internal = len11+len22;
634 if( len_internal < (len1 + len2 - len_internal) ) {
635 merge_bufferless_ONlogN_recursive(first, first_cut, new_middle, len11, len22, comp);
636 first = new_middle;
637 middle = second_cut;
638 len1 -= len11;
639 len2 -= len22;
640 }
641 else {
642 merge_bufferless_ONlogN_recursive(new_middle, second_cut, last, len1 - len11, len2 - len22, comp);
643 middle = first_cut;
644 last = new_middle;
645 len1 = len11;
646 len2 = len22;
647 }
648 }
649 }
650
651
652 //Complexity: NlogN
653 template<class RandIt, class Compare>
merge_bufferless_ONlogN(RandIt first,RandIt middle,RandIt last,Compare comp)654 void merge_bufferless_ONlogN(RandIt first, RandIt middle, RandIt last, Compare comp)
655 {
656 typedef typename iterator_traits<RandIt>::size_type size_type;
657 merge_bufferless_ONlogN_recursive
658 (first, middle, last, size_type(middle - first), size_type(last - middle), comp);
659 }
660
661 template<class RandIt, class Compare>
merge_bufferless(RandIt first,RandIt middle,RandIt last,Compare comp)662 void merge_bufferless(RandIt first, RandIt middle, RandIt last, Compare comp)
663 {
664 #define BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
665 #ifdef BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
666 merge_bufferless_ONlogN(first, middle, last, comp);
667 #else
668 merge_bufferless_ON2(first, middle, last, comp);
669 #endif //BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
670 }
671
672 // [r_first, r_last) are already in the right part of the destination range.
673 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)674 void op_merge_with_right_placed
675 ( InputIterator first, InputIterator last
676 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
677 , Compare comp, Op op)
678 {
679 BOOST_ASSERT((last - first) == (r_first - dest_first));
680 while ( first != last ) {
681 if (r_first == r_last) {
682 InputOutIterator end = op(forward_t(), first, last, dest_first);
683 BOOST_ASSERT(end == r_last);
684 boost::ignore_unused(end);
685 return;
686 }
687 else if (comp(*r_first, *first)) {
688 op(r_first, dest_first);
689 ++r_first;
690 }
691 else {
692 op(first, dest_first);
693 ++first;
694 }
695 ++dest_first;
696 }
697 // Remaining [r_first, r_last) already in the correct place
698 }
699
700 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)701 void swap_merge_with_right_placed
702 ( InputIterator first, InputIterator last
703 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
704 , Compare comp)
705 {
706 op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, swap_op());
707 }
708
709 // [first, last) are already in the right part of the destination range.
710 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)711 void op_merge_with_left_placed
712 ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
713 , BidirIterator const r_first, BidirIterator r_last
714 , Compare comp, Op op)
715 {
716 BOOST_ASSERT((dest_last - last) == (r_last - r_first));
717 while( r_first != r_last ) {
718 if(first == last) {
719 BidirOutIterator res = op(backward_t(), r_first, r_last, dest_last);
720 BOOST_ASSERT(last == res);
721 boost::ignore_unused(res);
722 return;
723 }
724 --r_last;
725 --last;
726 if(comp(*r_last, *last)){
727 ++r_last;
728 --dest_last;
729 op(last, dest_last);
730 }
731 else{
732 ++last;
733 --dest_last;
734 op(r_last, dest_last);
735 }
736 }
737 // Remaining [first, last) already in the correct place
738 }
739
740 // @endcond
741
742 // [first, last) are already in the right part of the destination range.
743 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)744 void merge_with_left_placed
745 ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
746 , BidirIterator const r_first, BidirIterator r_last
747 , Compare comp)
748 {
749 op_merge_with_left_placed(first, last, dest_last, r_first, r_last, comp, move_op());
750 }
751
752 // [r_first, r_last) are already in the right part of the destination range.
753 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)754 void merge_with_right_placed
755 ( InputIterator first, InputIterator last
756 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
757 , Compare comp)
758 {
759 op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, move_op());
760 }
761
762 // [r_first, r_last) are already in the right part of the destination range.
763 // [dest_first, r_first) is uninitialized memory
764 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)765 void uninitialized_merge_with_right_placed
766 ( InputIterator first, InputIterator last
767 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
768 , Compare comp)
769 {
770 BOOST_ASSERT((last - first) == (r_first - dest_first));
771 typedef typename iterator_traits<InputOutIterator>::value_type value_type;
772 InputOutIterator const original_r_first = r_first;
773
774 destruct_n<value_type, InputOutIterator> d(dest_first);
775
776 while ( first != last && dest_first != original_r_first ) {
777 if (r_first == r_last) {
778 for(; dest_first != original_r_first; ++dest_first, ++first){
779 ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
780 d.incr();
781 }
782 d.release();
783 InputOutIterator end = ::boost::move(first, last, original_r_first);
784 BOOST_ASSERT(end == r_last);
785 boost::ignore_unused(end);
786 return;
787 }
788 else if (comp(*r_first, *first)) {
789 ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*r_first));
790 d.incr();
791 ++r_first;
792 }
793 else {
794 ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
795 d.incr();
796 ++first;
797 }
798 ++dest_first;
799 }
800 d.release();
801 merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp);
802 }
803
804 /// This is a helper function for the merge routines.
805 template<typename BidirectionalIterator1, typename BidirectionalIterator2>
806 BidirectionalIterator1
rotate_adaptive(BidirectionalIterator1 first,BidirectionalIterator1 middle,BidirectionalIterator1 last,typename iterator_traits<BidirectionalIterator1>::size_type len1,typename iterator_traits<BidirectionalIterator1>::size_type len2,BidirectionalIterator2 buffer,typename iterator_traits<BidirectionalIterator1>::size_type buffer_size)807 rotate_adaptive(BidirectionalIterator1 first,
808 BidirectionalIterator1 middle,
809 BidirectionalIterator1 last,
810 typename iterator_traits<BidirectionalIterator1>::size_type len1,
811 typename iterator_traits<BidirectionalIterator1>::size_type len2,
812 BidirectionalIterator2 buffer,
813 typename iterator_traits<BidirectionalIterator1>::size_type buffer_size)
814 {
815 if (len1 > len2 && len2 <= buffer_size)
816 {
817 if(len2) //Protect against self-move ranges
818 {
819 BidirectionalIterator2 buffer_end = boost::move(middle, last, buffer);
820 boost::move_backward(first, middle, last);
821 return boost::move(buffer, buffer_end, first);
822 }
823 else
824 return first;
825 }
826 else if (len1 <= buffer_size)
827 {
828 if(len1) //Protect against self-move ranges
829 {
830 BidirectionalIterator2 buffer_end = boost::move(first, middle, buffer);
831 BidirectionalIterator1 ret = boost::move(middle, last, first);
832 boost::move(buffer, buffer_end, ret);
833 return ret;
834 }
835 else
836 return last;
837 }
838 else
839 return rotate_gcd(first, middle, last);
840 }
841
842 template<typename BidirectionalIterator,
843 typename Pointer, typename Compare>
merge_adaptive_ONlogN_recursive(BidirectionalIterator first,BidirectionalIterator middle,BidirectionalIterator last,typename iterator_traits<BidirectionalIterator>::size_type len1,typename iterator_traits<BidirectionalIterator>::size_type len2,Pointer buffer,typename iterator_traits<BidirectionalIterator>::size_type buffer_size,Compare comp)844 void merge_adaptive_ONlogN_recursive
845 (BidirectionalIterator first,
846 BidirectionalIterator middle,
847 BidirectionalIterator last,
848 typename iterator_traits<BidirectionalIterator>::size_type len1,
849 typename iterator_traits<BidirectionalIterator>::size_type len2,
850 Pointer buffer,
851 typename iterator_traits<BidirectionalIterator>::size_type buffer_size,
852 Compare comp)
853 {
854 typedef typename iterator_traits<BidirectionalIterator>::size_type size_type;
855 //trivial cases
856 if (!len2 || !len1) {
857 return;
858 }
859 else if (len1 <= buffer_size || len2 <= buffer_size)
860 {
861 range_xbuf<Pointer, size_type, move_op> rxbuf(buffer, buffer + buffer_size);
862 buffered_merge(first, middle, last, comp, rxbuf);
863 }
864 else if (size_type(len1 + len2) == 2u) {
865 if (comp(*middle, *first))
866 adl_move_swap(*first, *middle);
867 return;
868 }
869 else if (size_type(len1 + len2) < MergeBufferlessONLogNRotationThreshold) {
870 merge_bufferless_ON2(first, middle, last, comp);
871 return;
872 }
873 BidirectionalIterator first_cut = first;
874 BidirectionalIterator second_cut = middle;
875 size_type len11 = 0;
876 size_type len22 = 0;
877 if (len1 > len2) //(len1 < len2)
878 {
879 len11 = len1 / 2;
880 first_cut += len11;
881 second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
882 len22 = second_cut - middle;
883 }
884 else
885 {
886 len22 = len2 / 2;
887 second_cut += len22;
888 first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
889 len11 = first_cut - first;
890 }
891
892 BidirectionalIterator new_middle
893 = rotate_adaptive(first_cut, middle, second_cut,
894 size_type(len1 - len11), len22, buffer,
895 buffer_size);
896 merge_adaptive_ONlogN_recursive(first, first_cut, new_middle, len11,
897 len22, buffer, buffer_size, comp);
898 merge_adaptive_ONlogN_recursive(new_middle, second_cut, last,
899 len1 - len11, len2 - len22, buffer, buffer_size, comp);
900 }
901
902
903 template<typename BidirectionalIterator, typename Compare, typename RandRawIt>
merge_adaptive_ONlogN(BidirectionalIterator first,BidirectionalIterator middle,BidirectionalIterator last,Compare comp,RandRawIt uninitialized,typename iterator_traits<BidirectionalIterator>::size_type uninitialized_len)904 void merge_adaptive_ONlogN(BidirectionalIterator first,
905 BidirectionalIterator middle,
906 BidirectionalIterator last,
907 Compare comp,
908 RandRawIt uninitialized,
909 typename iterator_traits<BidirectionalIterator>::size_type uninitialized_len)
910 {
911 typedef typename iterator_traits<BidirectionalIterator>::value_type value_type;
912 typedef typename iterator_traits<BidirectionalIterator>::size_type size_type;
913
914 if (first == middle || middle == last)
915 return;
916
917 if(uninitialized_len)
918 {
919 const size_type len1 = size_type(middle - first);
920 const size_type len2 = size_type(last - middle);
921
922 ::boost::movelib::adaptive_xbuf<value_type, RandRawIt> xbuf(uninitialized, uninitialized_len);
923 xbuf.initialize_until(uninitialized_len, *first);
924 merge_adaptive_ONlogN_recursive(first, middle, last, len1, len2, xbuf.begin(), uninitialized_len, comp);
925 }
926 else
927 {
928 merge_bufferless(first, middle, last, comp);
929 }
930 }
931
932
933 } //namespace movelib {
934 } //namespace boost {
935
936 #endif //#define BOOST_MOVE_MERGE_HPP
937