Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:51:48

0001 // Details for templated Spreadsort-based float_sort.
0002 
0003 //          Copyright Steven J. Ross 2001 - 2014.
0004 // Distributed under the Boost Software License, Version 1.0.
0005 //    (See accompanying file LICENSE_1_0.txt or copy at
0006 //          http://www.boost.org/LICENSE_1_0.txt)
0007 
0008 // See http://www.boost.org/libs/sort for library home page.
0009 
0010 /*
0011 Some improvements suggested by:
0012 Phil Endecott and Frank Gennari
0013 float_mem_cast fix provided by:
0014 Scott McMurray
0015 */
0016 
0017 #ifndef BOOST_SORT_SPREADSORT_DETAIL_FLOAT_SORT_HPP
0018 #define BOOST_SORT_SPREADSORT_DETAIL_FLOAT_SORT_HPP
0019 #include <algorithm>
0020 #include <vector>
0021 #include <limits>
0022 #include <functional>
0023 #include <boost/static_assert.hpp>
0024 #include <boost/utility/enable_if.hpp>
0025 #include <boost/sort/spreadsort/detail/constants.hpp>
0026 #include <boost/sort/spreadsort/detail/integer_sort.hpp>
0027 #include <boost/sort/spreadsort/detail/spreadsort_common.hpp>
0028 #include <boost/cstdint.hpp>
0029 
0030 namespace boost {
0031 namespace sort {
0032 namespace spreadsort {
0033   namespace detail {
0034     //Casts a RandomAccessIter to the specified integer type
0035     template<class Cast_type, class RandomAccessIter>
0036     inline Cast_type
0037     cast_float_iter(const RandomAccessIter & floatiter)
0038     {
0039       typedef typename std::iterator_traits<RandomAccessIter>::value_type
0040         Data_type;
0041       //Only cast IEEE floating-point numbers, and only to same-sized integers
0042       BOOST_STATIC_ASSERT(sizeof(Cast_type) == sizeof(Data_type));
0043       BOOST_STATIC_ASSERT(std::numeric_limits<Data_type>::is_iec559);
0044       BOOST_STATIC_ASSERT(std::numeric_limits<Cast_type>::is_integer);
0045       Cast_type result;
0046       std::memcpy(&result, &(*floatiter), sizeof(Data_type));
0047       return result;
0048     }
0049 
0050     // Return true if the list is sorted.  Otherwise, find the minimum and
0051     // maximum.  Values are Right_shifted 0 bits before comparison.
0052     template <class RandomAccessIter, class Div_type, class Right_shift>
0053     inline bool
0054     is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last,
0055                   Div_type & max, Div_type & min, Right_shift rshift)
0056     {
0057       min = max = rshift(*current, 0);
0058       RandomAccessIter prev = current;
0059       bool sorted = true;
0060       while (++current < last) {
0061         Div_type value = rshift(*current, 0);
0062         sorted &= *current >= *prev;
0063         prev = current;
0064         if (max < value)
0065           max = value;
0066         else if (value < min)
0067           min = value;
0068       }
0069       return sorted;
0070     }
0071 
0072     // Return true if the list is sorted.  Otherwise, find the minimum and
0073     // maximum.  Uses comp to check if the data is already sorted.
0074     template <class RandomAccessIter, class Div_type, class Right_shift,
0075               class Compare>
0076     inline bool
0077     is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last,
0078                                Div_type & max, Div_type & min, 
0079                                Right_shift rshift, Compare comp)
0080     {
0081       min = max = rshift(*current, 0);
0082       RandomAccessIter prev = current;
0083       bool sorted = true;
0084       while (++current < last) {
0085         Div_type value = rshift(*current, 0);
0086         sorted &= !comp(*current, *prev);
0087         prev = current;
0088         if (max < value)
0089           max = value;
0090         else if (value < min)
0091           min = value;
0092       }
0093       return sorted;
0094     }
0095 
0096     //Specialized swap loops for floating-point casting
0097     template <class RandomAccessIter, class Div_type>
0098     inline void inner_float_swap_loop(RandomAccessIter * bins,
0099                         const RandomAccessIter & nextbinstart, unsigned ii
0100                         , const unsigned log_divisor, const Div_type div_min)
0101     {
0102       RandomAccessIter * local_bin = bins + ii;
0103       for (RandomAccessIter current = *local_bin; current < nextbinstart;
0104           ++current) {
0105         for (RandomAccessIter * target_bin =
0106             (bins + ((cast_float_iter<Div_type, RandomAccessIter>(current) >>
0107                       log_divisor) - div_min));  target_bin != local_bin;
0108           target_bin = bins + ((cast_float_iter<Div_type, RandomAccessIter>
0109                                (current) >> log_divisor) - div_min)) {
0110           typename std::iterator_traits<RandomAccessIter>::value_type tmp;
0111           RandomAccessIter b = (*target_bin)++;
0112           RandomAccessIter * b_bin = bins + ((cast_float_iter<Div_type,
0113                               RandomAccessIter>(b) >> log_divisor) - div_min);
0114           //Three-way swap; if the item to be swapped doesn't belong in the
0115           //current bin, swap it to where it belongs
0116           if (b_bin != local_bin) {
0117             RandomAccessIter c = (*b_bin)++;
0118             tmp = *c;
0119             *c = *b;
0120           }
0121           else
0122             tmp = *b;
0123           *b = *current;
0124           *current = tmp;
0125         }
0126       }
0127       *local_bin = nextbinstart;
0128     }
0129 
0130     template <class RandomAccessIter, class Div_type>
0131     inline void float_swap_loop(RandomAccessIter * bins,
0132                           RandomAccessIter & nextbinstart, unsigned ii,
0133                           const size_t *bin_sizes,
0134                           const unsigned log_divisor, const Div_type div_min)
0135     {
0136       nextbinstart += bin_sizes[ii];
0137       inner_float_swap_loop<RandomAccessIter, Div_type>
0138         (bins, nextbinstart, ii, log_divisor, div_min);
0139     }
0140 
0141     // Return true if the list is sorted.  Otherwise, find the minimum and
0142     // maximum.  Values are cast to Cast_type before comparison.
0143     template <class RandomAccessIter, class Cast_type>
0144     inline bool
0145     is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last,
0146                   Cast_type & max, Cast_type & min)
0147     {
0148       min = max = cast_float_iter<Cast_type, RandomAccessIter>(current);
0149       RandomAccessIter prev = current;
0150       bool sorted = true;
0151       while (++current < last) {
0152         Cast_type value = cast_float_iter<Cast_type, RandomAccessIter>(current);
0153         sorted &= *current >= *prev;
0154         prev = current;
0155         if (max < value)
0156           max = value;
0157         else if (value < min)
0158           min = value;
0159       }
0160       return sorted;
0161     }
0162 
0163     //Special-case sorting of positive floats with casting
0164     template <class RandomAccessIter, class Div_type, class Size_type>
0165     inline void
0166     positive_float_sort_rec(RandomAccessIter first, RandomAccessIter last,
0167               std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
0168               , size_t *bin_sizes)
0169     {
0170       Div_type max, min;
0171       if (is_sorted_or_find_extremes<RandomAccessIter, Div_type>(first, last, 
0172                                                                 max, min))
0173         return;
0174       unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
0175           last - first, rough_log_2_size(Size_type(max - min)));
0176       Div_type div_min = min >> log_divisor;
0177       Div_type div_max = max >> log_divisor;
0178       unsigned bin_count = unsigned(div_max - div_min) + 1;
0179       unsigned cache_end;
0180       RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
0181                                           cache_end, bin_count);
0182 
0183       //Calculating the size of each bin
0184       for (RandomAccessIter current = first; current != last;)
0185         bin_sizes[unsigned((cast_float_iter<Div_type, RandomAccessIter>(
0186             current++) >> log_divisor) - div_min)]++;
0187       bins[0] = first;
0188       for (unsigned u = 0; u < bin_count - 1; u++)
0189         bins[u + 1] = bins[u] + bin_sizes[u];
0190 
0191 
0192       //Swap into place
0193       RandomAccessIter nextbinstart = first;
0194       for (unsigned u = 0; u < bin_count - 1; ++u)
0195         float_swap_loop<RandomAccessIter, Div_type>
0196           (bins, nextbinstart, u, bin_sizes, log_divisor, div_min);
0197       bins[bin_count - 1] = last;
0198 
0199       //Return if we've completed bucketsorting
0200       if (!log_divisor)
0201         return;
0202 
0203       //Recursing
0204       size_t max_count = get_min_count<float_log_mean_bin_size,
0205                                        float_log_min_split_count,
0206                                        float_log_finishing_count>(log_divisor);
0207       RandomAccessIter lastPos = first;
0208       for (unsigned u = cache_offset; u < cache_end; lastPos = bin_cache[u],
0209           ++u) {
0210         size_t count = bin_cache[u] - lastPos;
0211         if (count < 2)
0212           continue;
0213         if (count < max_count)
0214           boost::sort::pdqsort(lastPos, bin_cache[u]);
0215         else
0216           positive_float_sort_rec<RandomAccessIter, Div_type, Size_type>
0217             (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes);
0218       }
0219     }
0220 
0221     //Sorting negative floats
0222     //Bins are iterated in reverse because max_neg_float = min_neg_int
0223     template <class RandomAccessIter, class Div_type, class Size_type>
0224     inline void
0225     negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last,
0226                         std::vector<RandomAccessIter> &bin_cache,
0227                         unsigned cache_offset, size_t *bin_sizes)
0228     {
0229       Div_type max, min;
0230       if (is_sorted_or_find_extremes<RandomAccessIter, Div_type>(first, last, 
0231                                                                  max, min))
0232         return;
0233 
0234       unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
0235           last - first, rough_log_2_size(Size_type(max - min)));
0236       Div_type div_min = min >> log_divisor;
0237       Div_type div_max = max >> log_divisor;
0238       unsigned bin_count = unsigned(div_max - div_min) + 1;
0239       unsigned cache_end;
0240       RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
0241                                           cache_end, bin_count);
0242 
0243       //Calculating the size of each bin
0244       for (RandomAccessIter current = first; current != last;)
0245         bin_sizes[unsigned((cast_float_iter<Div_type, RandomAccessIter>(
0246             current++) >> log_divisor) - div_min)]++;
0247       bins[bin_count - 1] = first;
0248       for (int ii = bin_count - 2; ii >= 0; --ii)
0249         bins[ii] = bins[ii + 1] + bin_sizes[ii + 1];
0250 
0251       //Swap into place
0252       RandomAccessIter nextbinstart = first;
0253       //The last bin will always have the correct elements in it
0254       for (int ii = bin_count - 1; ii > 0; --ii)
0255         float_swap_loop<RandomAccessIter, Div_type>
0256           (bins, nextbinstart, ii, bin_sizes, log_divisor, div_min);
0257       //Update the end position because we don't process the last bin
0258       bin_cache[cache_offset] = last;
0259 
0260       //Return if we've completed bucketsorting
0261       if (!log_divisor)
0262         return;
0263 
0264       //Recursing
0265       size_t max_count = get_min_count<float_log_mean_bin_size,
0266                                        float_log_min_split_count,
0267                                        float_log_finishing_count>(log_divisor);
0268       RandomAccessIter lastPos = first;
0269       for (int ii = cache_end - 1; ii >= static_cast<int>(cache_offset);
0270           lastPos = bin_cache[ii], --ii) {
0271         size_t count = bin_cache[ii] - lastPos;
0272         if (count < 2)
0273           continue;
0274         if (count < max_count)
0275           boost::sort::pdqsort(lastPos, bin_cache[ii]);
0276         else
0277           negative_float_sort_rec<RandomAccessIter, Div_type, Size_type>
0278             (lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes);
0279       }
0280     }
0281 
0282     //Sorting negative floats
0283     //Bins are iterated in reverse order because max_neg_float = min_neg_int
0284     template <class RandomAccessIter, class Div_type, class Right_shift,
0285               class Size_type>
0286     inline void
0287     negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last,
0288               std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
0289               , size_t *bin_sizes, Right_shift rshift)
0290     {
0291       Div_type max, min;
0292       if (is_sorted_or_find_extremes(first, last, max, min, rshift))
0293         return;
0294       unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
0295           last - first, rough_log_2_size(Size_type(max - min)));
0296       Div_type div_min = min >> log_divisor;
0297       Div_type div_max = max >> log_divisor;
0298       unsigned bin_count = unsigned(div_max - div_min) + 1;
0299       unsigned cache_end;
0300       RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
0301                                           cache_end, bin_count);
0302 
0303       //Calculating the size of each bin
0304       for (RandomAccessIter current = first; current != last;)
0305         bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++;
0306       bins[bin_count - 1] = first;
0307       for (int ii = bin_count - 2; ii >= 0; --ii)
0308         bins[ii] = bins[ii + 1] + bin_sizes[ii + 1];
0309 
0310       //Swap into place
0311       RandomAccessIter nextbinstart = first;
0312       //The last bin will always have the correct elements in it
0313       for (int ii = bin_count - 1; ii > 0; --ii)
0314         swap_loop<RandomAccessIter, Div_type, Right_shift>
0315           (bins, nextbinstart, ii, rshift, bin_sizes, log_divisor, div_min);
0316       //Update the end position of the unprocessed last bin
0317       bin_cache[cache_offset] = last;
0318 
0319       //Return if we've completed bucketsorting
0320       if (!log_divisor)
0321         return;
0322 
0323       //Recursing
0324       size_t max_count = get_min_count<float_log_mean_bin_size,
0325                                        float_log_min_split_count,
0326                                        float_log_finishing_count>(log_divisor);
0327       RandomAccessIter lastPos = first;
0328       for (int ii = cache_end - 1; ii >= static_cast<int>(cache_offset);
0329           lastPos = bin_cache[ii], --ii) {
0330         size_t count = bin_cache[ii] - lastPos;
0331         if (count < 2)
0332           continue;
0333         if (count < max_count)
0334           boost::sort::pdqsort(lastPos, bin_cache[ii]);
0335         else
0336           negative_float_sort_rec<RandomAccessIter, Div_type, Right_shift,
0337                                   Size_type>
0338             (lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes, rshift);
0339       }
0340     }
0341 
0342     template <class RandomAccessIter, class Div_type, class Right_shift,
0343               class Compare, class Size_type>
0344     inline void
0345     negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last,
0346             std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset,
0347             size_t *bin_sizes, Right_shift rshift, Compare comp)
0348     {
0349       Div_type max, min;
0350       if (is_sorted_or_find_extremes(first, last, max, min, rshift, comp))
0351         return;
0352       unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
0353           last - first, rough_log_2_size(Size_type(max - min)));
0354       Div_type div_min = min >> log_divisor;
0355       Div_type div_max = max >> log_divisor;
0356       unsigned bin_count = unsigned(div_max - div_min) + 1;
0357       unsigned cache_end;
0358       RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
0359                                           cache_end, bin_count);
0360 
0361       //Calculating the size of each bin
0362       for (RandomAccessIter current = first; current != last;)
0363         bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++;
0364       bins[bin_count - 1] = first;
0365       for (int ii = bin_count - 2; ii >= 0; --ii)
0366         bins[ii] = bins[ii + 1] + bin_sizes[ii + 1];
0367 
0368       //Swap into place
0369       RandomAccessIter nextbinstart = first;
0370       //The last bin will always have the correct elements in it
0371       for (int ii = bin_count - 1; ii > 0; --ii)
0372         swap_loop<RandomAccessIter, Div_type, Right_shift>
0373           (bins, nextbinstart, ii, rshift, bin_sizes, log_divisor, div_min);
0374       //Update the end position of the unprocessed last bin
0375       bin_cache[cache_offset] = last;
0376 
0377       //Return if we've completed bucketsorting
0378       if (!log_divisor)
0379         return;
0380 
0381       //Recursing
0382       size_t max_count = get_min_count<float_log_mean_bin_size,
0383                                        float_log_min_split_count,
0384                                        float_log_finishing_count>(log_divisor);
0385       RandomAccessIter lastPos = first;
0386       for (int ii = cache_end - 1; ii >= static_cast<int>(cache_offset);
0387           lastPos = bin_cache[ii], --ii) {
0388         size_t count = bin_cache[ii] - lastPos;
0389         if (count < 2)
0390           continue;
0391         if (count < max_count)
0392           boost::sort::pdqsort(lastPos, bin_cache[ii], comp);
0393         else
0394           negative_float_sort_rec<RandomAccessIter, Div_type, Right_shift,
0395                                   Compare, Size_type>(lastPos, bin_cache[ii],
0396                                                       bin_cache, cache_end,
0397                                                       bin_sizes, rshift, comp);
0398       }
0399     }
0400 
0401     //Casting special-case for floating-point sorting
0402     template <class RandomAccessIter, class Div_type, class Size_type>
0403     inline void
0404     float_sort_rec(RandomAccessIter first, RandomAccessIter last,
0405                 std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
0406                 , size_t *bin_sizes)
0407     {
0408       Div_type max, min;
0409       if (is_sorted_or_find_extremes<RandomAccessIter, Div_type>(first, last, 
0410                                                                 max, min))
0411         return;
0412       unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
0413           last - first, rough_log_2_size(Size_type(max/2 - min/2)) + 1);
0414       Div_type div_min = min >> log_divisor;
0415       Div_type div_max = max >> log_divisor;
0416       unsigned bin_count = unsigned(div_max - div_min) + 1;
0417       unsigned cache_end;
0418       RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
0419                                           cache_end, bin_count);
0420 
0421       //Calculating the size of each bin
0422       for (RandomAccessIter current = first; current != last;)
0423         bin_sizes[unsigned((cast_float_iter<Div_type, RandomAccessIter>(
0424             current++) >> log_divisor) - div_min)]++;
0425       //The index of the first positive bin
0426       //Must be divided small enough to fit into an integer
0427       unsigned first_positive = (div_min < 0) ? unsigned(-div_min) : 0;
0428       //Resetting if all bins are negative
0429       if (cache_offset + first_positive > cache_end)
0430         first_positive = cache_end - cache_offset;
0431       //Reversing the order of the negative bins
0432       //Note that because of the negative/positive ordering direction flip
0433       //We can not depend upon bin order and positions matching up
0434       //so bin_sizes must be reused to contain the end of the bin
0435       if (first_positive > 0) {
0436         bins[first_positive - 1] = first;
0437         for (int ii = first_positive - 2; ii >= 0; --ii) {
0438           bins[ii] = first + bin_sizes[ii + 1];
0439           bin_sizes[ii] += bin_sizes[ii + 1];
0440         }
0441         //Handling positives following negatives
0442         if (first_positive < bin_count) {
0443           bins[first_positive] = first + bin_sizes[0];
0444           bin_sizes[first_positive] += bin_sizes[0];
0445         }
0446       }
0447       else
0448         bins[0] = first;
0449       for (unsigned u = first_positive; u < bin_count - 1; u++) {
0450         bins[u + 1] = first + bin_sizes[u];
0451         bin_sizes[u + 1] += bin_sizes[u];
0452       }
0453 
0454       //Swap into place
0455       RandomAccessIter nextbinstart = first;
0456       for (unsigned u = 0; u < bin_count; ++u) {
0457         nextbinstart = first + bin_sizes[u];
0458         inner_float_swap_loop<RandomAccessIter, Div_type>
0459           (bins, nextbinstart, u, log_divisor, div_min);
0460       }
0461 
0462       if (!log_divisor)
0463         return;
0464 
0465       //Handling negative values first
0466       size_t max_count = get_min_count<float_log_mean_bin_size,
0467                                        float_log_min_split_count,
0468                                        float_log_finishing_count>(log_divisor);
0469       RandomAccessIter lastPos = first;
0470       for (int ii = cache_offset + first_positive - 1; 
0471            ii >= static_cast<int>(cache_offset);
0472            lastPos = bin_cache[ii--]) {
0473         size_t count = bin_cache[ii] - lastPos;
0474         if (count < 2)
0475           continue;
0476         if (count < max_count)
0477           boost::sort::pdqsort(lastPos, bin_cache[ii]);
0478         //sort negative values using reversed-bin spreadsort
0479         else
0480           negative_float_sort_rec<RandomAccessIter, Div_type, Size_type>
0481             (lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes);
0482       }
0483 
0484       for (unsigned u = cache_offset + first_positive; u < cache_end;
0485           lastPos = bin_cache[u], ++u) {
0486         size_t count = bin_cache[u] - lastPos;
0487         if (count < 2)
0488           continue;
0489         if (count < max_count)
0490           boost::sort::pdqsort(lastPos, bin_cache[u]);
0491         //sort positive values using normal spreadsort
0492         else
0493           positive_float_sort_rec<RandomAccessIter, Div_type, Size_type>
0494             (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes);
0495       }
0496     }
0497 
0498     //Functor implementation for recursive sorting
0499     template <class RandomAccessIter, class Div_type, class Right_shift
0500       , class Size_type>
0501     inline void
0502     float_sort_rec(RandomAccessIter first, RandomAccessIter last,
0503               std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
0504               , size_t *bin_sizes, Right_shift rshift)
0505     {
0506       Div_type max, min;
0507       if (is_sorted_or_find_extremes(first, last, max, min, rshift))
0508         return;
0509       unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
0510           last - first, rough_log_2_size(Size_type(max/2 - min/2)) + 1);
0511       Div_type div_min = min >> log_divisor;
0512       Div_type div_max = max >> log_divisor;
0513       unsigned bin_count = unsigned(div_max - div_min) + 1;
0514       unsigned cache_end;
0515       RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
0516                                           cache_end, bin_count);
0517 
0518       //Calculating the size of each bin
0519       for (RandomAccessIter current = first; current != last;)
0520         bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++;
0521       //The index of the first positive bin
0522       unsigned first_positive = (div_min < 0) ? unsigned(-div_min) : 0;
0523       //Resetting if all bins are negative
0524       if (cache_offset + first_positive > cache_end)
0525         first_positive = cache_end - cache_offset;
0526       //Reversing the order of the negative bins
0527       //Note that because of the negative/positive ordering direction flip
0528       //We can not depend upon bin order and positions matching up
0529       //so bin_sizes must be reused to contain the end of the bin
0530       if (first_positive > 0) {
0531         bins[first_positive - 1] = first;
0532         for (int ii = first_positive - 2; ii >= 0; --ii) {
0533           bins[ii] = first + bin_sizes[ii + 1];
0534           bin_sizes[ii] += bin_sizes[ii + 1];
0535         }
0536         //Handling positives following negatives
0537         if (static_cast<unsigned>(first_positive) < bin_count) {
0538           bins[first_positive] = first + bin_sizes[0];
0539           bin_sizes[first_positive] += bin_sizes[0];
0540         }
0541       }
0542       else
0543         bins[0] = first;
0544       for (unsigned u = first_positive; u < bin_count - 1; u++) {
0545         bins[u + 1] = first + bin_sizes[u];
0546         bin_sizes[u + 1] += bin_sizes[u];
0547       }
0548 
0549       //Swap into place
0550       RandomAccessIter next_bin_start = first;
0551       for (unsigned u = 0; u < bin_count; ++u) {
0552         next_bin_start = first + bin_sizes[u];
0553         inner_swap_loop<RandomAccessIter, Div_type, Right_shift>
0554           (bins, next_bin_start, u, rshift, log_divisor, div_min);
0555       }
0556 
0557       //Return if we've completed bucketsorting
0558       if (!log_divisor)
0559         return;
0560 
0561       //Handling negative values first
0562       size_t max_count = get_min_count<float_log_mean_bin_size,
0563                                        float_log_min_split_count,
0564                                        float_log_finishing_count>(log_divisor);
0565       RandomAccessIter lastPos = first;
0566       for (int ii = cache_offset + first_positive - 1; 
0567            ii >= static_cast<int>(cache_offset);
0568            lastPos = bin_cache[ii--]) {
0569         size_t count = bin_cache[ii] - lastPos;
0570         if (count < 2)
0571           continue;
0572         if (count < max_count)
0573           boost::sort::pdqsort(lastPos, bin_cache[ii]);
0574         //sort negative values using reversed-bin spreadsort
0575         else
0576           negative_float_sort_rec<RandomAccessIter, Div_type,
0577             Right_shift, Size_type>(lastPos, bin_cache[ii], bin_cache,
0578                                     cache_end, bin_sizes, rshift);
0579       }
0580 
0581       for (unsigned u = cache_offset + first_positive; u < cache_end;
0582           lastPos = bin_cache[u], ++u) {
0583         size_t count = bin_cache[u] - lastPos;
0584         if (count < 2)
0585           continue;
0586         if (count < max_count)
0587           boost::sort::pdqsort(lastPos, bin_cache[u]);
0588         //sort positive values using normal spreadsort
0589         else
0590           spreadsort_rec<RandomAccessIter, Div_type, Right_shift, Size_type,
0591                           float_log_mean_bin_size, float_log_min_split_count,
0592                           float_log_finishing_count>
0593             (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, rshift);
0594       }
0595     }
0596 
0597     template <class RandomAccessIter, class Div_type, class Right_shift,
0598               class Compare, class Size_type>
0599     inline void
0600     float_sort_rec(RandomAccessIter first, RandomAccessIter last,
0601             std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset,
0602             size_t *bin_sizes, Right_shift rshift, Compare comp)
0603     {
0604       Div_type max, min;
0605       if (is_sorted_or_find_extremes(first, last, max, min, rshift, comp))
0606         return;
0607       unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
0608           last - first, rough_log_2_size(Size_type(max/2 - min/2)) + 1);
0609       Div_type div_min = min >> log_divisor;
0610       Div_type div_max = max >> log_divisor;
0611       unsigned bin_count = unsigned(div_max - div_min) + 1;
0612       unsigned cache_end;
0613       RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
0614                                           cache_end, bin_count);
0615 
0616       //Calculating the size of each bin
0617       for (RandomAccessIter current = first; current != last;)
0618         bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++;
0619       //The index of the first positive bin
0620       unsigned first_positive = 
0621         (div_min < 0) ? static_cast<unsigned>(-div_min) : 0;
0622       //Resetting if all bins are negative
0623       if (cache_offset + first_positive > cache_end)
0624         first_positive = cache_end - cache_offset;
0625       //Reversing the order of the negative bins
0626       //Note that because of the negative/positive ordering direction flip
0627       //We can not depend upon bin order and positions matching up
0628       //so bin_sizes must be reused to contain the end of the bin
0629       if (first_positive > 0) {
0630         bins[first_positive - 1] = first;
0631         for (int ii = first_positive - 2; ii >= 0; --ii) {
0632           bins[ii] = first + bin_sizes[ii + 1];
0633           bin_sizes[ii] += bin_sizes[ii + 1];
0634         }
0635         //Handling positives following negatives
0636         if (static_cast<unsigned>(first_positive) < bin_count) {
0637           bins[first_positive] = first + bin_sizes[0];
0638           bin_sizes[first_positive] += bin_sizes[0];
0639         }
0640       }
0641       else
0642         bins[0] = first;
0643       for (unsigned u = first_positive; u < bin_count - 1; u++) {
0644         bins[u + 1] = first + bin_sizes[u];
0645         bin_sizes[u + 1] += bin_sizes[u];
0646       }
0647 
0648       //Swap into place
0649       RandomAccessIter next_bin_start = first;
0650       for (unsigned u = 0; u < bin_count; ++u) {
0651         next_bin_start = first + bin_sizes[u];
0652         inner_swap_loop<RandomAccessIter, Div_type, Right_shift>
0653           (bins, next_bin_start, u, rshift, log_divisor, div_min);
0654       }
0655 
0656       //Return if we've completed bucketsorting
0657       if (!log_divisor)
0658         return;
0659 
0660       //Handling negative values first
0661       size_t max_count = get_min_count<float_log_mean_bin_size,
0662                                        float_log_min_split_count,
0663                                        float_log_finishing_count>(log_divisor);
0664       RandomAccessIter lastPos = first;
0665       for (int ii = cache_offset + first_positive - 1; 
0666            ii >= static_cast<int>(cache_offset);
0667            lastPos = bin_cache[ii--]) {
0668         size_t count = bin_cache[ii] - lastPos;
0669         if (count < 2)
0670           continue;
0671         if (count < max_count)
0672           boost::sort::pdqsort(lastPos, bin_cache[ii], comp);
0673         //sort negative values using reversed-bin spreadsort
0674         else
0675           negative_float_sort_rec<RandomAccessIter, Div_type, Right_shift,
0676                                   Compare, Size_type>(lastPos, bin_cache[ii],
0677                                                       bin_cache, cache_end,
0678                                                       bin_sizes, rshift, comp);
0679       }
0680 
0681       for (unsigned u = cache_offset + first_positive; u < cache_end;
0682           lastPos = bin_cache[u], ++u) {
0683         size_t count = bin_cache[u] - lastPos;
0684         if (count < 2)
0685           continue;
0686         if (count < max_count)
0687           boost::sort::pdqsort(lastPos, bin_cache[u], comp);
0688         //sort positive values using normal spreadsort
0689         else
0690           spreadsort_rec<RandomAccessIter, Div_type, Right_shift, Compare,
0691                           Size_type, float_log_mean_bin_size,
0692                           float_log_min_split_count, float_log_finishing_count>
0693       (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, rshift, comp);
0694       }
0695     }
0696 
0697     //Checking whether the value type is a float, and trying a 32-bit integer
0698     template <class RandomAccessIter>
0699     inline typename boost::enable_if_c< sizeof(boost::uint32_t) ==
0700       sizeof(typename std::iterator_traits<RandomAccessIter>::value_type)
0701       && std::numeric_limits<typename
0702       std::iterator_traits<RandomAccessIter>::value_type>::is_iec559,
0703       void >::type
0704     float_sort(RandomAccessIter first, RandomAccessIter last)
0705     {
0706       size_t bin_sizes[1 << max_finishing_splits];
0707       std::vector<RandomAccessIter> bin_cache;
0708       float_sort_rec<RandomAccessIter, boost::int32_t, boost::uint32_t>
0709         (first, last, bin_cache, 0, bin_sizes);
0710     }
0711 
0712     //Checking whether the value type is a double, and using a 64-bit integer
0713     template <class RandomAccessIter>
0714     inline typename boost::enable_if_c< sizeof(boost::uint64_t) ==
0715       sizeof(typename std::iterator_traits<RandomAccessIter>::value_type)
0716       && std::numeric_limits<typename
0717       std::iterator_traits<RandomAccessIter>::value_type>::is_iec559,
0718       void >::type
0719     float_sort(RandomAccessIter first, RandomAccessIter last)
0720     {
0721       size_t bin_sizes[1 << max_finishing_splits];
0722       std::vector<RandomAccessIter> bin_cache;
0723       float_sort_rec<RandomAccessIter, boost::int64_t, boost::uint64_t>
0724         (first, last, bin_cache, 0, bin_sizes);
0725     }
0726 
0727     template <class RandomAccessIter>
0728     inline typename boost::disable_if_c< (sizeof(boost::uint64_t) ==
0729       sizeof(typename std::iterator_traits<RandomAccessIter>::value_type)
0730       || sizeof(boost::uint32_t) ==
0731       sizeof(typename std::iterator_traits<RandomAccessIter>::value_type))
0732       && std::numeric_limits<typename
0733       std::iterator_traits<RandomAccessIter>::value_type>::is_iec559,
0734       void >::type
0735     float_sort(RandomAccessIter first, RandomAccessIter last)
0736     {
0737       BOOST_STATIC_ASSERT(!(sizeof(boost::uint64_t) ==
0738       sizeof(typename std::iterator_traits<RandomAccessIter>::value_type)
0739       || sizeof(boost::uint32_t) ==
0740       sizeof(typename std::iterator_traits<RandomAccessIter>::value_type))
0741       || !std::numeric_limits<typename
0742       std::iterator_traits<RandomAccessIter>::value_type>::is_iec559);
0743       boost::sort::pdqsort(first, last);
0744     }
0745 
0746     //These approaches require the user to do the typecast
0747     //with rshift but default comparision
0748     template <class RandomAccessIter, class Div_type, class Right_shift>
0749     inline typename boost::enable_if_c< sizeof(size_t) >= sizeof(Div_type),
0750       void >::type
0751     float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
0752                Right_shift rshift)
0753     {
0754       size_t bin_sizes[1 << max_finishing_splits];
0755       std::vector<RandomAccessIter> bin_cache;
0756       float_sort_rec<RandomAccessIter, Div_type, Right_shift, size_t>
0757         (first, last, bin_cache, 0, bin_sizes, rshift);
0758     }
0759 
0760     //maximum integer size with rshift but default comparision
0761     template <class RandomAccessIter, class Div_type, class Right_shift>
0762     inline typename boost::enable_if_c< sizeof(size_t) < sizeof(Div_type)
0763       && sizeof(boost::uintmax_t) >= sizeof(Div_type), void >::type
0764     float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
0765                Right_shift rshift)
0766     {
0767       size_t bin_sizes[1 << max_finishing_splits];
0768       std::vector<RandomAccessIter> bin_cache;
0769       float_sort_rec<RandomAccessIter, Div_type, Right_shift, boost::uintmax_t>
0770         (first, last, bin_cache, 0, bin_sizes, rshift);
0771     }
0772 
0773     //sizeof(Div_type) doesn't match, so use boost::sort::pdqsort
0774     template <class RandomAccessIter, class Div_type, class Right_shift>
0775     inline typename boost::disable_if_c< sizeof(boost::uintmax_t) >=
0776       sizeof(Div_type), void >::type
0777     float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
0778                Right_shift rshift)
0779     {
0780       boost::sort::pdqsort(first, last);
0781     }
0782 
0783     //specialized comparison
0784     template <class RandomAccessIter, class Div_type, class Right_shift,
0785               class Compare>
0786     inline typename boost::enable_if_c< sizeof(size_t) >= sizeof(Div_type),
0787       void >::type
0788     float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
0789                Right_shift rshift, Compare comp)
0790     {
0791       size_t bin_sizes[1 << max_finishing_splits];
0792       std::vector<RandomAccessIter> bin_cache;
0793       float_sort_rec<RandomAccessIter, Div_type, Right_shift, Compare,
0794         size_t>
0795         (first, last, bin_cache, 0, bin_sizes, rshift, comp);
0796     }
0797 
0798     //max-sized integer with specialized comparison
0799     template <class RandomAccessIter, class Div_type, class Right_shift,
0800               class Compare>
0801     inline typename boost::enable_if_c< sizeof(size_t) < sizeof(Div_type)
0802       && sizeof(boost::uintmax_t) >= sizeof(Div_type), void >::type
0803     float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
0804                Right_shift rshift, Compare comp)
0805     {
0806       size_t bin_sizes[1 << max_finishing_splits];
0807       std::vector<RandomAccessIter> bin_cache;
0808       float_sort_rec<RandomAccessIter, Div_type, Right_shift, Compare,
0809         boost::uintmax_t>
0810         (first, last, bin_cache, 0, bin_sizes, rshift, comp);
0811     }
0812 
0813     //sizeof(Div_type) doesn't match, so use boost::sort::pdqsort
0814     template <class RandomAccessIter, class Div_type, class Right_shift,
0815               class Compare>
0816     inline typename boost::disable_if_c< sizeof(boost::uintmax_t) >=
0817       sizeof(Div_type), void >::type
0818     float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
0819                Right_shift rshift, Compare comp)
0820     {
0821       boost::sort::pdqsort(first, last, comp);
0822     }
0823   }
0824 }
0825 }
0826 }
0827 
0828 #endif