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