float_sort.hpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. // Details for templated Spreadsort-based float_sort.
  2. // Copyright Steven J. Ross 2001 - 2014.
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. // See http://www.boost.org/libs/sort for library home page.
  7. /*
  8. Some improvements suggested by:
  9. Phil Endecott and Frank Gennari
  10. float_mem_cast fix provided by:
  11. Scott McMurray
  12. */
  13. #ifndef BOOST_SORT_SPREADSORT_DETAIL_FLOAT_SORT_HPP
  14. #define BOOST_SORT_SPREADSORT_DETAIL_FLOAT_SORT_HPP
  15. #include <algorithm>
  16. #include <vector>
  17. #include <limits>
  18. #include <functional>
  19. #include <boost/static_assert.hpp>
  20. #include <boost/serialization/static_warning.hpp>
  21. #include <boost/utility/enable_if.hpp>
  22. #include <boost/sort/spreadsort/detail/constants.hpp>
  23. #include <boost/sort/spreadsort/detail/integer_sort.hpp>
  24. #include <boost/sort/spreadsort/detail/spreadsort_common.hpp>
  25. #include <boost/cstdint.hpp>
  26. namespace boost {
  27. namespace sort {
  28. namespace spreadsort {
  29. namespace detail {
  30. //Casts a RandomAccessIter to the specified integer type
  31. template<class Cast_type, class RandomAccessIter>
  32. inline Cast_type
  33. cast_float_iter(const RandomAccessIter & floatiter)
  34. {
  35. typedef typename std::iterator_traits<RandomAccessIter>::value_type
  36. Data_type;
  37. //Only cast IEEE floating-point numbers, and only to same-sized integers
  38. BOOST_STATIC_ASSERT(sizeof(Cast_type) == sizeof(Data_type));
  39. BOOST_STATIC_ASSERT(std::numeric_limits<Data_type>::is_iec559);
  40. BOOST_STATIC_ASSERT(std::numeric_limits<Cast_type>::is_integer);
  41. Cast_type result;
  42. std::memcpy(&result, &(*floatiter), sizeof(Data_type));
  43. return result;
  44. }
  45. // Return true if the list is sorted. Otherwise, find the minimum and
  46. // maximum. Values are Right_shifted 0 bits before comparison.
  47. template <class RandomAccessIter, class Div_type, class Right_shift>
  48. inline bool
  49. is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last,
  50. Div_type & max, Div_type & min, Right_shift rshift)
  51. {
  52. min = max = rshift(*current, 0);
  53. RandomAccessIter prev = current;
  54. bool sorted = true;
  55. while (++current < last) {
  56. Div_type value = rshift(*current, 0);
  57. sorted &= *current >= *prev;
  58. prev = current;
  59. if (max < value)
  60. max = value;
  61. else if (value < min)
  62. min = value;
  63. }
  64. return sorted;
  65. }
  66. // Return true if the list is sorted. Otherwise, find the minimum and
  67. // maximum. Uses comp to check if the data is already sorted.
  68. template <class RandomAccessIter, class Div_type, class Right_shift,
  69. class Compare>
  70. inline bool
  71. is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last,
  72. Div_type & max, Div_type & min,
  73. Right_shift rshift, Compare comp)
  74. {
  75. min = max = rshift(*current, 0);
  76. RandomAccessIter prev = current;
  77. bool sorted = true;
  78. while (++current < last) {
  79. Div_type value = rshift(*current, 0);
  80. sorted &= !comp(*current, *prev);
  81. prev = current;
  82. if (max < value)
  83. max = value;
  84. else if (value < min)
  85. min = value;
  86. }
  87. return sorted;
  88. }
  89. //Specialized swap loops for floating-point casting
  90. template <class RandomAccessIter, class Div_type>
  91. inline void inner_float_swap_loop(RandomAccessIter * bins,
  92. const RandomAccessIter & nextbinstart, unsigned ii
  93. , const unsigned log_divisor, const Div_type div_min)
  94. {
  95. RandomAccessIter * local_bin = bins + ii;
  96. for (RandomAccessIter current = *local_bin; current < nextbinstart;
  97. ++current) {
  98. for (RandomAccessIter * target_bin =
  99. (bins + ((cast_float_iter<Div_type, RandomAccessIter>(current) >>
  100. log_divisor) - div_min)); target_bin != local_bin;
  101. target_bin = bins + ((cast_float_iter<Div_type, RandomAccessIter>
  102. (current) >> log_divisor) - div_min)) {
  103. typename std::iterator_traits<RandomAccessIter>::value_type tmp;
  104. RandomAccessIter b = (*target_bin)++;
  105. RandomAccessIter * b_bin = bins + ((cast_float_iter<Div_type,
  106. RandomAccessIter>(b) >> log_divisor) - div_min);
  107. //Three-way swap; if the item to be swapped doesn't belong in the
  108. //current bin, swap it to where it belongs
  109. if (b_bin != local_bin) {
  110. RandomAccessIter c = (*b_bin)++;
  111. tmp = *c;
  112. *c = *b;
  113. }
  114. else
  115. tmp = *b;
  116. *b = *current;
  117. *current = tmp;
  118. }
  119. }
  120. *local_bin = nextbinstart;
  121. }
  122. template <class RandomAccessIter, class Div_type>
  123. inline void float_swap_loop(RandomAccessIter * bins,
  124. RandomAccessIter & nextbinstart, unsigned ii,
  125. const size_t *bin_sizes,
  126. const unsigned log_divisor, const Div_type div_min)
  127. {
  128. nextbinstart += bin_sizes[ii];
  129. inner_float_swap_loop<RandomAccessIter, Div_type>
  130. (bins, nextbinstart, ii, log_divisor, div_min);
  131. }
  132. // Return true if the list is sorted. Otherwise, find the minimum and
  133. // maximum. Values are cast to Cast_type before comparison.
  134. template <class RandomAccessIter, class Cast_type>
  135. inline bool
  136. is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last,
  137. Cast_type & max, Cast_type & min)
  138. {
  139. min = max = cast_float_iter<Cast_type, RandomAccessIter>(current);
  140. RandomAccessIter prev = current;
  141. bool sorted = true;
  142. while (++current < last) {
  143. Cast_type value = cast_float_iter<Cast_type, RandomAccessIter>(current);
  144. sorted &= *current >= *prev;
  145. prev = current;
  146. if (max < value)
  147. max = value;
  148. else if (value < min)
  149. min = value;
  150. }
  151. return sorted;
  152. }
  153. //Special-case sorting of positive floats with casting
  154. template <class RandomAccessIter, class Div_type, class Size_type>
  155. inline void
  156. positive_float_sort_rec(RandomAccessIter first, RandomAccessIter last,
  157. std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
  158. , size_t *bin_sizes)
  159. {
  160. Div_type max, min;
  161. if (is_sorted_or_find_extremes<RandomAccessIter, Div_type>(first, last,
  162. max, min))
  163. return;
  164. unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
  165. last - first, rough_log_2_size(Size_type(max - min)));
  166. Div_type div_min = min >> log_divisor;
  167. Div_type div_max = max >> log_divisor;
  168. unsigned bin_count = unsigned(div_max - div_min) + 1;
  169. unsigned cache_end;
  170. RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
  171. cache_end, bin_count);
  172. //Calculating the size of each bin
  173. for (RandomAccessIter current = first; current != last;)
  174. bin_sizes[unsigned((cast_float_iter<Div_type, RandomAccessIter>(
  175. current++) >> log_divisor) - div_min)]++;
  176. bins[0] = first;
  177. for (unsigned u = 0; u < bin_count - 1; u++)
  178. bins[u + 1] = bins[u] + bin_sizes[u];
  179. //Swap into place
  180. RandomAccessIter nextbinstart = first;
  181. for (unsigned u = 0; u < bin_count - 1; ++u)
  182. float_swap_loop<RandomAccessIter, Div_type>
  183. (bins, nextbinstart, u, bin_sizes, log_divisor, div_min);
  184. bins[bin_count - 1] = last;
  185. //Return if we've completed bucketsorting
  186. if (!log_divisor)
  187. return;
  188. //Recursing
  189. size_t max_count = get_min_count<float_log_mean_bin_size,
  190. float_log_min_split_count,
  191. float_log_finishing_count>(log_divisor);
  192. RandomAccessIter lastPos = first;
  193. for (unsigned u = cache_offset; u < cache_end; lastPos = bin_cache[u],
  194. ++u) {
  195. size_t count = bin_cache[u] - lastPos;
  196. if (count < 2)
  197. continue;
  198. if (count < max_count)
  199. boost::sort::pdqsort(lastPos, bin_cache[u]);
  200. else
  201. positive_float_sort_rec<RandomAccessIter, Div_type, Size_type>
  202. (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes);
  203. }
  204. }
  205. //Sorting negative floats
  206. //Bins are iterated in reverse because max_neg_float = min_neg_int
  207. template <class RandomAccessIter, class Div_type, class Size_type>
  208. inline void
  209. negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last,
  210. std::vector<RandomAccessIter> &bin_cache,
  211. unsigned cache_offset, size_t *bin_sizes)
  212. {
  213. Div_type max, min;
  214. if (is_sorted_or_find_extremes<RandomAccessIter, Div_type>(first, last,
  215. max, min))
  216. return;
  217. unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
  218. last - first, rough_log_2_size(Size_type(max - min)));
  219. Div_type div_min = min >> log_divisor;
  220. Div_type div_max = max >> log_divisor;
  221. unsigned bin_count = unsigned(div_max - div_min) + 1;
  222. unsigned cache_end;
  223. RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
  224. cache_end, bin_count);
  225. //Calculating the size of each bin
  226. for (RandomAccessIter current = first; current != last;)
  227. bin_sizes[unsigned((cast_float_iter<Div_type, RandomAccessIter>(
  228. current++) >> log_divisor) - div_min)]++;
  229. bins[bin_count - 1] = first;
  230. for (int ii = bin_count - 2; ii >= 0; --ii)
  231. bins[ii] = bins[ii + 1] + bin_sizes[ii + 1];
  232. //Swap into place
  233. RandomAccessIter nextbinstart = first;
  234. //The last bin will always have the correct elements in it
  235. for (int ii = bin_count - 1; ii > 0; --ii)
  236. float_swap_loop<RandomAccessIter, Div_type>
  237. (bins, nextbinstart, ii, bin_sizes, log_divisor, div_min);
  238. //Update the end position because we don't process the last bin
  239. bin_cache[cache_offset] = last;
  240. //Return if we've completed bucketsorting
  241. if (!log_divisor)
  242. return;
  243. //Recursing
  244. size_t max_count = get_min_count<float_log_mean_bin_size,
  245. float_log_min_split_count,
  246. float_log_finishing_count>(log_divisor);
  247. RandomAccessIter lastPos = first;
  248. for (int ii = cache_end - 1; ii >= static_cast<int>(cache_offset);
  249. lastPos = bin_cache[ii], --ii) {
  250. size_t count = bin_cache[ii] - lastPos;
  251. if (count < 2)
  252. continue;
  253. if (count < max_count)
  254. boost::sort::pdqsort(lastPos, bin_cache[ii]);
  255. else
  256. negative_float_sort_rec<RandomAccessIter, Div_type, Size_type>
  257. (lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes);
  258. }
  259. }
  260. //Sorting negative floats
  261. //Bins are iterated in reverse order because max_neg_float = min_neg_int
  262. template <class RandomAccessIter, class Div_type, class Right_shift,
  263. class Size_type>
  264. inline void
  265. negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last,
  266. std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
  267. , size_t *bin_sizes, Right_shift rshift)
  268. {
  269. Div_type max, min;
  270. if (is_sorted_or_find_extremes(first, last, max, min, rshift))
  271. return;
  272. unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
  273. last - first, rough_log_2_size(Size_type(max - min)));
  274. Div_type div_min = min >> log_divisor;
  275. Div_type div_max = max >> log_divisor;
  276. unsigned bin_count = unsigned(div_max - div_min) + 1;
  277. unsigned cache_end;
  278. RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
  279. cache_end, bin_count);
  280. //Calculating the size of each bin
  281. for (RandomAccessIter current = first; current != last;)
  282. bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++;
  283. bins[bin_count - 1] = first;
  284. for (int ii = bin_count - 2; ii >= 0; --ii)
  285. bins[ii] = bins[ii + 1] + bin_sizes[ii + 1];
  286. //Swap into place
  287. RandomAccessIter nextbinstart = first;
  288. //The last bin will always have the correct elements in it
  289. for (int ii = bin_count - 1; ii > 0; --ii)
  290. swap_loop<RandomAccessIter, Div_type, Right_shift>
  291. (bins, nextbinstart, ii, rshift, bin_sizes, log_divisor, div_min);
  292. //Update the end position of the unprocessed last bin
  293. bin_cache[cache_offset] = last;
  294. //Return if we've completed bucketsorting
  295. if (!log_divisor)
  296. return;
  297. //Recursing
  298. size_t max_count = get_min_count<float_log_mean_bin_size,
  299. float_log_min_split_count,
  300. float_log_finishing_count>(log_divisor);
  301. RandomAccessIter lastPos = first;
  302. for (int ii = cache_end - 1; ii >= static_cast<int>(cache_offset);
  303. lastPos = bin_cache[ii], --ii) {
  304. size_t count = bin_cache[ii] - lastPos;
  305. if (count < 2)
  306. continue;
  307. if (count < max_count)
  308. boost::sort::pdqsort(lastPos, bin_cache[ii]);
  309. else
  310. negative_float_sort_rec<RandomAccessIter, Div_type, Right_shift,
  311. Size_type>
  312. (lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes, rshift);
  313. }
  314. }
  315. template <class RandomAccessIter, class Div_type, class Right_shift,
  316. class Compare, class Size_type>
  317. inline void
  318. negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last,
  319. std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset,
  320. size_t *bin_sizes, Right_shift rshift, Compare comp)
  321. {
  322. Div_type max, min;
  323. if (is_sorted_or_find_extremes(first, last, max, min, rshift, comp))
  324. return;
  325. unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
  326. last - first, rough_log_2_size(Size_type(max - min)));
  327. Div_type div_min = min >> log_divisor;
  328. Div_type div_max = max >> log_divisor;
  329. unsigned bin_count = unsigned(div_max - div_min) + 1;
  330. unsigned cache_end;
  331. RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
  332. cache_end, bin_count);
  333. //Calculating the size of each bin
  334. for (RandomAccessIter current = first; current != last;)
  335. bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++;
  336. bins[bin_count - 1] = first;
  337. for (int ii = bin_count - 2; ii >= 0; --ii)
  338. bins[ii] = bins[ii + 1] + bin_sizes[ii + 1];
  339. //Swap into place
  340. RandomAccessIter nextbinstart = first;
  341. //The last bin will always have the correct elements in it
  342. for (int ii = bin_count - 1; ii > 0; --ii)
  343. swap_loop<RandomAccessIter, Div_type, Right_shift>
  344. (bins, nextbinstart, ii, rshift, bin_sizes, log_divisor, div_min);
  345. //Update the end position of the unprocessed last bin
  346. bin_cache[cache_offset] = last;
  347. //Return if we've completed bucketsorting
  348. if (!log_divisor)
  349. return;
  350. //Recursing
  351. size_t max_count = get_min_count<float_log_mean_bin_size,
  352. float_log_min_split_count,
  353. float_log_finishing_count>(log_divisor);
  354. RandomAccessIter lastPos = first;
  355. for (int ii = cache_end - 1; ii >= static_cast<int>(cache_offset);
  356. lastPos = bin_cache[ii], --ii) {
  357. size_t count = bin_cache[ii] - lastPos;
  358. if (count < 2)
  359. continue;
  360. if (count < max_count)
  361. boost::sort::pdqsort(lastPos, bin_cache[ii], comp);
  362. else
  363. negative_float_sort_rec<RandomAccessIter, Div_type, Right_shift,
  364. Compare, Size_type>(lastPos, bin_cache[ii],
  365. bin_cache, cache_end,
  366. bin_sizes, rshift, comp);
  367. }
  368. }
  369. //Casting special-case for floating-point sorting
  370. template <class RandomAccessIter, class Div_type, class Size_type>
  371. inline void
  372. float_sort_rec(RandomAccessIter first, RandomAccessIter last,
  373. std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
  374. , size_t *bin_sizes)
  375. {
  376. Div_type max, min;
  377. if (is_sorted_or_find_extremes<RandomAccessIter, Div_type>(first, last,
  378. max, min))
  379. return;
  380. unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
  381. last - first, rough_log_2_size(Size_type(max - min)));
  382. Div_type div_min = min >> log_divisor;
  383. Div_type div_max = max >> log_divisor;
  384. unsigned bin_count = unsigned(div_max - div_min) + 1;
  385. unsigned cache_end;
  386. RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
  387. cache_end, bin_count);
  388. //Calculating the size of each bin
  389. for (RandomAccessIter current = first; current != last;)
  390. bin_sizes[unsigned((cast_float_iter<Div_type, RandomAccessIter>(
  391. current++) >> log_divisor) - div_min)]++;
  392. //The index of the first positive bin
  393. //Must be divided small enough to fit into an integer
  394. unsigned first_positive = (div_min < 0) ? unsigned(-div_min) : 0;
  395. //Resetting if all bins are negative
  396. if (cache_offset + first_positive > cache_end)
  397. first_positive = cache_end - cache_offset;
  398. //Reversing the order of the negative bins
  399. //Note that because of the negative/positive ordering direction flip
  400. //We can not depend upon bin order and positions matching up
  401. //so bin_sizes must be reused to contain the end of the bin
  402. if (first_positive > 0) {
  403. bins[first_positive - 1] = first;
  404. for (int ii = first_positive - 2; ii >= 0; --ii) {
  405. bins[ii] = first + bin_sizes[ii + 1];
  406. bin_sizes[ii] += bin_sizes[ii + 1];
  407. }
  408. //Handling positives following negatives
  409. if (first_positive < bin_count) {
  410. bins[first_positive] = first + bin_sizes[0];
  411. bin_sizes[first_positive] += bin_sizes[0];
  412. }
  413. }
  414. else
  415. bins[0] = first;
  416. for (unsigned u = first_positive; u < bin_count - 1; u++) {
  417. bins[u + 1] = first + bin_sizes[u];
  418. bin_sizes[u + 1] += bin_sizes[u];
  419. }
  420. //Swap into place
  421. RandomAccessIter nextbinstart = first;
  422. for (unsigned u = 0; u < bin_count; ++u) {
  423. nextbinstart = first + bin_sizes[u];
  424. inner_float_swap_loop<RandomAccessIter, Div_type>
  425. (bins, nextbinstart, u, log_divisor, div_min);
  426. }
  427. if (!log_divisor)
  428. return;
  429. //Handling negative values first
  430. size_t max_count = get_min_count<float_log_mean_bin_size,
  431. float_log_min_split_count,
  432. float_log_finishing_count>(log_divisor);
  433. RandomAccessIter lastPos = first;
  434. for (int ii = cache_offset + first_positive - 1;
  435. ii >= static_cast<int>(cache_offset);
  436. lastPos = bin_cache[ii--]) {
  437. size_t count = bin_cache[ii] - lastPos;
  438. if (count < 2)
  439. continue;
  440. if (count < max_count)
  441. boost::sort::pdqsort(lastPos, bin_cache[ii]);
  442. //sort negative values using reversed-bin spreadsort
  443. else
  444. negative_float_sort_rec<RandomAccessIter, Div_type, Size_type>
  445. (lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes);
  446. }
  447. for (unsigned u = cache_offset + first_positive; u < cache_end;
  448. lastPos = bin_cache[u], ++u) {
  449. size_t count = bin_cache[u] - lastPos;
  450. if (count < 2)
  451. continue;
  452. if (count < max_count)
  453. boost::sort::pdqsort(lastPos, bin_cache[u]);
  454. //sort positive values using normal spreadsort
  455. else
  456. positive_float_sort_rec<RandomAccessIter, Div_type, Size_type>
  457. (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes);
  458. }
  459. }
  460. //Functor implementation for recursive sorting
  461. template <class RandomAccessIter, class Div_type, class Right_shift
  462. , class Size_type>
  463. inline void
  464. float_sort_rec(RandomAccessIter first, RandomAccessIter last,
  465. std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
  466. , size_t *bin_sizes, Right_shift rshift)
  467. {
  468. Div_type max, min;
  469. if (is_sorted_or_find_extremes(first, last, max, min, rshift))
  470. return;
  471. unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
  472. last - first, rough_log_2_size(Size_type(max - min)));
  473. Div_type div_min = min >> log_divisor;
  474. Div_type div_max = max >> log_divisor;
  475. unsigned bin_count = unsigned(div_max - div_min) + 1;
  476. unsigned cache_end;
  477. RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
  478. cache_end, bin_count);
  479. //Calculating the size of each bin
  480. for (RandomAccessIter current = first; current != last;)
  481. bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++;
  482. //The index of the first positive bin
  483. unsigned first_positive = (div_min < 0) ? unsigned(-div_min) : 0;
  484. //Resetting if all bins are negative
  485. if (cache_offset + first_positive > cache_end)
  486. first_positive = cache_end - cache_offset;
  487. //Reversing the order of the negative bins
  488. //Note that because of the negative/positive ordering direction flip
  489. //We can not depend upon bin order and positions matching up
  490. //so bin_sizes must be reused to contain the end of the bin
  491. if (first_positive > 0) {
  492. bins[first_positive - 1] = first;
  493. for (int ii = first_positive - 2; ii >= 0; --ii) {
  494. bins[ii] = first + bin_sizes[ii + 1];
  495. bin_sizes[ii] += bin_sizes[ii + 1];
  496. }
  497. //Handling positives following negatives
  498. if (static_cast<unsigned>(first_positive) < bin_count) {
  499. bins[first_positive] = first + bin_sizes[0];
  500. bin_sizes[first_positive] += bin_sizes[0];
  501. }
  502. }
  503. else
  504. bins[0] = first;
  505. for (unsigned u = first_positive; u < bin_count - 1; u++) {
  506. bins[u + 1] = first + bin_sizes[u];
  507. bin_sizes[u + 1] += bin_sizes[u];
  508. }
  509. //Swap into place
  510. RandomAccessIter next_bin_start = first;
  511. for (unsigned u = 0; u < bin_count; ++u) {
  512. next_bin_start = first + bin_sizes[u];
  513. inner_swap_loop<RandomAccessIter, Div_type, Right_shift>
  514. (bins, next_bin_start, u, rshift, log_divisor, div_min);
  515. }
  516. //Return if we've completed bucketsorting
  517. if (!log_divisor)
  518. return;
  519. //Handling negative values first
  520. size_t max_count = get_min_count<float_log_mean_bin_size,
  521. float_log_min_split_count,
  522. float_log_finishing_count>(log_divisor);
  523. RandomAccessIter lastPos = first;
  524. for (int ii = cache_offset + first_positive - 1;
  525. ii >= static_cast<int>(cache_offset);
  526. lastPos = bin_cache[ii--]) {
  527. size_t count = bin_cache[ii] - lastPos;
  528. if (count < 2)
  529. continue;
  530. if (count < max_count)
  531. boost::sort::pdqsort(lastPos, bin_cache[ii]);
  532. //sort negative values using reversed-bin spreadsort
  533. else
  534. negative_float_sort_rec<RandomAccessIter, Div_type,
  535. Right_shift, Size_type>(lastPos, bin_cache[ii], bin_cache,
  536. cache_end, bin_sizes, rshift);
  537. }
  538. for (unsigned u = cache_offset + first_positive; u < cache_end;
  539. lastPos = bin_cache[u], ++u) {
  540. size_t count = bin_cache[u] - lastPos;
  541. if (count < 2)
  542. continue;
  543. if (count < max_count)
  544. boost::sort::pdqsort(lastPos, bin_cache[u]);
  545. //sort positive values using normal spreadsort
  546. else
  547. spreadsort_rec<RandomAccessIter, Div_type, Right_shift, Size_type,
  548. float_log_mean_bin_size, float_log_min_split_count,
  549. float_log_finishing_count>
  550. (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, rshift);
  551. }
  552. }
  553. template <class RandomAccessIter, class Div_type, class Right_shift,
  554. class Compare, class Size_type>
  555. inline void
  556. float_sort_rec(RandomAccessIter first, RandomAccessIter last,
  557. std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset,
  558. size_t *bin_sizes, Right_shift rshift, Compare comp)
  559. {
  560. Div_type max, min;
  561. if (is_sorted_or_find_extremes(first, last, max, min, rshift, comp))
  562. return;
  563. unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
  564. last - first, rough_log_2_size(Size_type(max - min)));
  565. Div_type div_min = min >> log_divisor;
  566. Div_type div_max = max >> log_divisor;
  567. unsigned bin_count = unsigned(div_max - div_min) + 1;
  568. unsigned cache_end;
  569. RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
  570. cache_end, bin_count);
  571. //Calculating the size of each bin
  572. for (RandomAccessIter current = first; current != last;)
  573. bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++;
  574. //The index of the first positive bin
  575. unsigned first_positive =
  576. (div_min < 0) ? static_cast<unsigned>(-div_min) : 0;
  577. //Resetting if all bins are negative
  578. if (cache_offset + first_positive > cache_end)
  579. first_positive = cache_end - cache_offset;
  580. //Reversing the order of the negative bins
  581. //Note that because of the negative/positive ordering direction flip
  582. //We can not depend upon bin order and positions matching up
  583. //so bin_sizes must be reused to contain the end of the bin
  584. if (first_positive > 0) {
  585. bins[first_positive - 1] = first;
  586. for (int ii = first_positive - 2; ii >= 0; --ii) {
  587. bins[ii] = first + bin_sizes[ii + 1];
  588. bin_sizes[ii] += bin_sizes[ii + 1];
  589. }
  590. //Handling positives following negatives
  591. if (static_cast<unsigned>(first_positive) < bin_count) {
  592. bins[first_positive] = first + bin_sizes[0];
  593. bin_sizes[first_positive] += bin_sizes[0];
  594. }
  595. }
  596. else
  597. bins[0] = first;
  598. for (unsigned u = first_positive; u < bin_count - 1; u++) {
  599. bins[u + 1] = first + bin_sizes[u];
  600. bin_sizes[u + 1] += bin_sizes[u];
  601. }
  602. //Swap into place
  603. RandomAccessIter next_bin_start = first;
  604. for (unsigned u = 0; u < bin_count; ++u) {
  605. next_bin_start = first + bin_sizes[u];
  606. inner_swap_loop<RandomAccessIter, Div_type, Right_shift>
  607. (bins, next_bin_start, u, rshift, log_divisor, div_min);
  608. }
  609. //Return if we've completed bucketsorting
  610. if (!log_divisor)
  611. return;
  612. //Handling negative values first
  613. size_t max_count = get_min_count<float_log_mean_bin_size,
  614. float_log_min_split_count,
  615. float_log_finishing_count>(log_divisor);
  616. RandomAccessIter lastPos = first;
  617. for (int ii = cache_offset + first_positive - 1;
  618. ii >= static_cast<int>(cache_offset);
  619. lastPos = bin_cache[ii--]) {
  620. size_t count = bin_cache[ii] - lastPos;
  621. if (count < 2)
  622. continue;
  623. if (count < max_count)
  624. boost::sort::pdqsort(lastPos, bin_cache[ii], comp);
  625. //sort negative values using reversed-bin spreadsort
  626. else
  627. negative_float_sort_rec<RandomAccessIter, Div_type, Right_shift,
  628. Compare, Size_type>(lastPos, bin_cache[ii],
  629. bin_cache, cache_end,
  630. bin_sizes, rshift, comp);
  631. }
  632. for (unsigned u = cache_offset + first_positive; u < cache_end;
  633. lastPos = bin_cache[u], ++u) {
  634. size_t count = bin_cache[u] - lastPos;
  635. if (count < 2)
  636. continue;
  637. if (count < max_count)
  638. boost::sort::pdqsort(lastPos, bin_cache[u], comp);
  639. //sort positive values using normal spreadsort
  640. else
  641. spreadsort_rec<RandomAccessIter, Div_type, Right_shift, Compare,
  642. Size_type, float_log_mean_bin_size,
  643. float_log_min_split_count, float_log_finishing_count>
  644. (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, rshift, comp);
  645. }
  646. }
  647. //Checking whether the value type is a float, and trying a 32-bit integer
  648. template <class RandomAccessIter>
  649. inline typename boost::enable_if_c< sizeof(boost::uint32_t) ==
  650. sizeof(typename std::iterator_traits<RandomAccessIter>::value_type)
  651. && std::numeric_limits<typename
  652. std::iterator_traits<RandomAccessIter>::value_type>::is_iec559,
  653. void >::type
  654. float_sort(RandomAccessIter first, RandomAccessIter last)
  655. {
  656. size_t bin_sizes[1 << max_finishing_splits];
  657. std::vector<RandomAccessIter> bin_cache;
  658. float_sort_rec<RandomAccessIter, boost::int32_t, boost::uint32_t>
  659. (first, last, bin_cache, 0, bin_sizes);
  660. }
  661. //Checking whether the value type is a double, and using a 64-bit integer
  662. template <class RandomAccessIter>
  663. inline typename boost::enable_if_c< sizeof(boost::uint64_t) ==
  664. sizeof(typename std::iterator_traits<RandomAccessIter>::value_type)
  665. && std::numeric_limits<typename
  666. std::iterator_traits<RandomAccessIter>::value_type>::is_iec559,
  667. void >::type
  668. float_sort(RandomAccessIter first, RandomAccessIter last)
  669. {
  670. size_t bin_sizes[1 << max_finishing_splits];
  671. std::vector<RandomAccessIter> bin_cache;
  672. float_sort_rec<RandomAccessIter, boost::int64_t, boost::uint64_t>
  673. (first, last, bin_cache, 0, bin_sizes);
  674. }
  675. template <class RandomAccessIter>
  676. inline typename boost::disable_if_c< (sizeof(boost::uint64_t) ==
  677. sizeof(typename std::iterator_traits<RandomAccessIter>::value_type)
  678. || sizeof(boost::uint32_t) ==
  679. sizeof(typename std::iterator_traits<RandomAccessIter>::value_type))
  680. && std::numeric_limits<typename
  681. std::iterator_traits<RandomAccessIter>::value_type>::is_iec559,
  682. void >::type
  683. float_sort(RandomAccessIter first, RandomAccessIter last)
  684. {
  685. BOOST_STATIC_WARNING(!(sizeof(boost::uint64_t) ==
  686. sizeof(typename std::iterator_traits<RandomAccessIter>::value_type)
  687. || sizeof(boost::uint32_t) ==
  688. sizeof(typename std::iterator_traits<RandomAccessIter>::value_type))
  689. || !std::numeric_limits<typename
  690. std::iterator_traits<RandomAccessIter>::value_type>::is_iec559);
  691. boost::sort::pdqsort(first, last);
  692. }
  693. //These approaches require the user to do the typecast
  694. //with rshift but default comparision
  695. template <class RandomAccessIter, class Div_type, class Right_shift>
  696. inline typename boost::enable_if_c< sizeof(size_t) >= sizeof(Div_type),
  697. void >::type
  698. float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
  699. Right_shift rshift)
  700. {
  701. size_t bin_sizes[1 << max_finishing_splits];
  702. std::vector<RandomAccessIter> bin_cache;
  703. float_sort_rec<RandomAccessIter, Div_type, Right_shift, size_t>
  704. (first, last, bin_cache, 0, bin_sizes, rshift);
  705. }
  706. //maximum integer size with rshift but default comparision
  707. template <class RandomAccessIter, class Div_type, class Right_shift>
  708. inline typename boost::enable_if_c< sizeof(size_t) < sizeof(Div_type)
  709. && sizeof(boost::uintmax_t) >= sizeof(Div_type), void >::type
  710. float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
  711. Right_shift rshift)
  712. {
  713. size_t bin_sizes[1 << max_finishing_splits];
  714. std::vector<RandomAccessIter> bin_cache;
  715. float_sort_rec<RandomAccessIter, Div_type, Right_shift, boost::uintmax_t>
  716. (first, last, bin_cache, 0, bin_sizes, rshift);
  717. }
  718. //sizeof(Div_type) doesn't match, so use boost::sort::pdqsort
  719. template <class RandomAccessIter, class Div_type, class Right_shift>
  720. inline typename boost::disable_if_c< sizeof(boost::uintmax_t) >=
  721. sizeof(Div_type), void >::type
  722. float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
  723. Right_shift rshift)
  724. {
  725. BOOST_STATIC_WARNING(sizeof(boost::uintmax_t) >= sizeof(Div_type));
  726. boost::sort::pdqsort(first, last);
  727. }
  728. //specialized comparison
  729. template <class RandomAccessIter, class Div_type, class Right_shift,
  730. class Compare>
  731. inline typename boost::enable_if_c< sizeof(size_t) >= sizeof(Div_type),
  732. void >::type
  733. float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
  734. Right_shift rshift, Compare comp)
  735. {
  736. size_t bin_sizes[1 << max_finishing_splits];
  737. std::vector<RandomAccessIter> bin_cache;
  738. float_sort_rec<RandomAccessIter, Div_type, Right_shift, Compare,
  739. size_t>
  740. (first, last, bin_cache, 0, bin_sizes, rshift, comp);
  741. }
  742. //max-sized integer with specialized comparison
  743. template <class RandomAccessIter, class Div_type, class Right_shift,
  744. class Compare>
  745. inline typename boost::enable_if_c< sizeof(size_t) < sizeof(Div_type)
  746. && sizeof(boost::uintmax_t) >= sizeof(Div_type), void >::type
  747. float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
  748. Right_shift rshift, Compare comp)
  749. {
  750. size_t bin_sizes[1 << max_finishing_splits];
  751. std::vector<RandomAccessIter> bin_cache;
  752. float_sort_rec<RandomAccessIter, Div_type, Right_shift, Compare,
  753. boost::uintmax_t>
  754. (first, last, bin_cache, 0, bin_sizes, rshift, comp);
  755. }
  756. //sizeof(Div_type) doesn't match, so use boost::sort::pdqsort
  757. template <class RandomAccessIter, class Div_type, class Right_shift,
  758. class Compare>
  759. inline typename boost::disable_if_c< sizeof(boost::uintmax_t) >=
  760. sizeof(Div_type), void >::type
  761. float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
  762. Right_shift rshift, Compare comp)
  763. {
  764. BOOST_STATIC_WARNING(sizeof(boost::uintmax_t) >= sizeof(Div_type));
  765. boost::sort::pdqsort(first, last, comp);
  766. }
  767. }
  768. }
  769. }
  770. }
  771. #endif