merge.hpp 20 KB

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