File indexing completed on 2025-01-18 09:51:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef BOOST_SORT_SPREADSORT_DETAIL_INTEGER_SORT_HPP
0016 #define BOOST_SORT_SPREADSORT_DETAIL_INTEGER_SORT_HPP
0017 #include <algorithm>
0018 #include <vector>
0019 #include <limits>
0020 #include <functional>
0021 #include <boost/static_assert.hpp>
0022 #include <boost/utility/enable_if.hpp>
0023 #include <boost/sort/spreadsort/detail/constants.hpp>
0024 #include <boost/sort/spreadsort/detail/spreadsort_common.hpp>
0025 #include <boost/cstdint.hpp>
0026
0027 namespace boost {
0028 namespace sort {
0029 namespace spreadsort {
0030 namespace detail {
0031
0032
0033 template <class RandomAccessIter>
0034 inline bool
0035 is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last,
0036 RandomAccessIter & max, RandomAccessIter & min)
0037 {
0038 min = max = current;
0039
0040 while (!(*(current + 1) < *current)) {
0041
0042 if (++current == last - 1)
0043 return true;
0044 }
0045
0046
0047 max = current;
0048
0049 while (++current < last) {
0050 if (*max < *current)
0051 max = current;
0052 else if (*current < *min)
0053 min = current;
0054 }
0055 return false;
0056 }
0057
0058
0059
0060
0061 template <class RandomAccessIter, class Compare>
0062 inline bool
0063 is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last,
0064 RandomAccessIter & max, RandomAccessIter & min, Compare comp)
0065 {
0066 min = max = current;
0067 while (!comp(*(current + 1), *current)) {
0068
0069 if (++current == last - 1)
0070 return true;
0071 }
0072
0073
0074 max = current;
0075 while (++current < last) {
0076 if (comp(*max, *current))
0077 max = current;
0078 else if (comp(*current, *min))
0079 min = current;
0080 }
0081 return false;
0082 }
0083
0084
0085 template<unsigned log_mean_bin_size>
0086 inline int
0087 get_log_divisor(size_t count, int log_range)
0088 {
0089 int log_divisor;
0090
0091
0092 if ((log_divisor = log_range - rough_log_2_size(count)) <= 0 &&
0093 log_range <= max_finishing_splits)
0094 log_divisor = 0;
0095 else {
0096
0097 log_divisor += log_mean_bin_size;
0098
0099 if ((log_range - log_divisor) > max_splits)
0100 log_divisor = log_range - max_splits;
0101 }
0102 return log_divisor;
0103 }
0104
0105
0106 template <class RandomAccessIter, class Div_type, class Size_type>
0107 inline void
0108 spreadsort_rec(RandomAccessIter first, RandomAccessIter last,
0109 std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
0110 , size_t *bin_sizes)
0111 {
0112
0113
0114
0115
0116 RandomAccessIter max, min;
0117 if (is_sorted_or_find_extremes(first, last, max, min))
0118 return;
0119 RandomAccessIter * target_bin;
0120 unsigned log_divisor = get_log_divisor<int_log_mean_bin_size>(
0121 last - first, rough_log_2_size(Size_type((*max >> 0) - (*min >> 0))));
0122 Div_type div_min = *min >> log_divisor;
0123 Div_type div_max = *max >> log_divisor;
0124 unsigned bin_count = unsigned(div_max - div_min) + 1;
0125 unsigned cache_end;
0126 RandomAccessIter * bins =
0127 size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count);
0128
0129
0130 for (RandomAccessIter current = first; current != last;)
0131 bin_sizes[size_t((*(current++) >> log_divisor) - div_min)]++;
0132
0133 bins[0] = first;
0134 for (unsigned u = 0; u < bin_count - 1; u++)
0135 bins[u + 1] = bins[u] + bin_sizes[u];
0136
0137 RandomAccessIter nextbinstart = first;
0138
0139
0140 for (unsigned u = 0; u < bin_count - 1; ++u) {
0141 RandomAccessIter * local_bin = bins + u;
0142 nextbinstart += bin_sizes[u];
0143
0144 for (RandomAccessIter current = *local_bin; current < nextbinstart;
0145 ++current) {
0146
0147
0148 for (target_bin = (bins + ((*current >> log_divisor) - div_min));
0149 target_bin != local_bin;
0150 target_bin = bins + ((*current >> log_divisor) - div_min)) {
0151
0152
0153
0154 typename std::iterator_traits<RandomAccessIter>::value_type tmp;
0155 RandomAccessIter b = (*target_bin)++;
0156 RandomAccessIter * b_bin = bins + ((*b >> log_divisor) - div_min);
0157 if (b_bin != local_bin) {
0158 RandomAccessIter c = (*b_bin)++;
0159 tmp = *c;
0160 *c = *b;
0161 }
0162 else
0163 tmp = *b;
0164 *b = *current;
0165 *current = tmp;
0166 }
0167 }
0168 *local_bin = nextbinstart;
0169 }
0170 bins[bin_count - 1] = last;
0171
0172
0173 if (!log_divisor)
0174 return;
0175
0176 size_t max_count =
0177 get_min_count<int_log_mean_bin_size, int_log_min_split_count,
0178 int_log_finishing_count>(log_divisor);
0179
0180
0181 RandomAccessIter lastPos = first;
0182 for (unsigned u = cache_offset; u < cache_end; lastPos = bin_cache[u],
0183 ++u) {
0184 Size_type count = bin_cache[u] - lastPos;
0185
0186 if (count < 2)
0187 continue;
0188
0189 if (count < max_count)
0190 boost::sort::pdqsort(lastPos, bin_cache[u]);
0191 else
0192 spreadsort_rec<RandomAccessIter, Div_type, Size_type>(lastPos,
0193 bin_cache[u],
0194 bin_cache,
0195 cache_end,
0196 bin_sizes);
0197 }
0198 }
0199
0200
0201 template <class RandomAccessIter, class Div_type, class Right_shift>
0202 inline void inner_swap_loop(RandomAccessIter * bins,
0203 const RandomAccessIter & next_bin_start, unsigned ii, Right_shift &rshift
0204 , const unsigned log_divisor, const Div_type div_min)
0205 {
0206 RandomAccessIter * local_bin = bins + ii;
0207 for (RandomAccessIter current = *local_bin; current < next_bin_start;
0208 ++current) {
0209 for (RandomAccessIter * target_bin =
0210 (bins + (rshift(*current, log_divisor) - div_min));
0211 target_bin != local_bin;
0212 target_bin = bins + (rshift(*current, log_divisor) - div_min)) {
0213 typename std::iterator_traits<RandomAccessIter>::value_type tmp;
0214 RandomAccessIter b = (*target_bin)++;
0215 RandomAccessIter * b_bin =
0216 bins + (rshift(*b, log_divisor) - div_min);
0217
0218
0219 if (b_bin != local_bin) {
0220 RandomAccessIter c = (*b_bin)++;
0221 tmp = *c;
0222 *c = *b;
0223 }
0224
0225
0226 else
0227 tmp = *b;
0228 *b = *current;
0229 *current = tmp;
0230 }
0231 }
0232 *local_bin = next_bin_start;
0233 }
0234
0235
0236 template <class RandomAccessIter, class Div_type, class Right_shift>
0237 inline void swap_loop(RandomAccessIter * bins,
0238 RandomAccessIter & next_bin_start, unsigned ii, Right_shift &rshift
0239 , const size_t *bin_sizes
0240 , const unsigned log_divisor, const Div_type div_min)
0241 {
0242 next_bin_start += bin_sizes[ii];
0243 inner_swap_loop<RandomAccessIter, Div_type, Right_shift>(bins,
0244 next_bin_start, ii, rshift, log_divisor, div_min);
0245 }
0246
0247
0248 template <class RandomAccessIter, class Div_type, class Right_shift,
0249 class Compare, class Size_type, unsigned log_mean_bin_size,
0250 unsigned log_min_split_count, unsigned log_finishing_count>
0251 inline void
0252 spreadsort_rec(RandomAccessIter first, RandomAccessIter last,
0253 std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
0254 , size_t *bin_sizes, Right_shift rshift, Compare comp)
0255 {
0256 RandomAccessIter max, min;
0257 if (is_sorted_or_find_extremes(first, last, max, min, comp))
0258 return;
0259 unsigned log_divisor = get_log_divisor<log_mean_bin_size>(last - first,
0260 rough_log_2_size(Size_type(rshift(*max, 0) - rshift(*min, 0))));
0261 Div_type div_min = rshift(*min, log_divisor);
0262 Div_type div_max = rshift(*max, log_divisor);
0263 unsigned bin_count = unsigned(div_max - div_min) + 1;
0264 unsigned cache_end;
0265 RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
0266 cache_end, bin_count);
0267
0268
0269 for (RandomAccessIter current = first; current != last;)
0270 bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++;
0271 bins[0] = first;
0272 for (unsigned u = 0; u < bin_count - 1; u++)
0273 bins[u + 1] = bins[u] + bin_sizes[u];
0274
0275
0276 RandomAccessIter next_bin_start = first;
0277 for (unsigned u = 0; u < bin_count - 1; ++u)
0278 swap_loop<RandomAccessIter, Div_type, Right_shift>(bins, next_bin_start,
0279 u, rshift, bin_sizes, log_divisor, div_min);
0280 bins[bin_count - 1] = last;
0281
0282
0283 if (!log_divisor)
0284 return;
0285
0286
0287 size_t max_count = get_min_count<log_mean_bin_size, log_min_split_count,
0288 log_finishing_count>(log_divisor);
0289 RandomAccessIter lastPos = first;
0290 for (unsigned u = cache_offset; u < cache_end; lastPos = bin_cache[u],
0291 ++u) {
0292 size_t count = bin_cache[u] - lastPos;
0293 if (count < 2)
0294 continue;
0295 if (count < max_count)
0296 boost::sort::pdqsort(lastPos, bin_cache[u], comp);
0297 else
0298 spreadsort_rec<RandomAccessIter, Div_type, Right_shift, Compare,
0299 Size_type, log_mean_bin_size, log_min_split_count, log_finishing_count>
0300 (lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, rshift, comp);
0301 }
0302 }
0303
0304
0305 template <class RandomAccessIter, class Div_type, class Right_shift,
0306 class Size_type, unsigned log_mean_bin_size,
0307 unsigned log_min_split_count, unsigned log_finishing_count>
0308 inline void
0309 spreadsort_rec(RandomAccessIter first, RandomAccessIter last,
0310 std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
0311 , size_t *bin_sizes, Right_shift rshift)
0312 {
0313 RandomAccessIter max, min;
0314 if (is_sorted_or_find_extremes(first, last, max, min))
0315 return;
0316 unsigned log_divisor = get_log_divisor<log_mean_bin_size>(last - first,
0317 rough_log_2_size(Size_type(rshift(*max, 0) - rshift(*min, 0))));
0318 Div_type div_min = rshift(*min, log_divisor);
0319 Div_type div_max = rshift(*max, log_divisor);
0320 unsigned bin_count = unsigned(div_max - div_min) + 1;
0321 unsigned cache_end;
0322 RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset,
0323 cache_end, bin_count);
0324
0325
0326 for (RandomAccessIter current = first; current != last;)
0327 bin_sizes[unsigned(rshift(*(current++), log_divisor) - div_min)]++;
0328 bins[0] = first;
0329 for (unsigned u = 0; u < bin_count - 1; u++)
0330 bins[u + 1] = bins[u] + bin_sizes[u];
0331
0332
0333 RandomAccessIter nextbinstart = first;
0334 for (unsigned ii = 0; ii < bin_count - 1; ++ii)
0335 swap_loop<RandomAccessIter, Div_type, Right_shift>(bins, nextbinstart,
0336 ii, rshift, bin_sizes, log_divisor, div_min);
0337 bins[bin_count - 1] = last;
0338
0339
0340 if (!log_divisor)
0341 return;
0342
0343
0344 size_t max_count = get_min_count<log_mean_bin_size, log_min_split_count,
0345 log_finishing_count>(log_divisor);
0346 RandomAccessIter lastPos = first;
0347 for (unsigned u = cache_offset; u < cache_end; lastPos = bin_cache[u],
0348 ++u) {
0349 size_t count = bin_cache[u] - lastPos;
0350 if (count < 2)
0351 continue;
0352 if (count < max_count)
0353 boost::sort::pdqsort(lastPos, bin_cache[u]);
0354 else
0355 spreadsort_rec<RandomAccessIter, Div_type, Right_shift, Size_type,
0356 log_mean_bin_size, log_min_split_count, log_finishing_count>(lastPos,
0357 bin_cache[u], bin_cache, cache_end, bin_sizes, rshift);
0358 }
0359 }
0360
0361
0362 template <class RandomAccessIter, class Div_type>
0363
0364 inline typename boost::enable_if_c< sizeof(Div_type) <= sizeof(size_t),
0365 void >::type
0366 integer_sort(RandomAccessIter first, RandomAccessIter last, Div_type)
0367 {
0368 size_t bin_sizes[1 << max_finishing_splits];
0369 std::vector<RandomAccessIter> bin_cache;
0370 spreadsort_rec<RandomAccessIter, Div_type, size_t>(first, last,
0371 bin_cache, 0, bin_sizes);
0372 }
0373
0374
0375 template <class RandomAccessIter, class Div_type>
0376
0377 inline typename boost::enable_if_c< (sizeof(Div_type) > sizeof(size_t))
0378 && sizeof(Div_type) <= sizeof(boost::uintmax_t), void >::type
0379 integer_sort(RandomAccessIter first, RandomAccessIter last, Div_type)
0380 {
0381 size_t bin_sizes[1 << max_finishing_splits];
0382 std::vector<RandomAccessIter> bin_cache;
0383 spreadsort_rec<RandomAccessIter, Div_type, boost::uintmax_t>(first,
0384 last, bin_cache, 0, bin_sizes);
0385 }
0386
0387 template <class RandomAccessIter, class Div_type>
0388 inline typename boost::disable_if_c< sizeof(Div_type) <= sizeof(size_t)
0389 || sizeof(Div_type) <= sizeof(boost::uintmax_t), void >::type
0390
0391 integer_sort(RandomAccessIter first, RandomAccessIter last, Div_type)
0392 {
0393 boost::sort::pdqsort(first, last);
0394 }
0395
0396
0397
0398 template <class RandomAccessIter, class Div_type, class Right_shift,
0399 class Compare>
0400
0401 inline typename boost::enable_if_c< sizeof(Div_type) <= sizeof(size_t),
0402 void >::type
0403 integer_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
0404 Right_shift shift, Compare comp)
0405 {
0406 size_t bin_sizes[1 << max_finishing_splits];
0407 std::vector<RandomAccessIter> bin_cache;
0408 spreadsort_rec<RandomAccessIter, Div_type, Right_shift, Compare,
0409 size_t, int_log_mean_bin_size, int_log_min_split_count,
0410 int_log_finishing_count>
0411 (first, last, bin_cache, 0, bin_sizes, shift, comp);
0412 }
0413
0414 template <class RandomAccessIter, class Div_type, class Right_shift,
0415 class Compare>
0416
0417 inline typename boost::enable_if_c< (sizeof(Div_type) > sizeof(size_t))
0418 && sizeof(Div_type) <= sizeof(boost::uintmax_t), void >::type
0419 integer_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
0420 Right_shift shift, Compare comp)
0421 {
0422 size_t bin_sizes[1 << max_finishing_splits];
0423 std::vector<RandomAccessIter> bin_cache;
0424 spreadsort_rec<RandomAccessIter, Div_type, Right_shift, Compare,
0425 boost::uintmax_t, int_log_mean_bin_size,
0426 int_log_min_split_count, int_log_finishing_count>
0427 (first, last, bin_cache, 0, bin_sizes, shift, comp);
0428 }
0429
0430 template <class RandomAccessIter, class Div_type, class Right_shift,
0431 class Compare>
0432 inline typename boost::disable_if_c< sizeof(Div_type) <= sizeof(size_t)
0433 || sizeof(Div_type) <= sizeof(boost::uintmax_t), void >::type
0434
0435 integer_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
0436 Right_shift shift, Compare comp)
0437 {
0438 boost::sort::pdqsort(first, last, comp);
0439 }
0440
0441
0442
0443 template <class RandomAccessIter, class Div_type, class Right_shift>
0444
0445 inline typename boost::enable_if_c< sizeof(Div_type) <= sizeof(size_t),
0446 void >::type
0447 integer_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
0448 Right_shift shift)
0449 {
0450 size_t bin_sizes[1 << max_finishing_splits];
0451 std::vector<RandomAccessIter> bin_cache;
0452 spreadsort_rec<RandomAccessIter, Div_type, Right_shift, size_t,
0453 int_log_mean_bin_size, int_log_min_split_count,
0454 int_log_finishing_count>
0455 (first, last, bin_cache, 0, bin_sizes, shift);
0456 }
0457
0458 template <class RandomAccessIter, class Div_type, class Right_shift>
0459
0460 inline typename boost::enable_if_c< (sizeof(Div_type) > sizeof(size_t))
0461 && sizeof(Div_type) <= sizeof(boost::uintmax_t), void >::type
0462 integer_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
0463 Right_shift shift)
0464 {
0465 size_t bin_sizes[1 << max_finishing_splits];
0466 std::vector<RandomAccessIter> bin_cache;
0467 spreadsort_rec<RandomAccessIter, Div_type, Right_shift,
0468 boost::uintmax_t, int_log_mean_bin_size,
0469 int_log_min_split_count, int_log_finishing_count>
0470 (first, last, bin_cache, 0, bin_sizes, shift);
0471 }
0472
0473 template <class RandomAccessIter, class Div_type, class Right_shift>
0474 inline typename boost::disable_if_c< sizeof(Div_type) <= sizeof(size_t)
0475 || sizeof(Div_type) <= sizeof(boost::uintmax_t), void >::type
0476
0477 integer_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
0478 Right_shift shift)
0479 {
0480 boost::sort::pdqsort(first, last);
0481 }
0482 }
0483 }
0484 }
0485 }
0486
0487 #endif