merge.hpp 26 KB

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