Boost.Sort

- Main Page
- Namespaces
- Classes
- Files

- File List

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>
26 #include <boost/sort/spreadsort/detail/constants.hpp>
27 #include <boost/sort/spreadsort/detail/integer_sort.hpp>
28 #include <boost/sort/spreadsort/detail/spreadsort_common.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,
181 float_log_min_split_count,
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,
241 float_log_min_split_count,
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,
300 float_log_min_split_count,
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,
358 float_log_min_split_count,
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,
442 float_log_min_split_count,
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,
538 float_log_min_split_count,
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,
566 float_log_mean_bin_size, float_log_min_split_count,
567 float_log_finishing_count>
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,
637 float_log_min_split_count,
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,
667 float_log_min_split_count, float_log_finishing_count>
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
boost::sort::detail::float_sort_rec
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
boost
Definition: constants.hpp:11
boost::sort::detail::cast_float_iter
Cast_type cast_float_iter(const RandomAccessIter &floatiter)
Definition: float_sort.hpp:37
integer_sort.hpp
boost::sort::detail::float_log_finishing_count
Definition: constants.hpp:38
boost::sort::detail::inner_float_swap_loop
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
boost::sort::detail::get_min_count
size_t get_min_count(unsigned log_range)
Definition: spreadsort_common.hpp:51
boost::sort::detail::max_splits
Definition: constants.hpp:19
spreadsort_common.hpp
boost::sort::detail::float_swap_loop
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
boost::sort::detail::rough_log_2_size
unsigned rough_log_2_size(const T &input)
Definition: spreadsort_common.hpp:34
boost::sort::detail::is_sorted_or_find_extremes
bool is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last, Div_type &max, Div_type &min, Right_shift rshift)
Definition: float_sort.hpp:54
constants.hpp
boost::sort::detail::size_bins
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
boost::sort::detail::float_log_min_split_count
Definition: constants.hpp:35
boost::sort::detail::float_log_mean_bin_size
Definition: constants.hpp:32
boost::sort::detail::negative_float_sort_rec
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
boost::sort::detail::positive_float_sort_rec
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::sort::detail::float_sort
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