flat_stable_sort.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. //----------------------------------------------------------------------------
  2. /// @file flat_stable_sort.hpp
  3. /// @brief Flat stable sort algorithm
  4. ///
  5. /// @author Copyright (c) 2017 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_FLAT_STABLE_SORT_HPP
  14. #define __BOOST_SORT_FLAT_STABLE_SORT_HPP
  15. #include <boost/sort/insert_sort/insert_sort.hpp>
  16. #include <boost/sort/common/util/insert.hpp>
  17. #include <boost/sort/common/merge_block.hpp>
  18. #include <boost/sort/common/sort_basic.hpp>
  19. #include <boost/sort/common/range.hpp>
  20. #include <boost/sort/common/util/traits.hpp>
  21. #include <boost/sort/common/indirect.hpp>
  22. #include <cstdlib>
  23. #include <functional>
  24. #include <iterator>
  25. #include <memory>
  26. #include <type_traits>
  27. #include <vector>
  28. namespace boost
  29. {
  30. namespace sort
  31. {
  32. namespace flat_internal
  33. {
  34. namespace bsc = boost::sort::common;
  35. namespace bscu = boost::sort::common::util;
  36. //---------------------------------------------------------------------------
  37. /// @struct flat_stable_sort
  38. /// @brief This class implement s stable sort algorithm with 1 thread, with
  39. /// an auxiliary memory of N/2 elements
  40. //----------------------------------------------------------------------------
  41. template <class Iter_t, typename Compare = bscu::compare_iter<Iter_t>,
  42. uint32_t Power2 = 10>
  43. class flat_stable_sort: public bsc::merge_block<Iter_t, Compare, Power2>
  44. {
  45. //------------------------------------------------------------------------
  46. // DEFINITIONS AND CONSTANTS
  47. //------------------------------------------------------------------------
  48. typedef bsc::merge_block<Iter_t, Compare, Power2> merge_block_t;
  49. //-------------------------------------------------------------------------
  50. // D E F I N I T I O N S
  51. //-------------------------------------------------------------------------
  52. typedef typename merge_block_t::value_t value_t;
  53. typedef typename merge_block_t::range_pos range_pos;
  54. typedef typename merge_block_t::range_it range_it;
  55. typedef typename merge_block_t::range_buf range_buf;
  56. typedef typename merge_block_t::it_index it_index;
  57. typedef typename merge_block_t::circular_t circular_t;
  58. //------------------------------------------------------------------------
  59. // CONSTANTS
  60. //------------------------------------------------------------------------
  61. using merge_block_t::BLOCK_SIZE;
  62. using merge_block_t::LOG_BLOCK;
  63. using merge_block_t::index;
  64. using merge_block_t::cmp;
  65. using merge_block_t::ptr_circ;
  66. using merge_block_t::get_range;
  67. using merge_block_t::get_group_range;
  68. using merge_block_t::merge_range_pos;
  69. using merge_block_t::move_range_pos_backward;
  70. using merge_block_t::rearrange_with_index;
  71. public:
  72. //------------------------------------------------------------------------
  73. // PUBLIC FUNCTIONS
  74. //-------------------------------------------------------------------------
  75. flat_stable_sort(Iter_t first, Iter_t last, Compare comp,
  76. circular_t *ptr_circ)
  77. : merge_block_t(first, last, comp, ptr_circ)
  78. {
  79. divide(index.begin(), index.end());
  80. rearrange_with_index();
  81. };
  82. flat_stable_sort(Iter_t first, Iter_t last, Compare comp = Compare())
  83. : flat_stable_sort(first, last, comp, nullptr) { };
  84. void divide(it_index itx_first, it_index itx_last);
  85. void sort_small(it_index itx_first, it_index itx_last);
  86. bool is_sorted_forward(it_index itx_first, it_index itx_last);
  87. bool is_sorted_backward(it_index itx_first, it_index itx_last);
  88. };
  89. //----------------------------------------------------------------------------
  90. // End of class flat_stable_sort
  91. //----------------------------------------------------------------------------
  92. //
  93. //------------------------------------------------------------------------
  94. // function :
  95. /// @brief :
  96. /// @param Pos :
  97. /// @return
  98. //------------------------------------------------------------------------
  99. template <class Iter_t, typename Compare, uint32_t Power2>
  100. void flat_stable_sort <Iter_t, Compare, Power2>
  101. ::divide(it_index itx_first, it_index itx_last)
  102. {
  103. size_t nblock = size_t(itx_last - itx_first);
  104. if (nblock < 5)
  105. { sort_small(itx_first, itx_last);
  106. return;
  107. };
  108. if ( nblock > 7)
  109. { if (is_sorted_forward(itx_first, itx_last)) return;
  110. if (is_sorted_backward(itx_first, itx_last)) return;
  111. };
  112. size_t nblock1 = (nblock + 1) >> 1;
  113. divide(itx_first, itx_first + nblock1);
  114. divide(itx_first + nblock1, itx_last);
  115. merge_range_pos(itx_first, itx_first + nblock1, itx_last);
  116. };
  117. //
  118. //------------------------------------------------------------------------
  119. // function : sort_small
  120. /// @brief :
  121. /// @param
  122. /// @param
  123. /// @param
  124. //------------------------------------------------------------------------
  125. template <class Iter_t, typename Compare, uint32_t Power2>
  126. void flat_stable_sort <Iter_t, Compare, Power2>
  127. ::sort_small(it_index itx_first, it_index itx_last)
  128. {
  129. size_t nblock = size_t(itx_last - itx_first);
  130. assert(nblock > 0 and nblock < 5);
  131. value_t *paux = ptr_circ->get_buffer();
  132. range_it rng_data = get_group_range(*itx_first, nblock);
  133. if (nblock < 3)
  134. {
  135. range_buf rng_aux(paux, paux + rng_data.size());
  136. range_sort_data(rng_data, rng_aux, cmp);
  137. return;
  138. };
  139. //--------------------------------------------------------------------
  140. // division of range_data in two ranges for be sorted and merged
  141. //--------------------------------------------------------------------
  142. size_t nblock1 = (nblock + 1) >> 1;
  143. range_it rng_data1 = get_group_range(*itx_first, nblock1);
  144. range_it rng_data2(rng_data1.last, rng_data.last);
  145. range_buf rng_aux1(paux, paux + rng_data1.size());
  146. range_buf rng_aux2(paux, paux + rng_data2.size());
  147. range_sort_data(rng_data2, rng_aux2, cmp);
  148. range_sort_buffer(rng_data1, rng_aux1, cmp);
  149. merge_half(rng_data, rng_aux1, rng_data2, cmp);
  150. };
  151. //
  152. //------------------------------------------------------------------------
  153. // function : is_sorted_forward
  154. /// @brief : return if the data are ordered,
  155. /// @param itx_first : iterator to the first block in the index
  156. /// @param itx_last : iterator to the last block in the index
  157. /// @return : true : the data are ordered false : not ordered
  158. //------------------------------------------------------------------------
  159. template <class Iter_t, typename Compare, uint32_t Power2>
  160. bool flat_stable_sort <Iter_t, Compare, Power2>
  161. ::is_sorted_forward(it_index itx_first, it_index itx_last)
  162. {
  163. size_t nblock = size_t(itx_last - itx_first);
  164. range_it rng = get_group_range(*itx_first, nblock);
  165. size_t nelem = rng.size();
  166. size_t min_process = std::max(BLOCK_SIZE, (nelem >> 3));
  167. size_t nsorted1 = bsc::number_stable_sorted_forward (rng.first, rng.last,
  168. min_process, cmp);
  169. if (nsorted1 == nelem) return true;
  170. if (nsorted1 == 0) return false;
  171. size_t nsorted2 = nelem - nsorted1;
  172. Iter_t itaux = rng.first + nsorted1;
  173. if (nsorted2 <= (BLOCK_SIZE << 1))
  174. {
  175. flat_stable_sort(itaux, rng.last, cmp, ptr_circ);
  176. bscu::insert_sorted(rng.first, itaux, rng.last, cmp,
  177. ptr_circ->get_buffer());
  178. }
  179. else
  180. { // Adjust the size of the sorted data to a number of blocks
  181. size_t mask = ~(BLOCK_SIZE - 1);
  182. size_t nsorted1_adjust = nsorted1 & mask;
  183. flat_stable_sort(rng.first + nsorted1_adjust, rng.last, cmp,
  184. ptr_circ);
  185. size_t nblock1 = nsorted1_adjust >> Power2;
  186. merge_range_pos(itx_first, itx_first + nblock1, itx_last);
  187. };
  188. return true;
  189. };
  190. //
  191. //------------------------------------------------------------------------
  192. // function : is_sorted_backward
  193. /// @brief : return if the data are ordered,
  194. /// @param itx_first : iterator to the first block in the index
  195. /// @param itx_last : iterator to the last block in the index
  196. /// @return : true : the data are ordered false : not ordered
  197. //------------------------------------------------------------------------
  198. template <class Iter_t, typename Compare, uint32_t Power2>
  199. bool flat_stable_sort <Iter_t, Compare, Power2>
  200. ::is_sorted_backward(it_index itx_first, it_index itx_last)
  201. {
  202. size_t nblock = size_t(itx_last - itx_first);
  203. range_it rng = get_group_range(*itx_first, nblock);
  204. size_t nelem = rng.size();
  205. size_t min_process = std::max(BLOCK_SIZE, (nelem >> 3));
  206. size_t nsorted2 = bsc::number_stable_sorted_backward(rng.first, rng.last,
  207. min_process, cmp);
  208. if (nsorted2 == nelem) return true;
  209. if (nsorted2 == 0 ) return false;
  210. Iter_t itaux = rng.last - nsorted2;
  211. size_t nsorted1 = nelem - nsorted2;
  212. if (nsorted1 <= (BLOCK_SIZE << 1))
  213. {
  214. flat_stable_sort(rng.first, itaux, cmp, ptr_circ);
  215. bscu::insert_sorted_backward(rng.first, itaux, rng.last, cmp,
  216. ptr_circ->get_buffer());
  217. }
  218. else
  219. { // Adjust the size of nsorted2 for to be a number of blocks
  220. size_t nblock1 = (nsorted1 + BLOCK_SIZE - 1) >> Power2;
  221. size_t nsorted1_adjust = (nblock1 << Power2);
  222. flat_stable_sort(rng.first, rng.first + nsorted1_adjust, cmp,
  223. ptr_circ);
  224. merge_range_pos(itx_first, itx_first + nblock1, itx_last);
  225. };
  226. return true;
  227. };
  228. //****************************************************************************
  229. };// End namespace flat_internal
  230. //****************************************************************************
  231. //
  232. namespace bscu = boost::sort::common::util;
  233. namespace flat = boost::sort::flat_internal;
  234. //
  235. ///---------------------------------------------------------------------------
  236. // function flat_stable_sort
  237. /// @brief This class is select the block size in the block_indirect_sort
  238. /// algorithm depending of the type and size of the data to sort
  239. ///
  240. //----------------------------------------------------------------------------
  241. template <class Iter_t, class Compare = bscu::compare_iter<Iter_t>,
  242. bscu::enable_if_string<value_iter<Iter_t> > * = nullptr>
  243. inline void flat_stable_sort (Iter_t first, Iter_t last,
  244. Compare cmp = Compare())
  245. {
  246. flat::flat_stable_sort<Iter_t, Compare, 6> (first, last, cmp);
  247. };
  248. template<size_t Size>
  249. struct block_size_fss
  250. {
  251. static constexpr const uint32_t BitsSize =
  252. (Size == 0) ? 0 : (Size > 128) ? 7 : bscu::tmsb[Size - 1];
  253. static constexpr const uint32_t sz[10] =
  254. { 10, 10, 10, 9, 8, 7, 6, 6 };
  255. static constexpr const uint32_t data = sz[BitsSize];
  256. };
  257. //
  258. ///---------------------------------------------------------------------------
  259. // function flat_stable_sort
  260. /// @brief This class is select the block size in the flat_stable_sort
  261. /// algorithm depending of the type and size of the data to sort
  262. ///
  263. //----------------------------------------------------------------------------
  264. template <class Iter_t, class Compare = bscu::compare_iter<Iter_t>,
  265. bscu::enable_if_not_string<value_iter<Iter_t> >* = nullptr>
  266. inline void flat_stable_sort (Iter_t first, Iter_t last,
  267. Compare cmp = Compare())
  268. {
  269. flat::flat_stable_sort<Iter_t, Compare,
  270. block_size_fss<sizeof(value_iter<Iter_t> )>::data>
  271. (first, last, cmp);
  272. };
  273. template<class Iter_t, class Compare = compare_iter<Iter_t> >
  274. inline void indirect_flat_stable_sort (Iter_t first, Iter_t last,
  275. Compare comp = Compare())
  276. {
  277. typedef typename std::vector<Iter_t>::iterator itx_iter;
  278. typedef common::less_ptr_no_null<Iter_t, Compare> itx_comp;
  279. common::indirect_sort ( flat_stable_sort<itx_iter, itx_comp>,
  280. first, last, comp);
  281. };
  282. //****************************************************************************
  283. };// End namespace sort
  284. };// End namepspace boost
  285. //****************************************************************************
  286. //
  287. #endif