move_blocks.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. //----------------------------------------------------------------------------
  2. /// @file move_blocks.hpp
  3. /// @brief contains the class move_blocks, which is part of the
  4. /// block_indirect_sort algorithm
  5. ///
  6. /// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
  7. /// Distributed under the Boost Software License, Version 1.0.\n
  8. /// ( See accompanying file LICENSE_1_0.txt or copy at
  9. /// http://www.boost.org/LICENSE_1_0.txt )
  10. /// @version 0.1
  11. ///
  12. /// @remarks
  13. //-----------------------------------------------------------------------------
  14. #ifndef __BOOST_SORT_PARALLEL_DETAIL_MOVE_BLOCKS_HPP
  15. #define __BOOST_SORT_PARALLEL_DETAIL_MOVE_BLOCKS_HPP
  16. #include <atomic>
  17. #include <boost/sort/block_indirect_sort/blk_detail/backbone.hpp>
  18. #include <future>
  19. #include <iostream>
  20. #include <iterator>
  21. namespace boost
  22. {
  23. namespace sort
  24. {
  25. namespace blk_detail
  26. {
  27. //----------------------------------------------------------------------------
  28. // USING SENTENCES
  29. //----------------------------------------------------------------------------
  30. namespace bsc = boost::sort::common;
  31. //
  32. ///---------------------------------------------------------------------------
  33. /// @struct move_blocks
  34. /// @brief This class move the blocks, trnasforming a logical sort by an index,
  35. /// in physical sort
  36. //----------------------------------------------------------------------------
  37. template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
  38. struct move_blocks
  39. {
  40. //-------------------------------------------------------------------------
  41. // D E F I N I T I O N S
  42. //-------------------------------------------------------------------------
  43. typedef move_blocks<Block_size, Group_size, Iter_t, Compare> this_type;
  44. typedef typename std::iterator_traits<Iter_t>::value_type value_t;
  45. typedef std::atomic<uint32_t> atomic_t;
  46. typedef bsc::range<size_t> range_pos;
  47. typedef bsc::range<Iter_t> range_it;
  48. typedef bsc::range<value_t *> range_buf;
  49. typedef std::function<void(void)> function_t;
  50. typedef backbone<Block_size, Iter_t, Compare> backbone_t;
  51. //------------------------------------------------------------------------
  52. // V A R I A B L E S
  53. //------------------------------------------------------------------------
  54. // Object with the elements to sort and all internal data structures of the
  55. // algorithm
  56. backbone_t &bk;
  57. //------------------------------------------------------------------------
  58. // F U N C T I O N S
  59. //------------------------------------------------------------------------
  60. move_blocks(backbone_t &bkb);
  61. void move_sequence(const std::vector<size_t> &init_sequence);
  62. void move_long_sequence(const std::vector<size_t> &init_sequence);
  63. //
  64. //------------------------------------------------------------------------
  65. // function : function_move_sequence
  66. /// @brief create a function_t with a call to move_sequence, and insert
  67. /// in the stack of the backbone
  68. ///
  69. /// @param sequence :sequence of positions for to move the blocks
  70. /// @param counter : atomic variable which is decremented when finish
  71. /// the function. This variable is used for to know
  72. /// when are finished all the function_t created
  73. /// inside an object
  74. /// @param error : global indicator of error.
  75. //------------------------------------------------------------------------
  76. void function_move_sequence(std::vector<size_t> &sequence,
  77. atomic_t &counter, bool &error)
  78. {
  79. bscu::atomic_add(counter, 1);
  80. function_t f1 = [this, sequence, &counter, &error]( ) -> void
  81. {
  82. if (not error)
  83. {
  84. try
  85. {
  86. this->move_sequence (sequence);
  87. }
  88. catch (std::bad_alloc &)
  89. {
  90. error = true;
  91. };
  92. }
  93. bscu::atomic_sub (counter, 1);
  94. };
  95. bk.works.emplace_back(f1);
  96. }
  97. //
  98. //------------------------------------------------------------------------
  99. // function : function_move_long_sequence
  100. /// @brief create a function_t with a call to move_long_sequence, and
  101. /// insert in the stack of the backbone
  102. //
  103. /// @param sequence :sequence of positions for to move the blocks
  104. /// @param counter : atomic variable which is decremented when finish
  105. /// the function. This variable is used for to know
  106. /// when are finished all the function_t created
  107. /// inside an object
  108. /// @param error : global indicator of error.
  109. //------------------------------------------------------------------------
  110. void function_move_long_sequence(std::vector<size_t> &sequence,
  111. atomic_t &counter, bool &error)
  112. {
  113. bscu::atomic_add(counter, 1);
  114. function_t f1 = [this, sequence, &counter, &error]( ) -> void
  115. {
  116. if (not error)
  117. {
  118. try
  119. {
  120. this->move_long_sequence (sequence);
  121. }
  122. catch (std::bad_alloc &)
  123. {
  124. error = true;
  125. };
  126. }
  127. bscu::atomic_sub (counter, 1);
  128. };
  129. bk.works.emplace_back(f1);
  130. }
  131. ;
  132. //---------------------------------------------------------------------------
  133. }; // end of struct move_blocks
  134. //---------------------------------------------------------------------------
  135. //
  136. //############################################################################
  137. // ##
  138. // ##
  139. // N O N I N L I N E F U N C T I O N S ##
  140. // ##
  141. // ##
  142. //############################################################################
  143. //
  144. //-------------------------------------------------------------------------
  145. // function : move_blocks
  146. /// @brief constructor of the class for to move the blocks to their true
  147. /// position obtained from the index
  148. //
  149. /// @param bkb : backbone with the index and the blocks
  150. //-------------------------------------------------------------------------
  151. template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
  152. move_blocks<Block_size, Group_size, Iter_t, Compare>
  153. ::move_blocks(backbone_t &bkb) : bk(bkb)
  154. {
  155. std::vector<std::vector<size_t> > vsequence;
  156. vsequence.reserve(bk.index.size() >> 1);
  157. std::vector<size_t> sequence;
  158. atomic_t counter(0);
  159. size_t pos_index_ini = 0, pos_index_src = 0, pos_index_dest = 0;
  160. while (pos_index_ini < bk.index.size())
  161. {
  162. while (pos_index_ini < bk.index.size()
  163. and bk.index[pos_index_ini].pos() == pos_index_ini)
  164. {
  165. ++pos_index_ini;
  166. };
  167. if (pos_index_ini == bk.index.size()) break;
  168. sequence.clear();
  169. pos_index_src = pos_index_dest = pos_index_ini;
  170. sequence.push_back(pos_index_ini);
  171. while (bk.index[pos_index_dest].pos() != pos_index_ini)
  172. {
  173. pos_index_src = bk.index[pos_index_dest].pos();
  174. sequence.push_back(pos_index_src);
  175. bk.index[pos_index_dest].set_pos(pos_index_dest);
  176. pos_index_dest = pos_index_src;
  177. };
  178. bk.index[pos_index_dest].set_pos(pos_index_dest);
  179. vsequence.push_back(sequence);
  180. if (sequence.size() < Group_size)
  181. {
  182. function_move_sequence(vsequence.back(), counter, bk.error);
  183. }
  184. else
  185. {
  186. function_move_long_sequence(vsequence.back(), counter, bk.error);
  187. };
  188. };
  189. bk.exec(counter);
  190. }
  191. ;
  192. //
  193. //-------------------------------------------------------------------------
  194. // function : move_sequence
  195. /// @brief move the blocks, following the positions of the init_sequence
  196. //
  197. /// @param init_sequence : vector with the positions from and where move the
  198. /// blocks
  199. //-------------------------------------------------------------------------
  200. template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
  201. void move_blocks<Block_size, Group_size, Iter_t, Compare>
  202. ::move_sequence(const std::vector<size_t> &init_sequence)
  203. {
  204. range_buf rbuf = bk.get_range_buf();
  205. size_t pos_range2 = init_sequence[0];
  206. range_it range2 = bk.get_range(pos_range2);
  207. move_forward(rbuf, range2);
  208. for (size_t i = 1; i < init_sequence.size(); ++i)
  209. {
  210. pos_range2 = init_sequence[i];
  211. range_it range1(range2);
  212. range2 = bk.get_range(pos_range2);
  213. move_forward(range1, range2);
  214. };
  215. move_forward(range2, rbuf);
  216. };
  217. //
  218. //-------------------------------------------------------------------------
  219. // function : move_long_sequence
  220. /// @brief move the blocks, following the positions of the init_sequence.
  221. /// if the sequence is greater than Group_size, it is divided in small
  222. /// sequences, creating function_t elements, for to be inserted in the
  223. /// concurrent stack
  224. //
  225. /// @param init_sequence : vector with the positions from and where move the
  226. /// blocks
  227. //-------------------------------------------------------------------------
  228. template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
  229. void move_blocks<Block_size, Group_size, Iter_t, Compare>
  230. ::move_long_sequence(const std::vector<size_t> &init_sequence)
  231. {
  232. if (init_sequence.size() < Group_size) return move_sequence(init_sequence);
  233. size_t npart = (init_sequence.size() + Group_size - 1) / Group_size;
  234. size_t size_part = init_sequence.size() / npart;
  235. atomic_t son_counter(0);
  236. std::vector<size_t> sequence;
  237. sequence.reserve(size_part);
  238. std::vector<size_t> index_seq;
  239. index_seq.reserve(npart);
  240. auto it_pos = init_sequence.begin();
  241. for (size_t i = 0; i < (npart - 1); ++i, it_pos += size_part)
  242. {
  243. sequence.assign(it_pos, it_pos + size_part);
  244. index_seq.emplace_back(*(it_pos + size_part - 1));
  245. function_move_sequence(sequence, son_counter, bk.error);
  246. };
  247. sequence.assign(it_pos, init_sequence.end());
  248. index_seq.emplace_back(init_sequence.back());
  249. function_move_sequence(sequence, son_counter, bk.error);
  250. bk.exec(son_counter);
  251. if (bk.error) return;
  252. move_long_sequence(index_seq);
  253. }
  254. //
  255. //****************************************************************************
  256. }; // End namespace blk_detail
  257. }; // End namespace sort
  258. }; // End namespace boost
  259. //****************************************************************************
  260. //
  261. #endif