merge_four.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. //----------------------------------------------------------------------------
  2. /// @file merge_four.hpp
  3. /// @brief This file have the functions for to merge 4 buffers
  4. ///
  5. /// @author Copyright (c) 2016 Francisco José 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_PARALLEL_DETAIL_UTIL_MERGE_FOUR_HPP
  14. #define __BOOST_SORT_PARALLEL_DETAIL_UTIL_MERGE_FOUR_HPP
  15. #include <boost/sort/common/util/traits.hpp>
  16. #include <boost/sort/common/range.hpp>
  17. #include <functional>
  18. #include <iterator>
  19. #include <memory>
  20. #include <vector>
  21. namespace boost
  22. {
  23. namespace sort
  24. {
  25. namespace common
  26. {
  27. //
  28. //############################################################################
  29. // ##
  30. // F U S I O N O F ##
  31. // ##
  32. // F O U R E L E M E N T S R A N G E ##
  33. // ##
  34. //############################################################################
  35. //
  36. //-----------------------------------------------------------------------------
  37. // function : less_range
  38. /// @brief Compare the elements pointed by it1 and it2, and if they
  39. /// are equals, compare their position, doing a stable comparison
  40. ///
  41. /// @param it1 : iterator to the first element
  42. /// @param pos1 : position of the object pointed by it1
  43. /// @param it2 : iterator to the second element
  44. /// @param pos2 : position of the element pointed by it2
  45. /// @param comp : comparison object
  46. /// @return result of the comparison
  47. //-----------------------------------------------------------------------------
  48. template<class Iter_t, class Compare = typename util::compare_iter<Iter_t> >
  49. inline bool less_range(Iter_t it1, uint32_t pos1, Iter_t it2, uint32_t pos2,
  50. Compare comp = Compare())
  51. {
  52. return (comp(*it1, *it2)) ? true :
  53. (pos2 < pos1) ? false : not (comp(*it2, *it1));
  54. };
  55. //-----------------------------------------------------------------------------
  56. // function : full_merge4
  57. /// @brief Merge four ranges
  58. ///
  59. /// @param dest: range where move the elements merged. Their size must be
  60. /// greater or equal than the sum of the sizes of the ranges
  61. /// in vrange_input
  62. /// @param vrange_input : array of ranges to merge
  63. /// @param nrange_input : number of ranges in vrange_input
  64. /// @param comp : comparison object
  65. /// @return range with all the elements moved with the size adjusted
  66. //-----------------------------------------------------------------------------
  67. template<class Iter1_t, class Iter2_t, class Compare>
  68. range<Iter1_t> full_merge4(const range<Iter1_t> &rdest,
  69. range<Iter2_t> vrange_input[4],
  70. uint32_t nrange_input, Compare comp)
  71. {
  72. typedef range<Iter1_t> range1_t;
  73. typedef util::value_iter<Iter1_t> type1;
  74. typedef util::value_iter<Iter2_t> type2;
  75. static_assert (std::is_same< type1, type2 >::value,
  76. "Incompatible iterators\n");
  77. size_t ndest = 0;
  78. uint32_t i = 0;
  79. while (i < nrange_input)
  80. {
  81. if (vrange_input[i].size() != 0)
  82. {
  83. ndest += vrange_input[i++].size();
  84. }
  85. else
  86. {
  87. for (uint32_t k = i + 1; k < nrange_input; ++k)
  88. {
  89. vrange_input[k - 1] = vrange_input[k];
  90. };
  91. --nrange_input;
  92. };
  93. };
  94. if (nrange_input == 0) return range1_t(rdest.first, rdest.first);
  95. if (nrange_input == 1) return move_forward(rdest, vrange_input[0]);
  96. if (nrange_input == 2)
  97. {
  98. return merge(rdest, vrange_input[0], vrange_input[1], comp);
  99. };
  100. //------------------------------------------------------------------------
  101. // Initial sort
  102. //------------------------------------------------------------------------
  103. uint32_t pos[4] =
  104. { 0, 1, 2, 3 }, npos = nrange_input;
  105. //-----------------------------------------------------------------------
  106. // thanks to Steven Ross by their suggestion about the optimal
  107. // sorting networks
  108. //-----------------------------------------------------------------------
  109. if (less_range(vrange_input[pos[1]].first, pos[1],
  110. vrange_input[pos[0]].first, pos[0], comp))
  111. {
  112. std::swap(pos[0], pos[1]);
  113. };
  114. if (npos == 4 and less_range(vrange_input[pos[3]].first, pos[3],
  115. vrange_input[pos[2]].first, pos[2], comp))
  116. {
  117. std::swap(pos[3], pos[2]);
  118. };
  119. if (less_range (vrange_input[pos[2]].first, pos[2],
  120. vrange_input[pos[0]].first, pos[0], comp))
  121. {
  122. std::swap(pos[0], pos[2]);
  123. };
  124. if (npos == 4
  125. and less_range (vrange_input[pos[3]].first, pos[3],
  126. vrange_input[pos[1]].first, pos[1], comp))
  127. {
  128. std::swap(pos[1], pos[3]);
  129. };
  130. if (less_range (vrange_input[pos[2]].first, pos[2],
  131. vrange_input[pos[1]].first, pos[1], comp))
  132. {
  133. std::swap(pos[1], pos[2]);
  134. };
  135. Iter1_t it_dest = rdest.first;
  136. while (npos > 2)
  137. {
  138. *(it_dest++) = std::move(*(vrange_input[pos[0]].first++));
  139. if (vrange_input[pos[0]].size() == 0)
  140. {
  141. pos[0] = pos[1];
  142. pos[1] = pos[2];
  143. pos[2] = pos[3];
  144. --npos;
  145. }
  146. else
  147. {
  148. if (less_range(vrange_input[pos[1]].first, pos[1],
  149. vrange_input[pos[0]].first, pos[0], comp))
  150. {
  151. std::swap(pos[0], pos[1]);
  152. if (less_range(vrange_input[pos[2]].first, pos[2],
  153. vrange_input[pos[1]].first, pos[1], comp))
  154. {
  155. std::swap(pos[1], pos[2]);
  156. if (npos == 4
  157. and less_range(vrange_input[pos[3]].first,
  158. pos[3],
  159. vrange_input[pos[2]].first,
  160. pos[2], comp))
  161. {
  162. std::swap(pos[2], pos[3]);
  163. };
  164. };
  165. };
  166. };
  167. };
  168. range1_t raux1(rdest.first, it_dest), raux2(it_dest, rdest.last);
  169. if (pos[0] < pos[1])
  170. {
  171. return concat(raux1,merge(raux2, vrange_input[pos[0]],
  172. vrange_input[pos[1]], comp));
  173. }
  174. else
  175. {
  176. return concat(raux1, merge (raux2, vrange_input[pos[1]],
  177. vrange_input[pos[0]], comp));
  178. };
  179. };
  180. //-----------------------------------------------------------------------------
  181. // function : uninit_full_merge4
  182. /// @brief Merge four ranges and put the result in uninitialized memory
  183. ///
  184. /// @param dest: range where create and move the elements merged. Their
  185. /// size must be greater or equal than the sum of the sizes
  186. /// of the ranges in the array R
  187. /// @param vrange_input : array of ranges to merge
  188. /// @param nrange_input : number of ranges in vrange_input
  189. /// @param comp : comparison object
  190. /// @return range with all the elements move with the size adjusted
  191. //-----------------------------------------------------------------------------
  192. template<class Value_t, class Iter_t, class Compare>
  193. range<Value_t *> uninit_full_merge4(const range<Value_t *> &dest,
  194. range<Iter_t> vrange_input[4],
  195. uint32_t nrange_input, Compare comp)
  196. {
  197. typedef util::value_iter<Iter_t> type1;
  198. static_assert (std::is_same< type1, Value_t >::value,
  199. "Incompatible iterators\n");
  200. size_t ndest = 0;
  201. uint32_t i = 0;
  202. while (i < nrange_input)
  203. {
  204. if (vrange_input[i].size() != 0)
  205. {
  206. ndest += vrange_input[i++].size();
  207. }
  208. else
  209. {
  210. for (uint32_t k = i + 1; k < nrange_input; ++k)
  211. {
  212. vrange_input[k - 1] = vrange_input[k];
  213. };
  214. --nrange_input;
  215. };
  216. };
  217. if (nrange_input == 0) return range<Value_t *>(dest.first, dest.first);
  218. if (nrange_input == 1) return move_construct(dest, vrange_input[0]);
  219. if (nrange_input == 2)
  220. {
  221. return merge_construct(dest, vrange_input[0], vrange_input[1], comp);
  222. };
  223. //------------------------------------------------------------------------
  224. // Initial sort
  225. //------------------------------------------------------------------------
  226. uint32_t pos[4] = { 0, 1, 2, 3 }, npos = nrange_input;
  227. //-----------------------------------------------------------------------
  228. // thanks to Steven Ross by their suggestion about the optimal
  229. // sorting networks
  230. //-----------------------------------------------------------------------
  231. if (less_range(vrange_input[pos[1]].first, pos[1],
  232. vrange_input[pos[0]].first, pos[0], comp))
  233. {
  234. std::swap(pos[0], pos[1]);
  235. };
  236. if (npos == 4 and less_range(vrange_input[pos[3]].first, pos[3],
  237. vrange_input[pos[2]].first, pos[2], comp))
  238. {
  239. std::swap(pos[3], pos[2]);
  240. };
  241. if (less_range(vrange_input[pos[2]].first, pos[2],
  242. vrange_input[pos[0]].first, pos[0], comp))
  243. {
  244. std::swap(pos[0], pos[2]);
  245. };
  246. if (npos == 4 and less_range(vrange_input[pos[3]].first, pos[3],
  247. vrange_input[pos[1]].first, pos[1], comp))
  248. {
  249. std::swap(pos[1], pos[3]);
  250. };
  251. if (less_range(vrange_input[pos[2]].first, pos[2],
  252. vrange_input[pos[1]].first, pos[1], comp))
  253. {
  254. std::swap(pos[1], pos[2]);
  255. };
  256. Value_t *it_dest = dest.first;
  257. while (npos > 2)
  258. {
  259. util::construct_object(&(*(it_dest++)),
  260. std::move(*(vrange_input[pos[0]].first++)));
  261. if (vrange_input[pos[0]].size() == 0)
  262. {
  263. pos[0] = pos[1];
  264. pos[1] = pos[2];
  265. pos[2] = pos[3];
  266. --npos;
  267. }
  268. else
  269. {
  270. if (less_range (vrange_input[pos[1]].first, pos[1],
  271. vrange_input[pos[0]].first, pos[0], comp))
  272. {
  273. std::swap(pos[0], pos[1]);
  274. if (less_range (vrange_input[pos[2]].first, pos[2],
  275. vrange_input[pos[1]].first, pos[1], comp))
  276. {
  277. std::swap(pos[1], pos[2]);
  278. if (npos == 4 and less_range(vrange_input[pos[3]].first,
  279. pos[3],
  280. vrange_input[pos[2]].first,
  281. pos[2], comp))
  282. {
  283. std::swap(pos[2], pos[3]);
  284. };
  285. };
  286. };
  287. };
  288. }; // end while (npos > 2)
  289. range<Value_t *> raux1(dest.first, it_dest), raux2(it_dest, dest.last);
  290. if (pos[0] < pos[1])
  291. {
  292. return concat(raux1,
  293. merge_construct(raux2, vrange_input[pos[0]],
  294. vrange_input[pos[1]], comp));
  295. }
  296. else
  297. {
  298. return concat(raux1,
  299. merge_construct(raux2, vrange_input[pos[1]],
  300. vrange_input[pos[0]], comp));
  301. };
  302. };
  303. //****************************************************************************
  304. };// End namespace common
  305. };// End namespace sort
  306. };// End namespace boost
  307. //****************************************************************************
  308. //
  309. #endif