// Details for templated Spreadsort-based float_sort. // Copyright Steven J. Ross 2001 - 2014. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // See http://www.boost.org/libs/sort for library home page. /* Some improvements suggested by: Phil Endecott and Frank Gennari float_mem_cast fix provided by: Scott McMurray */ #ifndef BOOST_SORT_SPREADSORT_DETAIL_FLOAT_SORT_HPP #define BOOST_SORT_SPREADSORT_DETAIL_FLOAT_SORT_HPP #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace sort { namespace spreadsort { namespace detail { //Casts a RandomAccessIter to the specified integer type template inline Cast_type cast_float_iter(const RandomAccessIter & floatiter) { typedef typename std::iterator_traits::value_type Data_type; //Only cast IEEE floating-point numbers, and only to same-sized integers BOOST_STATIC_ASSERT(sizeof(Cast_type) == sizeof(Data_type)); BOOST_STATIC_ASSERT(std::numeric_limits::is_iec559); BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); Cast_type result; std::memcpy(&result, &(*floatiter), sizeof(Data_type)); return result; } // Return true if the list is sorted. Otherwise, find the minimum and // maximum. Values are Right_shifted 0 bits before comparison. template inline bool is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last, Div_type & max, Div_type & min, Right_shift rshift) { min = max = rshift(*current, 0); RandomAccessIter prev = current; bool sorted = true; while (++current < last) { Div_type value = rshift(*current, 0); sorted &= *current >= *prev; prev = current; if (max < value) max = value; else if (value < min) min = value; } return sorted; } // Return true if the list is sorted. Otherwise, find the minimum and // maximum. Uses comp to check if the data is already sorted. template inline bool is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last, Div_type & max, Div_type & min, Right_shift rshift, Compare comp) { min = max = rshift(*current, 0); RandomAccessIter prev = current; bool sorted = true; while (++current < last) { Div_type value = rshift(*current, 0); sorted &= !comp(*current, *prev); prev = current; if (max < value) max = value; else if (value < min) min = value; } return sorted; } //Specialized swap loops for floating-point casting template inline void inner_float_swap_loop(RandomAccessIter * bins, const RandomAccessIter & nextbinstart, unsigned ii , const unsigned log_divisor, const Div_type div_min) { RandomAccessIter * local_bin = bins + ii; for (RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { for (RandomAccessIter * target_bin = (bins + ((cast_float_iter(current) >> log_divisor) - div_min)); target_bin != local_bin; target_bin = bins + ((cast_float_iter (current) >> log_divisor) - div_min)) { typename std::iterator_traits::value_type tmp; RandomAccessIter b = (*target_bin)++; RandomAccessIter * b_bin = bins + ((cast_float_iter(b) >> log_divisor) - div_min); //Three-way swap; if the item to be swapped doesn't belong in the //current bin, swap it to where it belongs if (b_bin != local_bin) { RandomAccessIter c = (*b_bin)++; tmp = *c; *c = *b; } else tmp = *b; *b = *current; *current = tmp; } } *local_bin = nextbinstart; } template inline void float_swap_loop(RandomAccessIter * bins, RandomAccessIter & nextbinstart, unsigned ii, const size_t *bin_sizes, const unsigned log_divisor, const Div_type div_min) { nextbinstart += bin_sizes[ii]; inner_float_swap_loop (bins, nextbinstart, ii, log_divisor, div_min); } // Return true if the list is sorted. Otherwise, find the minimum and // maximum. Values are cast to Cast_type before comparison. template inline bool is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last, Cast_type & max, Cast_type & min) { min = max = cast_float_iter(current); RandomAccessIter prev = current; bool sorted = true; while (++current < last) { Cast_type value = cast_float_iter(current); sorted &= *current >= *prev; prev = current; if (max < value) max = value; else if (value < min) min = value; } return sorted; } //Special-case sorting of positive floats with casting template inline void positive_float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset , size_t *bin_sizes) { Div_type max, min; if (is_sorted_or_find_extremes(first, last, max, min)) return; unsigned log_divisor = get_log_divisor( last - first, rough_log_2_size(Size_type(max - min))); Div_type div_min = min >> log_divisor; Div_type div_max = max >> log_divisor; unsigned bin_count = unsigned(div_max - div_min) + 1; unsigned cache_end; RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); //Calculating the size of each bin for (RandomAccessIter current = first; current != last;) bin_sizes[unsigned((cast_float_iter( current++) >> log_divisor) - div_min)]++; bins[0] = first; for (unsigned u = 0; u < bin_count - 1; u++) bins[u + 1] = bins[u] + bin_sizes[u]; //Swap into place RandomAccessIter nextbinstart = first; for (unsigned u = 0; u < bin_count - 1; ++u) float_swap_loop (bins, nextbinstart, u, bin_sizes, log_divisor, div_min); bins[bin_count - 1] = last; //Return if we've completed bucketsorting if (!log_divisor) return; //Recursing size_t max_count = get_min_count(log_divisor); RandomAccessIter lastPos = first; for (unsigned u = cache_offset; u < cache_end; lastPos = bin_cache[u], ++u) { size_t count = bin_cache[u] - lastPos; if (count < 2) continue; if (count < max_count) std::sort(lastPos, bin_cache[u]); else positive_float_sort_rec (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes); } } //Sorting negative floats //Bins are iterated in reverse because max_neg_float = min_neg_int template inline void negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset, size_t *bin_sizes) { Div_type max, min; if (is_sorted_or_find_extremes(first, last, max, min)) return; unsigned log_divisor = get_log_divisor( last - first, rough_log_2_size(Size_type(max - min))); Div_type div_min = min >> log_divisor; Div_type div_max = max >> log_divisor; unsigned bin_count = unsigned(div_max - div_min) + 1; unsigned cache_end; RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); //Calculating the size of each bin for (RandomAccessIter current = first; current != last;) bin_sizes[unsigned((cast_float_iter( current++) >> log_divisor) - div_min)]++; bins[bin_count - 1] = first; for (int ii = bin_count - 2; ii >= 0; --ii) bins[ii] = bins[ii + 1] + bin_sizes[ii + 1]; //Swap into place RandomAccessIter nextbinstart = first; //The last bin will always have the correct elements in it for (int ii = bin_count - 1; ii > 0; --ii) float_swap_loop (bins, nextbinstart, ii, bin_sizes, log_divisor, div_min); //Update the end position because we don't process the last bin bin_cache[cache_offset] = last; //Return if we've completed bucketsorting if (!log_divisor) return; //Recursing size_t max_count = get_min_count(log_divisor); RandomAccessIter lastPos = first; for (int ii = cache_end - 1; ii >= static_cast(cache_offset); lastPos = bin_cache[ii], --ii) { size_t count = bin_cache[ii] - lastPos; if (count < 2) continue; if (count < max_count) std::sort(lastPos, bin_cache[ii]); else negative_float_sort_rec (lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes); } } //Sorting negative floats //Bins are iterated in reverse order because max_neg_float = min_neg_int template inline void negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset , size_t *bin_sizes, Right_shift rshift) { Div_type max, min; if (is_sorted_or_find_extremes(first, last, max, min, rshift)) return; unsigned log_divisor = get_log_divisor( last - first, rough_log_2_size(Size_type(max - min))); Div_type div_min = min >> log_divisor; Div_type div_max = max >> log_divisor; unsigned bin_count = unsigned(div_max - div_min) + 1; unsigned cache_end; RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); //Calculating the size of each bin for (RandomAccessIter current = first; current != last;) bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++; bins[bin_count - 1] = first; for (int ii = bin_count - 2; ii >= 0; --ii) bins[ii] = bins[ii + 1] + bin_sizes[ii + 1]; //Swap into place RandomAccessIter nextbinstart = first; //The last bin will always have the correct elements in it for (int ii = bin_count - 1; ii > 0; --ii) swap_loop (bins, nextbinstart, ii, rshift, bin_sizes, log_divisor, div_min); //Update the end position of the unprocessed last bin bin_cache[cache_offset] = last; //Return if we've completed bucketsorting if (!log_divisor) return; //Recursing size_t max_count = get_min_count(log_divisor); RandomAccessIter lastPos = first; for (int ii = cache_end - 1; ii >= static_cast(cache_offset); lastPos = bin_cache[ii], --ii) { size_t count = bin_cache[ii] - lastPos; if (count < 2) continue; if (count < max_count) std::sort(lastPos, bin_cache[ii]); else negative_float_sort_rec (lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes, rshift); } } template inline void negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset, size_t *bin_sizes, Right_shift rshift, Compare comp) { Div_type max, min; if (is_sorted_or_find_extremes(first, last, max, min, rshift, comp)) return; unsigned log_divisor = get_log_divisor( last - first, rough_log_2_size(Size_type(max - min))); Div_type div_min = min >> log_divisor; Div_type div_max = max >> log_divisor; unsigned bin_count = unsigned(div_max - div_min) + 1; unsigned cache_end; RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); //Calculating the size of each bin for (RandomAccessIter current = first; current != last;) bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++; bins[bin_count - 1] = first; for (int ii = bin_count - 2; ii >= 0; --ii) bins[ii] = bins[ii + 1] + bin_sizes[ii + 1]; //Swap into place RandomAccessIter nextbinstart = first; //The last bin will always have the correct elements in it for (int ii = bin_count - 1; ii > 0; --ii) swap_loop (bins, nextbinstart, ii, rshift, bin_sizes, log_divisor, div_min); //Update the end position of the unprocessed last bin bin_cache[cache_offset] = last; //Return if we've completed bucketsorting if (!log_divisor) return; //Recursing size_t max_count = get_min_count(log_divisor); RandomAccessIter lastPos = first; for (int ii = cache_end - 1; ii >= static_cast(cache_offset); lastPos = bin_cache[ii], --ii) { size_t count = bin_cache[ii] - lastPos; if (count < 2) continue; if (count < max_count) std::sort(lastPos, bin_cache[ii], comp); else negative_float_sort_rec(lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes, rshift, comp); } } //Casting special-case for floating-point sorting template inline void float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset , size_t *bin_sizes) { Div_type max, min; if (is_sorted_or_find_extremes(first, last, max, min)) return; unsigned log_divisor = get_log_divisor( last - first, rough_log_2_size(Size_type(max - min))); Div_type div_min = min >> log_divisor; Div_type div_max = max >> log_divisor; unsigned bin_count = unsigned(div_max - div_min) + 1; unsigned cache_end; RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); //Calculating the size of each bin for (RandomAccessIter current = first; current != last;) bin_sizes[unsigned((cast_float_iter( current++) >> log_divisor) - div_min)]++; //The index of the first positive bin //Must be divided small enough to fit into an integer unsigned first_positive = (div_min < 0) ? unsigned(-div_min) : 0; //Resetting if all bins are negative if (cache_offset + first_positive > cache_end) first_positive = cache_end - cache_offset; //Reversing the order of the negative bins //Note that because of the negative/positive ordering direction flip //We can not depend upon bin order and positions matching up //so bin_sizes must be reused to contain the end of the bin if (first_positive > 0) { bins[first_positive - 1] = first; for (int ii = first_positive - 2; ii >= 0; --ii) { bins[ii] = first + bin_sizes[ii + 1]; bin_sizes[ii] += bin_sizes[ii + 1]; } //Handling positives following negatives if (first_positive < bin_count) { bins[first_positive] = first + bin_sizes[0]; bin_sizes[first_positive] += bin_sizes[0]; } } else bins[0] = first; for (unsigned u = first_positive; u < bin_count - 1; u++) { bins[u + 1] = first + bin_sizes[u]; bin_sizes[u + 1] += bin_sizes[u]; } //Swap into place RandomAccessIter nextbinstart = first; for (unsigned u = 0; u < bin_count; ++u) { nextbinstart = first + bin_sizes[u]; inner_float_swap_loop (bins, nextbinstart, u, log_divisor, div_min); } if (!log_divisor) return; //Handling negative values first size_t max_count = get_min_count(log_divisor); RandomAccessIter lastPos = first; for (int ii = cache_offset + first_positive - 1; ii >= static_cast(cache_offset); lastPos = bin_cache[ii--]) { size_t count = bin_cache[ii] - lastPos; if (count < 2) continue; if (count < max_count) std::sort(lastPos, bin_cache[ii]); //sort negative values using reversed-bin spreadsort else negative_float_sort_rec (lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes); } for (unsigned u = cache_offset + first_positive; u < cache_end; lastPos = bin_cache[u], ++u) { size_t count = bin_cache[u] - lastPos; if (count < 2) continue; if (count < max_count) std::sort(lastPos, bin_cache[u]); //sort positive values using normal spreadsort else positive_float_sort_rec (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes); } } //Functor implementation for recursive sorting template inline void float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset , size_t *bin_sizes, Right_shift rshift) { Div_type max, min; if (is_sorted_or_find_extremes(first, last, max, min, rshift)) return; unsigned log_divisor = get_log_divisor( last - first, rough_log_2_size(Size_type(max - min))); Div_type div_min = min >> log_divisor; Div_type div_max = max >> log_divisor; unsigned bin_count = unsigned(div_max - div_min) + 1; unsigned cache_end; RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); //Calculating the size of each bin for (RandomAccessIter current = first; current != last;) bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++; //The index of the first positive bin unsigned first_positive = (div_min < 0) ? unsigned(-div_min) : 0; //Resetting if all bins are negative if (cache_offset + first_positive > cache_end) first_positive = cache_end - cache_offset; //Reversing the order of the negative bins //Note that because of the negative/positive ordering direction flip //We can not depend upon bin order and positions matching up //so bin_sizes must be reused to contain the end of the bin if (first_positive > 0) { bins[first_positive - 1] = first; for (int ii = first_positive - 2; ii >= 0; --ii) { bins[ii] = first + bin_sizes[ii + 1]; bin_sizes[ii] += bin_sizes[ii + 1]; } //Handling positives following negatives if (static_cast(first_positive) < bin_count) { bins[first_positive] = first + bin_sizes[0]; bin_sizes[first_positive] += bin_sizes[0]; } } else bins[0] = first; for (unsigned u = first_positive; u < bin_count - 1; u++) { bins[u + 1] = first + bin_sizes[u]; bin_sizes[u + 1] += bin_sizes[u]; } //Swap into place RandomAccessIter next_bin_start = first; for (unsigned u = 0; u < bin_count; ++u) { next_bin_start = first + bin_sizes[u]; inner_swap_loop (bins, next_bin_start, u, rshift, log_divisor, div_min); } //Return if we've completed bucketsorting if (!log_divisor) return; //Handling negative values first size_t max_count = get_min_count(log_divisor); RandomAccessIter lastPos = first; for (int ii = cache_offset + first_positive - 1; ii >= static_cast(cache_offset); lastPos = bin_cache[ii--]) { size_t count = bin_cache[ii] - lastPos; if (count < 2) continue; if (count < max_count) std::sort(lastPos, bin_cache[ii]); //sort negative values using reversed-bin spreadsort else negative_float_sort_rec(lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes, rshift); } for (unsigned u = cache_offset + first_positive; u < cache_end; lastPos = bin_cache[u], ++u) { size_t count = bin_cache[u] - lastPos; if (count < 2) continue; if (count < max_count) std::sort(lastPos, bin_cache[u]); //sort positive values using normal spreadsort else spreadsort_rec (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, rshift); } } template inline void float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset, size_t *bin_sizes, Right_shift rshift, Compare comp) { Div_type max, min; if (is_sorted_or_find_extremes(first, last, max, min, rshift, comp)) return; unsigned log_divisor = get_log_divisor( last - first, rough_log_2_size(Size_type(max - min))); Div_type div_min = min >> log_divisor; Div_type div_max = max >> log_divisor; unsigned bin_count = unsigned(div_max - div_min) + 1; unsigned cache_end; RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); //Calculating the size of each bin for (RandomAccessIter current = first; current != last;) bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++; //The index of the first positive bin unsigned first_positive = (div_min < 0) ? static_cast(-div_min) : 0; //Resetting if all bins are negative if (cache_offset + first_positive > cache_end) first_positive = cache_end - cache_offset; //Reversing the order of the negative bins //Note that because of the negative/positive ordering direction flip //We can not depend upon bin order and positions matching up //so bin_sizes must be reused to contain the end of the bin if (first_positive > 0) { bins[first_positive - 1] = first; for (int ii = first_positive - 2; ii >= 0; --ii) { bins[ii] = first + bin_sizes[ii + 1]; bin_sizes[ii] += bin_sizes[ii + 1]; } //Handling positives following negatives if (static_cast(first_positive) < bin_count) { bins[first_positive] = first + bin_sizes[0]; bin_sizes[first_positive] += bin_sizes[0]; } } else bins[0] = first; for (unsigned u = first_positive; u < bin_count - 1; u++) { bins[u + 1] = first + bin_sizes[u]; bin_sizes[u + 1] += bin_sizes[u]; } //Swap into place RandomAccessIter next_bin_start = first; for (unsigned u = 0; u < bin_count; ++u) { next_bin_start = first + bin_sizes[u]; inner_swap_loop (bins, next_bin_start, u, rshift, log_divisor, div_min); } //Return if we've completed bucketsorting if (!log_divisor) return; //Handling negative values first size_t max_count = get_min_count(log_divisor); RandomAccessIter lastPos = first; for (int ii = cache_offset + first_positive - 1; ii >= static_cast(cache_offset); lastPos = bin_cache[ii--]) { size_t count = bin_cache[ii] - lastPos; if (count < 2) continue; if (count < max_count) std::sort(lastPos, bin_cache[ii], comp); //sort negative values using reversed-bin spreadsort else negative_float_sort_rec(lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes, rshift, comp); } for (unsigned u = cache_offset + first_positive; u < cache_end; lastPos = bin_cache[u], ++u) { size_t count = bin_cache[u] - lastPos; if (count < 2) continue; if (count < max_count) std::sort(lastPos, bin_cache[u], comp); //sort positive values using normal spreadsort else spreadsort_rec (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, rshift, comp); } } //Checking whether the value type is a float, and trying a 32-bit integer template inline typename boost::enable_if_c< sizeof(boost::uint32_t) == sizeof(typename std::iterator_traits::value_type) && std::numeric_limits::value_type>::is_iec559, void >::type float_sort(RandomAccessIter first, RandomAccessIter last) { size_t bin_sizes[1 << max_finishing_splits]; std::vector bin_cache; float_sort_rec (first, last, bin_cache, 0, bin_sizes); } //Checking whether the value type is a double, and using a 64-bit integer template inline typename boost::enable_if_c< sizeof(boost::uint64_t) == sizeof(typename std::iterator_traits::value_type) && std::numeric_limits::value_type>::is_iec559, void >::type float_sort(RandomAccessIter first, RandomAccessIter last) { size_t bin_sizes[1 << max_finishing_splits]; std::vector bin_cache; float_sort_rec (first, last, bin_cache, 0, bin_sizes); } template inline typename boost::disable_if_c< (sizeof(boost::uint64_t) == sizeof(typename std::iterator_traits::value_type) || sizeof(boost::uint32_t) == sizeof(typename std::iterator_traits::value_type)) && std::numeric_limits::value_type>::is_iec559, void >::type float_sort(RandomAccessIter first, RandomAccessIter last) { BOOST_STATIC_WARNING(!(sizeof(boost::uint64_t) == sizeof(typename std::iterator_traits::value_type) || sizeof(boost::uint32_t) == sizeof(typename std::iterator_traits::value_type)) || !std::numeric_limits::value_type>::is_iec559); std::sort(first, last); } //These approaches require the user to do the typecast //with rshift but default comparision template inline typename boost::enable_if_c< sizeof(size_t) >= sizeof(Div_type), void >::type float_sort(RandomAccessIter first, RandomAccessIter last, Div_type, Right_shift rshift) { size_t bin_sizes[1 << max_finishing_splits]; std::vector bin_cache; float_sort_rec (first, last, bin_cache, 0, bin_sizes, rshift); } //maximum integer size with rshift but default comparision template inline typename boost::enable_if_c< sizeof(size_t) < sizeof(Div_type) && sizeof(boost::uintmax_t) >= sizeof(Div_type), void >::type float_sort(RandomAccessIter first, RandomAccessIter last, Div_type, Right_shift rshift) { size_t bin_sizes[1 << max_finishing_splits]; std::vector bin_cache; float_sort_rec (first, last, bin_cache, 0, bin_sizes, rshift); } //sizeof(Div_type) doesn't match, so use std::sort template inline typename boost::disable_if_c< sizeof(boost::uintmax_t) >= sizeof(Div_type), void >::type float_sort(RandomAccessIter first, RandomAccessIter last, Div_type, Right_shift rshift) { BOOST_STATIC_WARNING(sizeof(boost::uintmax_t) >= sizeof(Div_type)); std::sort(first, last); } //specialized comparison template inline typename boost::enable_if_c< sizeof(size_t) >= sizeof(Div_type), void >::type float_sort(RandomAccessIter first, RandomAccessIter last, Div_type, Right_shift rshift, Compare comp) { size_t bin_sizes[1 << max_finishing_splits]; std::vector bin_cache; float_sort_rec (first, last, bin_cache, 0, bin_sizes, rshift, comp); } //max-sized integer with specialized comparison template inline typename boost::enable_if_c< sizeof(size_t) < sizeof(Div_type) && sizeof(boost::uintmax_t) >= sizeof(Div_type), void >::type float_sort(RandomAccessIter first, RandomAccessIter last, Div_type, Right_shift rshift, Compare comp) { size_t bin_sizes[1 << max_finishing_splits]; std::vector bin_cache; float_sort_rec (first, last, bin_cache, 0, bin_sizes, rshift, comp); } //sizeof(Div_type) doesn't match, so use std::sort template inline typename boost::disable_if_c< sizeof(boost::uintmax_t) >= sizeof(Div_type), void >::type float_sort(RandomAccessIter first, RandomAccessIter last, Div_type, Right_shift rshift, Compare comp) { BOOST_STATIC_WARNING(sizeof(boost::uintmax_t) >= sizeof(Div_type)); std::sort(first, last, comp); } } } } } #endif