merge.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  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/assert.hpp>
  19. namespace boost {
  20. namespace movelib {
  21. // @cond
  22. /*
  23. template<typename Unsigned>
  24. inline Unsigned gcd(Unsigned x, Unsigned y)
  25. {
  26. if(0 == ((x &(x-1)) | (y & (y-1)))){
  27. return x < y ? x : y;
  28. }
  29. else{
  30. do
  31. {
  32. Unsigned t = x % y;
  33. x = y;
  34. y = t;
  35. } while (y);
  36. return x;
  37. }
  38. }
  39. */
  40. //Modified version from "An Optimal In-Place Array Rotation Algorithm", Ching-Kuang Shene
  41. template<typename Unsigned>
  42. Unsigned gcd(Unsigned x, Unsigned y)
  43. {
  44. if(0 == ((x &(x-1)) | (y & (y-1)))){
  45. return x < y ? x : y;
  46. }
  47. else{
  48. Unsigned z = 1;
  49. while((!(x&1)) & (!(y&1))){
  50. z <<=1, x>>=1, y>>=1;
  51. }
  52. while(x && y){
  53. if(!(x&1))
  54. x >>=1;
  55. else if(!(y&1))
  56. y >>=1;
  57. else if(x >=y)
  58. x = (x-y) >> 1;
  59. else
  60. y = (y-x) >> 1;
  61. }
  62. return z*(x+y);
  63. }
  64. }
  65. template<typename RandIt>
  66. RandIt rotate_gcd(RandIt first, RandIt middle, RandIt last)
  67. {
  68. typedef typename iterator_traits<RandIt>::size_type size_type;
  69. typedef typename iterator_traits<RandIt>::value_type value_type;
  70. if(first == middle)
  71. return last;
  72. if(middle == last)
  73. return first;
  74. const size_type middle_pos = size_type(middle - first);
  75. RandIt ret = last - middle_pos;
  76. if (middle == ret){
  77. boost::adl_move_swap_ranges(first, middle, middle);
  78. }
  79. else{
  80. const size_type length = size_type(last - first);
  81. for( RandIt it_i(first), it_gcd(it_i + gcd(length, middle_pos))
  82. ; it_i != it_gcd
  83. ; ++it_i){
  84. value_type temp(boost::move(*it_i));
  85. RandIt it_j = it_i;
  86. RandIt it_k = it_j+middle_pos;
  87. do{
  88. *it_j = boost::move(*it_k);
  89. it_j = it_k;
  90. size_type const left = size_type(last - it_j);
  91. it_k = left > middle_pos ? it_j + middle_pos : first + (middle_pos - left);
  92. } while(it_k != it_i);
  93. *it_j = boost::move(temp);
  94. }
  95. }
  96. return ret;
  97. }
  98. template <class RandIt, class T, class Compare>
  99. RandIt lower_bound
  100. (RandIt first, const RandIt last, const T& key, Compare comp)
  101. {
  102. typedef typename iterator_traits
  103. <RandIt>::size_type size_type;
  104. size_type len = size_type(last - first);
  105. RandIt middle;
  106. while (len) {
  107. size_type step = len >> 1;
  108. middle = first;
  109. middle += step;
  110. if (comp(*middle, key)) {
  111. first = ++middle;
  112. len -= step + 1;
  113. }
  114. else{
  115. len = step;
  116. }
  117. }
  118. return first;
  119. }
  120. template <class RandIt, class T, class Compare>
  121. RandIt upper_bound
  122. (RandIt first, const RandIt last, const T& key, Compare comp)
  123. {
  124. typedef typename iterator_traits
  125. <RandIt>::size_type size_type;
  126. size_type len = size_type(last - first);
  127. RandIt middle;
  128. while (len) {
  129. size_type step = len >> 1;
  130. middle = first;
  131. middle += step;
  132. if (!comp(key, *middle)) {
  133. first = ++middle;
  134. len -= step + 1;
  135. }
  136. else{
  137. len = step;
  138. }
  139. }
  140. return first;
  141. }
  142. template<class RandIt, class Compare, class Op>
  143. void op_merge_left( RandIt buf_first
  144. , RandIt first1
  145. , RandIt const last1
  146. , RandIt const last2
  147. , Compare comp
  148. , Op op)
  149. {
  150. for(RandIt first2=last1; first2 != last2; ++buf_first){
  151. if(first1 == last1){
  152. op(forward_t(), first2, last2, buf_first);
  153. return;
  154. }
  155. else if(comp(*first2, *first1)){
  156. op(first2, buf_first);
  157. ++first2;
  158. }
  159. else{
  160. op(first1, buf_first);
  161. ++first1;
  162. }
  163. }
  164. if(buf_first != first1){//In case all remaining elements are in the same place
  165. //(e.g. buffer is exactly the size of the second half
  166. //and all elements from the second half are less)
  167. op(forward_t(), first1, last1, buf_first);
  168. }
  169. else{
  170. buf_first = buf_first;
  171. }
  172. }
  173. // [buf_first, first1) -> buffer
  174. // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
  175. // Elements from buffer are moved to [last2 - (first1-buf_first), last2)
  176. // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
  177. template<class RandIt, class Compare>
  178. void merge_left
  179. (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
  180. {
  181. op_merge_left(buf_first, first1, last1, last2, comp, move_op());
  182. }
  183. // [buf_first, first1) -> buffer
  184. // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
  185. // Elements from buffer are swapped to [last2 - (first1-buf_first), last2)
  186. // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
  187. template<class RandIt, class Compare>
  188. void swap_merge_left
  189. (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
  190. {
  191. op_merge_left(buf_first, first1, last1, last2, comp, swap_op());
  192. }
  193. template<class RandIt, class Compare, class Op>
  194. void op_merge_right
  195. (RandIt const first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp, Op op)
  196. {
  197. RandIt const first2 = last1;
  198. while(first1 != last1){
  199. if(last2 == first2){
  200. op(backward_t(), first1, last1, buf_last);
  201. return;
  202. }
  203. --last2;
  204. --last1;
  205. --buf_last;
  206. if(comp(*last2, *last1)){
  207. op(last1, buf_last);
  208. ++last2;
  209. }
  210. else{
  211. op(last2, buf_last);
  212. ++last1;
  213. }
  214. }
  215. if(last2 != buf_last){ //In case all remaining elements are in the same place
  216. //(e.g. buffer is exactly the size of the first half
  217. //and all elements from the second half are less)
  218. op(backward_t(), first2, last2, buf_last);
  219. }
  220. }
  221. // [last2, buf_last) - buffer
  222. // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
  223. // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
  224. template<class RandIt, class Compare>
  225. void merge_right
  226. (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
  227. {
  228. op_merge_right(first1, last1, last2, buf_last, comp, move_op());
  229. }
  230. // [last2, buf_last) - buffer
  231. // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
  232. // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
  233. template<class RandIt, class Compare>
  234. void swap_merge_right
  235. (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
  236. {
  237. op_merge_right(first1, last1, last2, buf_last, comp, swap_op());
  238. }
  239. // cost: min(L1,L2)^2+max(L1,L2)
  240. template<class RandIt, class Compare>
  241. void merge_bufferless(RandIt first, RandIt middle, RandIt last, Compare comp)
  242. {
  243. if((middle - first) < (last - middle)){
  244. while(first != middle){
  245. RandIt const old_last1 = middle;
  246. middle = lower_bound(middle, last, *first, comp);
  247. first = rotate_gcd(first, old_last1, middle);
  248. if(middle == last){
  249. break;
  250. }
  251. do{
  252. ++first;
  253. } while(first != middle && !comp(*middle, *first));
  254. }
  255. }
  256. else{
  257. while(middle != last){
  258. RandIt p = upper_bound(first, middle, last[-1], comp);
  259. last = rotate_gcd(p, middle, last);
  260. middle = p;
  261. if(middle == first){
  262. break;
  263. }
  264. --p;
  265. do{
  266. --last;
  267. } while(middle != last && !comp(last[-1], *p));
  268. }
  269. }
  270. }
  271. template<class Comp>
  272. struct antistable
  273. {
  274. antistable(Comp &comp)
  275. : m_comp(comp)
  276. {}
  277. template<class U, class V>
  278. bool operator()(const U &u, const V & v)
  279. { return !m_comp(v, u); }
  280. private:
  281. antistable & operator=(const antistable &);
  282. Comp &m_comp;
  283. };
  284. // [r_first, r_last) are already in the right part of the destination range.
  285. template <class Compare, class InputIterator, class InputOutIterator, class Op>
  286. void op_merge_with_right_placed
  287. ( InputIterator first, InputIterator last
  288. , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
  289. , Compare comp, Op op)
  290. {
  291. BOOST_ASSERT((last - first) == (r_first - dest_first));
  292. while ( first != last ) {
  293. if (r_first == r_last) {
  294. InputOutIterator end = op(forward_t(), first, last, dest_first);
  295. BOOST_ASSERT(end == r_last);
  296. (void)end;
  297. return;
  298. }
  299. else if (comp(*r_first, *first)) {
  300. op(r_first, dest_first);
  301. ++r_first;
  302. }
  303. else {
  304. op(first, dest_first);
  305. ++first;
  306. }
  307. ++dest_first;
  308. }
  309. // Remaining [r_first, r_last) already in the correct place
  310. }
  311. template <class Compare, class InputIterator, class InputOutIterator>
  312. void swap_merge_with_right_placed
  313. ( InputIterator first, InputIterator last
  314. , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
  315. , Compare comp)
  316. {
  317. op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, swap_op());
  318. }
  319. // [r_first, r_last) are already in the right part of the destination range.
  320. template <class Compare, class Op, class BidirIterator, class BidirOutIterator>
  321. void op_merge_with_left_placed
  322. ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
  323. , BidirIterator const r_first, BidirIterator r_last
  324. , Compare comp, Op op)
  325. {
  326. BOOST_ASSERT((dest_last - last) == (r_last - r_first));
  327. while( r_first != r_last ) {
  328. if(first == last) {
  329. BidirOutIterator res = op(backward_t(), r_first, r_last, dest_last);
  330. BOOST_ASSERT(last == res);
  331. (void)res;
  332. return;
  333. }
  334. --r_last;
  335. --last;
  336. if(comp(*r_last, *last)){
  337. ++r_last;
  338. --dest_last;
  339. op(last, dest_last);
  340. }
  341. else{
  342. ++last;
  343. --dest_last;
  344. op(r_last, dest_last);
  345. }
  346. }
  347. // Remaining [first, last) already in the correct place
  348. }
  349. // @endcond
  350. // [r_first, r_last) are already in the right part of the destination range.
  351. template <class Compare, class BidirIterator, class BidirOutIterator>
  352. void merge_with_left_placed
  353. ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
  354. , BidirIterator const r_first, BidirIterator r_last
  355. , Compare comp)
  356. {
  357. op_merge_with_left_placed(first, last, dest_last, r_first, r_last, comp, move_op());
  358. }
  359. // [r_first, r_last) are already in the right part of the destination range.
  360. template <class Compare, class InputIterator, class InputOutIterator>
  361. void merge_with_right_placed
  362. ( InputIterator first, InputIterator last
  363. , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
  364. , Compare comp)
  365. {
  366. op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, move_op());
  367. }
  368. // [r_first, r_last) are already in the right part of the destination range.
  369. // [dest_first, r_first) is uninitialized memory
  370. template <class Compare, class InputIterator, class InputOutIterator>
  371. void uninitialized_merge_with_right_placed
  372. ( InputIterator first, InputIterator last
  373. , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
  374. , Compare comp)
  375. {
  376. BOOST_ASSERT((last - first) == (r_first - dest_first));
  377. typedef typename iterator_traits<InputOutIterator>::value_type value_type;
  378. InputOutIterator const original_r_first = r_first;
  379. destruct_n<value_type> d(&*dest_first);
  380. while ( first != last && dest_first != original_r_first ) {
  381. if (r_first == r_last) {
  382. for(; dest_first != original_r_first; ++dest_first, ++first){
  383. ::new(&*dest_first) value_type(::boost::move(*first));
  384. d.incr();
  385. }
  386. d.release();
  387. InputOutIterator end = ::boost::move(first, last, original_r_first);
  388. BOOST_ASSERT(end == r_last);
  389. (void)end;
  390. return;
  391. }
  392. else if (comp(*r_first, *first)) {
  393. ::new(&*dest_first) value_type(::boost::move(*r_first));
  394. d.incr();
  395. ++r_first;
  396. }
  397. else {
  398. ::new(&*dest_first) value_type(::boost::move(*first));
  399. d.incr();
  400. ++first;
  401. }
  402. ++dest_first;
  403. }
  404. d.release();
  405. merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp);
  406. }
  407. } //namespace movelib {
  408. } //namespace boost {
  409. #endif //#define BOOST_MOVE_MERGE_HPP