merge.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. //----------------------------------------------------------------------------
  2. /// @file merge.hpp
  3. /// @brief low level merge functions
  4. ///
  5. /// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
  6. /// Distributed under the Boost Software License, Version 1.0.\n
  7. /// ( See accompanying file LICENSE_1_0.txt or copy at
  8. /// http://www.boost.org/LICENSE_1_0.txt )
  9. /// @version 0.1
  10. ///
  11. /// @remarks
  12. //-----------------------------------------------------------------------------
  13. #ifndef __BOOST_SORT_COMMON_UTIL_MERGE_HPP
  14. #define __BOOST_SORT_COMMON_UTIL_MERGE_HPP
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iterator>
  18. #include <memory>
  19. #include <boost/sort/common/util/algorithm.hpp>
  20. #include <boost/sort/common/util/traits.hpp>
  21. #include <boost/sort/common/util/circular_buffer.hpp>
  22. namespace boost
  23. {
  24. namespace sort
  25. {
  26. namespace common
  27. {
  28. namespace util
  29. {
  30. namespace here = boost::sort::common::util;
  31. //----------------------------------------------------------------------------
  32. //
  33. // F U N C T I O N S I N T H E F I L E
  34. //----------------------------------------------------------------------------
  35. //
  36. // template < class Iter1_t, class Iter2_t, class Compare >
  37. // Iter2_t merge (Iter1_t buf1, const Iter1_t end_buf1, Iter1_t buf2,
  38. // const Iter1_t end_buf2, Iter2_t buf_out, Compare comp)
  39. //
  40. // template < class Iter_t, class Value_t, class Compare >
  41. // Value_t *merge_construct (Iter_t first1, const Iter_t last1, Iter_t first2,
  42. // const Iter_t last2, Value_t *it_out, Compare comp)
  43. //
  44. // template < class Iter1_t, class Iter2_t, class Compare >
  45. // Iter2_t merge_half (Iter1_t buf1, const Iter1_t end_buf1, Iter2_t buf2,
  46. // const Iter2_t end_buf2, Iter2_t buf_out, Compare comp)
  47. //
  48. // template < class Iter1_t, class Iter2_t, class Compare >
  49. // Iter2_t merge_half_backward (Iter1_t buf1, Iter1_t end_buf1,
  50. // Iter2_t buf2, Iter2_t end_buf2,
  51. // Iter1_t end_buf_out, Compare comp)
  52. //
  53. // template < class Iter1_t, class Iter2_t, class Iter3_t, class Compare >
  54. // bool merge_uncontiguous (Iter1_t src1, const Iter1_t end_src1,
  55. // Iter2_t src2, const Iter2_t end_src2,
  56. // Iter3_t aux, Compare comp)
  57. //
  58. // template < class Iter1_t, class Iter2_t, class Compare >
  59. // bool merge_contiguous (Iter1_t src1, Iter1_t src2, Iter1_t end_src2,
  60. // Iter2_t buf, Compare comp)
  61. //
  62. // template < class Iter_t, class Circular ,class Compare >
  63. // bool merge_circular (Iter_t buf1, Iter_t end_buf1,
  64. // Iter_t buf2, Iter_t end_buf2,
  65. // Circular &circ, Compare comp, Iter_t &it_aux)
  66. //
  67. //----------------------------------------------------------------------------
  68. //
  69. //-----------------------------------------------------------------------------
  70. // function : merge
  71. /// @brief Merge two contiguous buffers pointed by buf1 and buf2, and put
  72. /// in the buffer pointed by buf_out
  73. ///
  74. /// @param buf1 : iterator to the first element in the first buffer
  75. /// @param end_buf1 : final iterator of first buffer
  76. /// @param buf2 : iterator to the first iterator to the second buffer
  77. /// @param end_buf2 : final iterator of the second buffer
  78. /// @param buf_out : buffer where move the elements merged
  79. /// @param comp : comparison object
  80. //-----------------------------------------------------------------------------
  81. template<class Iter1_t, class Iter2_t, class Iter3_t, class Compare>
  82. static Iter3_t merge(Iter1_t buf1, const Iter1_t end_buf1, Iter2_t buf2,
  83. const Iter2_t end_buf2, Iter3_t buf_out, Compare comp)
  84. {
  85. //-------------------------------------------------------------------------
  86. // Metaprogramming
  87. //-------------------------------------------------------------------------
  88. typedef value_iter<Iter1_t> value1_t;
  89. typedef value_iter<Iter2_t> value2_t;
  90. typedef value_iter<Iter3_t> value3_t;
  91. static_assert (std::is_same< value1_t, value2_t >::value,
  92. "Incompatible iterators\n");
  93. static_assert (std::is_same< value3_t, value2_t >::value,
  94. "Incompatible iterators\n");
  95. //-------------------------------------------------------------------------
  96. // Code
  97. //-------------------------------------------------------------------------
  98. const size_t MIN_CHECK = 1024;
  99. if (size_t((end_buf1 - buf1) + (end_buf2 - buf2)) >= MIN_CHECK)
  100. {
  101. if (buf1 == end_buf1) return move_forward(buf_out, buf2, end_buf2);
  102. if (buf2 == end_buf2) return move_forward(buf_out, buf1, end_buf1);
  103. if (not comp(*buf2, *(end_buf1 - 1)))
  104. {
  105. Iter3_t mid = move_forward(buf_out, buf1, end_buf1);
  106. return move_forward(mid, buf2, end_buf2);
  107. };
  108. if (comp(*(end_buf2 - 1), *buf1))
  109. {
  110. Iter3_t mid = move_forward(buf_out, buf2, end_buf2);
  111. return move_forward(mid, buf1, end_buf1);
  112. };
  113. };
  114. while ((buf1 != end_buf1) and (buf2 != end_buf2))
  115. {
  116. *(buf_out++) = (not comp(*buf2, *buf1)) ?
  117. std::move(*(buf1++)) : std::move(*(buf2++));
  118. };
  119. return (buf1 == end_buf1) ?
  120. move_forward(buf_out, buf2, end_buf2) :
  121. move_forward(buf_out, buf1, end_buf1);
  122. }
  123. ;
  124. //
  125. //-----------------------------------------------------------------------------
  126. // function : merge_construct
  127. /// @brief Merge two contiguous buffers pointed by first1 and first2, and put
  128. /// in the uninitialized buffer pointed by it_out
  129. ///
  130. /// @param first1 : iterator to the first element in the first buffer
  131. /// @param last1 : last iterator of the first buffer
  132. /// @param first2 : iterator to the first element to the second buffer
  133. /// @param last2 : final iterator of the second buffer
  134. /// @param it_out : uninitialized buffer where move the elements merged
  135. /// @param comp : comparison object
  136. //-----------------------------------------------------------------------------
  137. template<class Iter1_t, class Iter2_t, class Value_t, class Compare>
  138. static Value_t *merge_construct(Iter1_t first1, const Iter1_t last1,
  139. Iter2_t first2, const Iter2_t last2,
  140. Value_t *it_out, Compare comp)
  141. {
  142. //-------------------------------------------------------------------------
  143. // Metaprogramming
  144. //-------------------------------------------------------------------------
  145. typedef value_iter<Iter1_t> type1;
  146. typedef value_iter<Iter2_t> type2;
  147. static_assert (std::is_same< Value_t, type1 >::value,
  148. "Incompatible iterators\n");
  149. static_assert (std::is_same< Value_t, type2 >::value,
  150. "Incompatible iterators\n");
  151. //-------------------------------------------------------------------------
  152. // Code
  153. //-------------------------------------------------------------------------
  154. const size_t MIN_CHECK = 1024;
  155. if (size_t((last1 - first1) + (last2 - first2)) >= MIN_CHECK)
  156. {
  157. if (first1 == last1) return move_construct(it_out, first2, last2);
  158. if (first2 == last2) return move_construct(it_out, first1, last1);
  159. if (not comp(*first2, *(last1 - 1)))
  160. {
  161. Value_t* mid = move_construct(it_out, first1, last1);
  162. return move_construct(mid, first2, last2);
  163. };
  164. if (comp(*(last2 - 1), *first1))
  165. {
  166. Value_t* mid = move_construct(it_out, first2, last2);
  167. return move_construct(mid, first1, last1);
  168. };
  169. };
  170. while (first1 != last1 and first2 != last2)
  171. {
  172. construct_object((it_out++),
  173. (not comp(*first2, *first1)) ?
  174. std::move(*(first1++)) :
  175. std::move(*(first2++)));
  176. };
  177. return (first1 == last1) ?
  178. move_construct(it_out, first2, last2) :
  179. move_construct(it_out, first1, last1);
  180. };
  181. //
  182. //---------------------------------------------------------------------------
  183. // function : merge_half
  184. /// @brief : Merge two buffers. The first buffer is in a separate memory.
  185. /// The second buffer have a empty space before buf2 of the same size
  186. /// than the (end_buf1 - buf1)
  187. ///
  188. /// @param buf1 : iterator to the first element of the first buffer
  189. /// @param end_buf1 : iterator to the last element of the first buffer
  190. /// @param buf2 : iterator to the first element of the second buffer
  191. /// @param end_buf2 : iterator to the last element of the second buffer
  192. /// @param buf_out : iterator to the first element to the buffer where put
  193. /// the result
  194. /// @param comp : object for Compare two elements of the type pointed
  195. /// by the Iter1_t and Iter2_t
  196. //---------------------------------------------------------------------------
  197. template<class Iter1_t, class Iter2_t, class Compare>
  198. static Iter2_t merge_half(Iter1_t buf1, const Iter1_t end_buf1, Iter2_t buf2,
  199. const Iter2_t end_buf2, Iter2_t buf_out, Compare comp)
  200. {
  201. //-------------------------------------------------------------------------
  202. // Metaprogramming
  203. //-------------------------------------------------------------------------
  204. typedef value_iter<Iter1_t> value1_t;
  205. typedef value_iter<Iter2_t> value2_t;
  206. static_assert (std::is_same< value1_t, value2_t >::value,
  207. "Incompatible iterators\n");
  208. //-------------------------------------------------------------------------
  209. // Code
  210. //-------------------------------------------------------------------------
  211. #ifdef __BS_DEBUG
  212. assert ( (buf2 - buf_out) == ( end_buf1 - buf1));
  213. #endif
  214. const size_t MIN_CHECK = 1024;
  215. if (size_t((end_buf1 - buf1) + (end_buf2 - buf2)) >= MIN_CHECK)
  216. {
  217. if (buf1 == end_buf1) return end_buf2;
  218. if (buf2 == end_buf2) return move_forward(buf_out, buf1, end_buf1);
  219. if (not comp(*buf2, *(end_buf1 - 1)))
  220. {
  221. move_forward(buf_out, buf1, end_buf1);
  222. return end_buf2;
  223. };
  224. if (comp(*(end_buf2 - 1), *buf1))
  225. {
  226. Iter2_t mid = move_forward(buf_out, buf2, end_buf2);
  227. return move_forward(mid, buf1, end_buf1);
  228. };
  229. };
  230. while ((buf1 != end_buf1) and (buf2 != end_buf2))
  231. {
  232. *(buf_out++) = (not comp(*buf2, *buf1)) ?
  233. std::move(*(buf1++)) : std::move(*(buf2++));
  234. };
  235. return (buf2 == end_buf2)? move_forward(buf_out, buf1, end_buf1) : end_buf2;
  236. };
  237. //
  238. //---------------------------------------------------------------------------
  239. // function : merge_half_backward
  240. /// @brief : Merge two buffers. The first buffer is in a separate memory.
  241. /// The second buffer have a empty space before buf2 of the same size
  242. /// than the (end_buf1 - buf1)
  243. ///
  244. /// @param buf1 : iterator to the first element of the first buffer
  245. /// @param end_buf1 : iterator to the last element of the first buffer
  246. /// @param buf2 : iterator to the first element of the second buffer
  247. /// @param end_buf2 : iterator to the last element of the second buffer
  248. /// @param buf_out : iterator to the first element to the buffer where put
  249. /// the result
  250. /// @param comp : object for Compare two elements of the type pointed
  251. /// by the Iter1_t and Iter2_t
  252. //---------------------------------------------------------------------------
  253. template<class Iter1_t, class Iter2_t, class Compare>
  254. static Iter2_t merge_half_backward(Iter1_t buf1, Iter1_t end_buf1, Iter2_t buf2,
  255. Iter2_t end_buf2, Iter1_t end_buf_out,
  256. Compare comp)
  257. {
  258. //-------------------------------------------------------------------------
  259. // Metaprogramming
  260. //-------------------------------------------------------------------------
  261. typedef value_iter<Iter1_t> value1_t;
  262. typedef value_iter<Iter2_t> value2_t;
  263. static_assert (std::is_same< value1_t, value2_t >::value,
  264. "Incompatible iterators\n");
  265. //-------------------------------------------------------------------------
  266. // Code
  267. //-------------------------------------------------------------------------
  268. #ifdef __BS_DEBUG
  269. assert ((end_buf_out - end_buf1) == (end_buf2 - buf2) );
  270. #endif
  271. const size_t MIN_CHECK = 1024;
  272. if (size_t((end_buf1 - buf1) + (end_buf2 - buf2)) >= MIN_CHECK)
  273. {
  274. if (buf2 == end_buf2) return buf1;
  275. if (buf1 == end_buf1)
  276. return here::move_backward(end_buf_out, buf2, end_buf2);
  277. if (not comp(*buf2, *(end_buf1 - 1)))
  278. {
  279. here::move_backward(end_buf_out, buf2, end_buf2);
  280. return buf1;
  281. };
  282. if (comp(*(end_buf2 - 1), *buf1))
  283. {
  284. Iter1_t mid = here::move_backward(end_buf_out, buf1, end_buf1);
  285. return here::move_backward(mid, buf2, end_buf2);
  286. };
  287. };
  288. while ((buf1 != end_buf1) and (buf2 != end_buf2))
  289. {
  290. *(--end_buf_out) =
  291. (not comp(*(end_buf2 - 1), *(end_buf1 - 1))) ?
  292. std::move(*(--end_buf2)):
  293. std::move(*(--end_buf1));
  294. };
  295. return (buf1 == end_buf1) ?
  296. here::move_backward(end_buf_out, buf2, end_buf2) : buf1;
  297. };
  298. //
  299. //-----------------------------------------------------------------------------
  300. // function : merge_uncontiguous
  301. /// @brief : merge two uncontiguous buffers, placing the results in the buffers
  302. /// Use an auxiliary buffer pointed by aux
  303. ///
  304. /// @param src1 : iterator to the first element of the first buffer
  305. /// @param end_src1 : last iterator of the first buffer
  306. /// @param src2 : iterator to the first element of the second buffer
  307. /// @param end_src2 : last iterator of the second buffer
  308. /// @param aux : iterator to the first element of the auxiliary buffer
  309. /// @param comp : object for to Compare elements
  310. /// @return true : not changes done, false : changes in the buffers
  311. /// @remarks
  312. //-----------------------------------------------------------------------------
  313. template<class Iter1_t, class Iter2_t, class Iter3_t, class Compare>
  314. static bool merge_uncontiguous(Iter1_t src1, const Iter1_t end_src1,
  315. Iter2_t src2, const Iter2_t end_src2,
  316. Iter3_t aux, Compare comp)
  317. {
  318. //-------------------------------------------------------------------------
  319. // Metaprogramming
  320. //-------------------------------------------------------------------------
  321. typedef value_iter<Iter1_t> type1;
  322. typedef value_iter<Iter2_t> type2;
  323. typedef value_iter<Iter3_t> type3;
  324. static_assert (std::is_same< type1, type2 >::value,
  325. "Incompatible iterators\n");
  326. static_assert (std::is_same< type3, type2 >::value,
  327. "Incompatible iterators\n");
  328. //-------------------------------------------------------------------------
  329. // Code
  330. //-------------------------------------------------------------------------
  331. if (src1 == end_src1 or src2 == end_src2
  332. or not comp(*src2, *(end_src1 - 1))) return true;
  333. while (src1 != end_src1 and not comp(*src2, *src1))
  334. ++src1;
  335. Iter3_t const end_aux = aux + (end_src1 - src1);
  336. Iter2_t src2_first = src2;
  337. move_forward(aux, src1, end_src1);
  338. while ((src1 != end_src1) and (src2 != end_src2))
  339. {
  340. *(src1++) = std::move((not comp(*src2, *aux)) ? *(aux++) : *(src2++));
  341. }
  342. if (src2 == end_src2)
  343. {
  344. while (src1 != end_src1)
  345. *(src1++) = std::move(*(aux++));
  346. move_forward(src2_first, aux, end_aux);
  347. }
  348. else
  349. {
  350. merge_half(aux, end_aux, src2, end_src2, src2_first, comp);
  351. };
  352. return false;
  353. };
  354. //
  355. //-----------------------------------------------------------------------------
  356. // function : merge_contiguous
  357. /// @brief : merge two contiguous buffers,using an auxiliary buffer pointed
  358. /// by buf. The results are in src1 and src2
  359. ///
  360. /// @param src1: iterator to the first position of the first buffer
  361. /// @param src2: final iterator of the first buffer and first iterator
  362. /// of the second buffer
  363. /// @param end_src2 : final iterator of the second buffer
  364. /// @param buf : iterator to buffer used as auxiliary memory
  365. /// @param comp : object for to Compare elements
  366. /// @return true : not changes done, false : changes in the buffers
  367. //-----------------------------------------------------------------------------
  368. template<class Iter1_t, class Iter2_t, class Compare>
  369. static bool merge_contiguous(Iter1_t src1, Iter1_t src2, Iter1_t end_src2,
  370. Iter2_t buf, Compare comp)
  371. {
  372. //-------------------------------------------------------------------------
  373. // Metaprogramming
  374. //-------------------------------------------------------------------------
  375. typedef value_iter<Iter1_t> type1;
  376. typedef value_iter<Iter2_t> type2;
  377. static_assert (std::is_same< type1, type2 >::value,
  378. "Incompatible iterators\n");
  379. //-------------------------------------------------------------------------
  380. // Code
  381. //-------------------------------------------------------------------------
  382. if (src1 == src2 or src2 == end_src2 or not comp(*src2, *(src2 - 1)))
  383. return true;
  384. Iter1_t end_src1 = src2;
  385. while (src1 != end_src1 and not comp(*src2, *src1))
  386. ++src1;
  387. if (src1 == end_src1) return false;
  388. size_t nx = end_src1 - src1;
  389. move_forward(buf, src1, end_src1);
  390. merge_half(buf, buf + nx, src2, end_src2, src1, comp);
  391. return false;
  392. };
  393. //
  394. //-----------------------------------------------------------------------------
  395. // function : merge_circular
  396. /// @brief : merge two buffers,using a circular buffer
  397. /// This function don't check the parameters
  398. /// @param buf1: iterator to the first position of the first buffer
  399. /// @param end_buf1: iterator after the last element of the first buffer
  400. /// @param buf2: iterator to the first element of the secind buffer
  401. /// @param end_buf2: iterator to the first element of the secind buffer
  402. /// @param circ : circular buffer
  403. /// @param comp : comparison object
  404. /// @return true : finished buf1, false : finished buf2
  405. /// @comments : be carefully because the iterators buf1 and buf2 are modified
  406. //-----------------------------------------------------------------------------
  407. template<class Iter1_t, class Iter2_t, class Circular, class Compare>
  408. static bool merge_circular(Iter1_t buf1, Iter1_t end_buf1, Iter2_t buf2,
  409. Iter2_t end_buf2, Circular &circ, Compare comp,
  410. Iter1_t &it1_out, Iter2_t &it2_out)
  411. {
  412. //-------------------------------------------------------------------------
  413. // Metaprogramming
  414. //-------------------------------------------------------------------------
  415. typedef value_iter<Iter1_t> type1;
  416. typedef value_iter<Iter2_t> type2;
  417. static_assert (std::is_same< type1, type2 >::value,
  418. "Incompatible iterators\n");
  419. typedef typename Circular::value_t type3;
  420. static_assert (std::is_same<type1, type3>::value,
  421. "Incompatible iterators\n");
  422. //-------------------------------------------------------------------------
  423. // Code
  424. //-------------------------------------------------------------------------
  425. #ifdef __BS_DEBUG
  426. assert ( circ.free_size() >= size_t ((end_buf1-buf1) + (end_buf2-buf2)));
  427. #endif
  428. if (not comp(*buf2, *(end_buf1 - 1)))
  429. {
  430. circ.push_move_back(buf1, (end_buf1 - buf1));
  431. it1_out = end_buf1;
  432. it2_out = buf2;
  433. return true;
  434. };
  435. if (comp(*(end_buf2 - 1), *buf1))
  436. {
  437. circ.push_move_back(buf2, (end_buf2 - buf2));
  438. it1_out = buf1;
  439. it2_out = end_buf2;
  440. return false;
  441. }
  442. while (buf1 != end_buf1 and buf2 != end_buf2)
  443. {
  444. circ.push_back(comp(*buf2, *buf1) ? std::move(*(buf2++))
  445. : std::move(*(buf1++)));
  446. };
  447. it2_out = buf2;
  448. it1_out = buf1;
  449. bool ret = (buf1 == end_buf1);
  450. return ret;
  451. };
  452. //
  453. //****************************************************************************
  454. };// End namespace util
  455. };// End namespace common
  456. };// End namespace sort
  457. };// End namespace boost
  458. //****************************************************************************
  459. //
  460. #endif