merge.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  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/algo/move.hpp>
  14. #include <boost/move/adl_move_swap.hpp>
  15. #include <boost/move/algo/detail/basic_op.hpp>
  16. #include <boost/move/detail/iterator_traits.hpp>
  17. #include <boost/move/detail/destruct_n.hpp>
  18. #include <boost/move/algo/predicate.hpp>
  19. #include <boost/move/detail/iterator_to_raw_pointer.hpp>
  20. #include <boost/assert.hpp>
  21. namespace boost {
  22. namespace movelib {
  23. // @cond
  24. /*
  25. template<typename Unsigned>
  26. inline Unsigned gcd(Unsigned x, Unsigned y)
  27. {
  28. if(0 == ((x &(x-1)) | (y & (y-1)))){
  29. return x < y ? x : y;
  30. }
  31. else{
  32. do
  33. {
  34. Unsigned t = x % y;
  35. x = y;
  36. y = t;
  37. } while (y);
  38. return x;
  39. }
  40. }
  41. */
  42. //Modified version from "An Optimal In-Place Array Rotation Algorithm", Ching-Kuang Shene
  43. template<typename Unsigned>
  44. Unsigned gcd(Unsigned x, Unsigned y)
  45. {
  46. if(0 == ((x &(x-1)) | (y & (y-1)))){
  47. return x < y ? x : y;
  48. }
  49. else{
  50. Unsigned z = 1;
  51. while((!(x&1)) & (!(y&1))){
  52. z <<=1, x>>=1, y>>=1;
  53. }
  54. while(x && y){
  55. if(!(x&1))
  56. x >>=1;
  57. else if(!(y&1))
  58. y >>=1;
  59. else if(x >=y)
  60. x = (x-y) >> 1;
  61. else
  62. y = (y-x) >> 1;
  63. }
  64. return z*(x+y);
  65. }
  66. }
  67. template<typename RandIt>
  68. RandIt rotate_gcd(RandIt first, RandIt middle, RandIt last)
  69. {
  70. typedef typename iterator_traits<RandIt>::size_type size_type;
  71. typedef typename iterator_traits<RandIt>::value_type value_type;
  72. if(first == middle)
  73. return last;
  74. if(middle == last)
  75. return first;
  76. const size_type middle_pos = size_type(middle - first);
  77. RandIt ret = last - middle_pos;
  78. if (middle == ret){
  79. boost::adl_move_swap_ranges(first, middle, middle);
  80. }
  81. else{
  82. const size_type length = size_type(last - first);
  83. for( RandIt it_i(first), it_gcd(it_i + gcd(length, middle_pos))
  84. ; it_i != it_gcd
  85. ; ++it_i){
  86. value_type temp(boost::move(*it_i));
  87. RandIt it_j = it_i;
  88. RandIt it_k = it_j+middle_pos;
  89. do{
  90. *it_j = boost::move(*it_k);
  91. it_j = it_k;
  92. size_type const left = size_type(last - it_j);
  93. it_k = left > middle_pos ? it_j + middle_pos : first + (middle_pos - left);
  94. } while(it_k != it_i);
  95. *it_j = boost::move(temp);
  96. }
  97. }
  98. return ret;
  99. }
  100. template <class RandIt, class T, class Compare>
  101. RandIt lower_bound
  102. (RandIt first, const RandIt last, const T& key, Compare comp)
  103. {
  104. typedef typename iterator_traits
  105. <RandIt>::size_type size_type;
  106. size_type len = size_type(last - first);
  107. RandIt middle;
  108. while (len) {
  109. size_type step = len >> 1;
  110. middle = first;
  111. middle += step;
  112. if (comp(*middle, key)) {
  113. first = ++middle;
  114. len -= step + 1;
  115. }
  116. else{
  117. len = step;
  118. }
  119. }
  120. return first;
  121. }
  122. template <class RandIt, class T, class Compare>
  123. RandIt upper_bound
  124. (RandIt first, const RandIt last, const T& key, Compare comp)
  125. {
  126. typedef typename iterator_traits
  127. <RandIt>::size_type size_type;
  128. size_type len = size_type(last - first);
  129. RandIt middle;
  130. while (len) {
  131. size_type step = len >> 1;
  132. middle = first;
  133. middle += step;
  134. if (!comp(key, *middle)) {
  135. first = ++middle;
  136. len -= step + 1;
  137. }
  138. else{
  139. len = step;
  140. }
  141. }
  142. return first;
  143. }
  144. template<class RandIt, class Compare, class Op>
  145. void op_merge_left( RandIt buf_first
  146. , RandIt first1
  147. , RandIt const last1
  148. , RandIt const last2
  149. , Compare comp
  150. , Op op)
  151. {
  152. for(RandIt first2=last1; first2 != last2; ++buf_first){
  153. if(first1 == last1){
  154. op(forward_t(), first2, last2, buf_first);
  155. return;
  156. }
  157. else if(comp(*first2, *first1)){
  158. op(first2, buf_first);
  159. ++first2;
  160. }
  161. else{
  162. op(first1, buf_first);
  163. ++first1;
  164. }
  165. }
  166. if(buf_first != first1){//In case all remaining elements are in the same place
  167. //(e.g. buffer is exactly the size of the second half
  168. //and all elements from the second half are less)
  169. op(forward_t(), first1, last1, buf_first);
  170. }
  171. }
  172. // [buf_first, first1) -> buffer
  173. // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
  174. // Elements from buffer are moved to [last2 - (first1-buf_first), last2)
  175. // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
  176. template<class RandIt, class Compare>
  177. void merge_left
  178. (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
  179. {
  180. op_merge_left(buf_first, first1, last1, last2, comp, move_op());
  181. }
  182. // [buf_first, first1) -> buffer
  183. // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
  184. // Elements from buffer are swapped to [last2 - (first1-buf_first), last2)
  185. // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
  186. template<class RandIt, class Compare>
  187. void swap_merge_left
  188. (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
  189. {
  190. op_merge_left(buf_first, first1, last1, last2, comp, swap_op());
  191. }
  192. template<class RandIt, class Compare, class Op>
  193. void op_merge_right
  194. (RandIt const first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp, Op op)
  195. {
  196. RandIt const first2 = last1;
  197. while(first1 != last1){
  198. if(last2 == first2){
  199. op(backward_t(), first1, last1, buf_last);
  200. return;
  201. }
  202. --last2;
  203. --last1;
  204. --buf_last;
  205. if(comp(*last2, *last1)){
  206. op(last1, buf_last);
  207. ++last2;
  208. }
  209. else{
  210. op(last2, buf_last);
  211. ++last1;
  212. }
  213. }
  214. if(last2 != buf_last){ //In case all remaining elements are in the same place
  215. //(e.g. buffer is exactly the size of the first half
  216. //and all elements from the second half are less)
  217. op(backward_t(), first2, last2, buf_last);
  218. }
  219. }
  220. // [last2, buf_last) - buffer
  221. // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
  222. // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
  223. template<class RandIt, class Compare>
  224. void merge_right
  225. (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
  226. {
  227. op_merge_right(first1, last1, last2, buf_last, comp, move_op());
  228. }
  229. // [last2, buf_last) - buffer
  230. // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
  231. // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
  232. template<class RandIt, class Compare>
  233. void swap_merge_right
  234. (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
  235. {
  236. op_merge_right(first1, last1, last2, buf_last, comp, swap_op());
  237. }
  238. //Complexity: min(len1,len2)^2 + max(len1,len2)
  239. template<class RandIt, class Compare>
  240. void merge_bufferless_ON2(RandIt first, RandIt middle, RandIt last, Compare comp)
  241. {
  242. if((middle - first) < (last - middle)){
  243. while(first != middle){
  244. RandIt const old_last1 = middle;
  245. middle = boost::movelib::lower_bound(middle, last, *first, comp);
  246. first = rotate_gcd(first, old_last1, middle);
  247. if(middle == last){
  248. break;
  249. }
  250. do{
  251. ++first;
  252. } while(first != middle && !comp(*middle, *first));
  253. }
  254. }
  255. else{
  256. while(middle != last){
  257. RandIt p = boost::movelib::upper_bound(first, middle, last[-1], comp);
  258. last = rotate_gcd(p, middle, last);
  259. middle = p;
  260. if(middle == first){
  261. break;
  262. }
  263. --p;
  264. do{
  265. --last;
  266. } while(middle != last && !comp(last[-1], *p));
  267. }
  268. }
  269. }
  270. static const std::size_t MergeBufferlessONLogNRotationThreshold = 32;
  271. template <class RandIt, class Distance, class Compare>
  272. void merge_bufferless_ONlogN_recursive
  273. (RandIt first, RandIt middle, RandIt last, Distance len1, Distance len2, Compare comp)
  274. {
  275. typedef typename iterator_traits<RandIt>::size_type size_type;
  276. while(1) {
  277. //trivial cases
  278. if (!len2) {
  279. return;
  280. }
  281. else if (!len1) {
  282. return;
  283. }
  284. else if (size_type(len1 | len2) == 1u) {
  285. if (comp(*middle, *first))
  286. adl_move_swap(*first, *middle);
  287. return;
  288. }
  289. else if(size_type(len1+len2) < MergeBufferlessONLogNRotationThreshold){
  290. merge_bufferless_ON2(first, middle, last, comp);
  291. return;
  292. }
  293. RandIt first_cut = first;
  294. RandIt second_cut = middle;
  295. Distance len11 = 0;
  296. Distance len22 = 0;
  297. if (len1 > len2) {
  298. len11 = len1 / 2;
  299. first_cut += len11;
  300. second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
  301. len22 = size_type(second_cut - middle);
  302. }
  303. else {
  304. len22 = len2 / 2;
  305. second_cut += len22;
  306. first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
  307. len11 = size_type(first_cut - first);
  308. }
  309. RandIt new_middle = rotate_gcd(first_cut, middle, second_cut);
  310. //Avoid one recursive call doing a manual tail call elimination on the biggest range
  311. const Distance len_internal = len11+len22;
  312. if( len_internal < (len1 + len2 - len_internal) ) {
  313. merge_bufferless_ONlogN_recursive(first, first_cut, new_middle, len11, len22, comp);
  314. first = new_middle;
  315. middle = second_cut;
  316. len1 -= len11;
  317. len2 -= len22;
  318. }
  319. else {
  320. merge_bufferless_ONlogN_recursive(new_middle, second_cut, last, len1 - len11, len2 - len22, comp);
  321. middle = first_cut;
  322. last = new_middle;
  323. len1 = len11;
  324. len2 = len22;
  325. }
  326. }
  327. }
  328. //Complexity: NlogN
  329. template<class RandIt, class Compare>
  330. void merge_bufferless_ONlogN(RandIt first, RandIt middle, RandIt last, Compare comp)
  331. {
  332. merge_bufferless_ONlogN_recursive
  333. (first, middle, last, middle - first, last - middle, comp);
  334. }
  335. template<class RandIt, class Compare>
  336. void merge_bufferless(RandIt first, RandIt middle, RandIt last, Compare comp)
  337. {
  338. #define BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
  339. #ifdef BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
  340. merge_bufferless_ONlogN(first, middle, last, comp);
  341. #else
  342. merge_bufferless_ON2(first, middle, last, comp);
  343. #endif //BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
  344. }
  345. // [r_first, r_last) are already in the right part of the destination range.
  346. template <class Compare, class InputIterator, class InputOutIterator, class Op>
  347. void op_merge_with_right_placed
  348. ( InputIterator first, InputIterator last
  349. , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
  350. , Compare comp, Op op)
  351. {
  352. BOOST_ASSERT((last - first) == (r_first - dest_first));
  353. while ( first != last ) {
  354. if (r_first == r_last) {
  355. InputOutIterator end = op(forward_t(), first, last, dest_first);
  356. BOOST_ASSERT(end == r_last);
  357. (void)end;
  358. return;
  359. }
  360. else if (comp(*r_first, *first)) {
  361. op(r_first, dest_first);
  362. ++r_first;
  363. }
  364. else {
  365. op(first, dest_first);
  366. ++first;
  367. }
  368. ++dest_first;
  369. }
  370. // Remaining [r_first, r_last) already in the correct place
  371. }
  372. template <class Compare, class InputIterator, class InputOutIterator>
  373. void swap_merge_with_right_placed
  374. ( InputIterator first, InputIterator last
  375. , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
  376. , Compare comp)
  377. {
  378. op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, swap_op());
  379. }
  380. // [first, last) are already in the right part of the destination range.
  381. template <class Compare, class Op, class BidirIterator, class BidirOutIterator>
  382. void op_merge_with_left_placed
  383. ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
  384. , BidirIterator const r_first, BidirIterator r_last
  385. , Compare comp, Op op)
  386. {
  387. BOOST_ASSERT((dest_last - last) == (r_last - r_first));
  388. while( r_first != r_last ) {
  389. if(first == last) {
  390. BidirOutIterator res = op(backward_t(), r_first, r_last, dest_last);
  391. BOOST_ASSERT(last == res);
  392. (void)res;
  393. return;
  394. }
  395. --r_last;
  396. --last;
  397. if(comp(*r_last, *last)){
  398. ++r_last;
  399. --dest_last;
  400. op(last, dest_last);
  401. }
  402. else{
  403. ++last;
  404. --dest_last;
  405. op(r_last, dest_last);
  406. }
  407. }
  408. // Remaining [first, last) already in the correct place
  409. }
  410. // @endcond
  411. // [irst, last) are already in the right part of the destination range.
  412. template <class Compare, class BidirIterator, class BidirOutIterator>
  413. void merge_with_left_placed
  414. ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
  415. , BidirIterator const r_first, BidirIterator r_last
  416. , Compare comp)
  417. {
  418. op_merge_with_left_placed(first, last, dest_last, r_first, r_last, comp, move_op());
  419. }
  420. // [r_first, r_last) are already in the right part of the destination range.
  421. template <class Compare, class InputIterator, class InputOutIterator>
  422. void merge_with_right_placed
  423. ( InputIterator first, InputIterator last
  424. , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
  425. , Compare comp)
  426. {
  427. op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, move_op());
  428. }
  429. // [r_first, r_last) are already in the right part of the destination range.
  430. // [dest_first, r_first) is uninitialized memory
  431. template <class Compare, class InputIterator, class InputOutIterator>
  432. void uninitialized_merge_with_right_placed
  433. ( InputIterator first, InputIterator last
  434. , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
  435. , Compare comp)
  436. {
  437. BOOST_ASSERT((last - first) == (r_first - dest_first));
  438. typedef typename iterator_traits<InputOutIterator>::value_type value_type;
  439. InputOutIterator const original_r_first = r_first;
  440. destruct_n<value_type, InputOutIterator> d(dest_first);
  441. while ( first != last && dest_first != original_r_first ) {
  442. if (r_first == r_last) {
  443. for(; dest_first != original_r_first; ++dest_first, ++first){
  444. ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
  445. d.incr();
  446. }
  447. d.release();
  448. InputOutIterator end = ::boost::move(first, last, original_r_first);
  449. BOOST_ASSERT(end == r_last);
  450. (void)end;
  451. return;
  452. }
  453. else if (comp(*r_first, *first)) {
  454. ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*r_first));
  455. d.incr();
  456. ++r_first;
  457. }
  458. else {
  459. ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
  460. d.incr();
  461. ++first;
  462. }
  463. ++dest_first;
  464. }
  465. d.release();
  466. merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp);
  467. }
  468. /*
  469. // [r_first, r_last) are already in the right part of the destination range.
  470. // [dest_first, r_first) is uninitialized memory
  471. template <class Compare, class BidirOutIterator, class BidirIterator>
  472. void uninitialized_merge_with_left_placed
  473. ( BidirOutIterator dest_first, BidirOutIterator r_first, BidirOutIterator r_last
  474. , BidirIterator first, BidirIterator last
  475. , Compare comp)
  476. {
  477. BOOST_ASSERT((last - first) == (r_last - r_first));
  478. typedef typename iterator_traits<BidirOutIterator>::value_type value_type;
  479. BidirOutIterator const original_r_last = r_last;
  480. destruct_n<value_type> d(&*dest_last);
  481. while ( first != last && dest_first != original_r_first ) {
  482. if (r_first == r_last) {
  483. for(; dest_first != original_r_first; ++dest_first, ++first){
  484. ::new(&*dest_first) value_type(::boost::move(*first));
  485. d.incr();
  486. }
  487. d.release();
  488. BidirOutIterator end = ::boost::move(first, last, original_r_first);
  489. BOOST_ASSERT(end == r_last);
  490. (void)end;
  491. return;
  492. }
  493. else if (comp(*r_first, *first)) {
  494. ::new(&*dest_first) value_type(::boost::move(*r_first));
  495. d.incr();
  496. ++r_first;
  497. }
  498. else {
  499. ::new(&*dest_first) value_type(::boost::move(*first));
  500. d.incr();
  501. ++first;
  502. }
  503. ++dest_first;
  504. }
  505. d.release();
  506. merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp);
  507. }
  508. */
  509. } //namespace movelib {
  510. } //namespace boost {
  511. #endif //#define BOOST_MOVE_MERGE_HPP