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