File indexing completed on 2025-01-18 09:51:47
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef __BOOST_SORT_PARALLEL_ALGORITHM_SPIN_SORT_HPP
0014 #define __BOOST_SORT_PARALLEL_ALGORITHM_SPIN_SORT_HPP
0015
0016
0017 #include <ciso646>
0018 #include <cstdlib>
0019 #include <functional>
0020 #include <iterator>
0021 #include <memory>
0022 #include <type_traits>
0023 #include <vector>
0024 #include <cstddef>
0025 #include <boost/sort/insert_sort/insert_sort.hpp>
0026 #include <boost/sort/common/util/traits.hpp>
0027 #include <boost/sort/common/util/algorithm.hpp>
0028 #include <boost/sort/common/range.hpp>
0029 #include <boost/sort/common/indirect.hpp>
0030
0031
0032 namespace boost
0033 {
0034 namespace sort
0035 {
0036 namespace spin_detail
0037 {
0038
0039
0040
0041
0042 namespace bsc = boost::sort::common;
0043 using bsc::range;
0044 using bsc::util::nbits64;
0045 using bsc::util::compare_iter;
0046 using bsc::util::value_iter;
0047 using boost::sort::insert_sort;
0048
0049
0050
0051
0052
0053
0054
0055
0056 template <class Iter1_t, class Iter2_t, typename Compare>
0057 static void insert_partial_sort (Iter1_t first, Iter1_t mid,
0058 Iter1_t last, Compare comp,
0059 const range<Iter2_t> &rng_aux);
0060
0061 template<class Iter1_t, class Iter2_t, class Compare>
0062 static bool check_stable_sort (const range<Iter1_t> &rng_data,
0063 const range<Iter2_t> &rng_aux, Compare comp);
0064
0065 template<class Iter1_t, class Iter2_t, class Compare>
0066 static void range_sort (const range<Iter1_t> &range1,
0067 const range<Iter2_t> &range2, Compare comp,
0068 uint32_t level);
0069
0070 template<class Iter1_t, class Iter2_t, class Compare>
0071 static void sort_range_sort (const range<Iter1_t> &rng_data,
0072 const range<Iter2_t> &rng_aux, Compare comp);
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085 template<class Iter1_t, class Iter2_t, typename Compare>
0086 static void insert_partial_sort (Iter1_t first, Iter1_t mid, Iter1_t last,
0087 Compare comp, const range <Iter2_t> &rng_aux)
0088 {
0089
0090
0091
0092 typedef value_iter<Iter1_t> value_t;
0093 typedef value_iter<Iter2_t> value2_t;
0094 static_assert (std::is_same<value_t, value2_t>::value,
0095 "Incompatible iterators\n");
0096
0097
0098
0099
0100 assert(size_t(last - mid) <= rng_aux.size());
0101
0102 if (mid == last) return;
0103
0104 if (first == mid) return;
0105
0106
0107
0108
0109
0110
0111 std::vector<Iter1_t> viter;
0112 Iter2_t beta = rng_aux.first, data = rng_aux.first;
0113
0114 for (Iter1_t alpha = mid; alpha != last; ++alpha)
0115 *(beta++) = std::move(*alpha);
0116
0117 size_t ndata = last - mid;
0118
0119 Iter1_t linf = first, lsup = mid;
0120 for (uint32_t i = 0; i < ndata; ++i)
0121 {
0122 Iter1_t it1 = std::upper_bound(linf, lsup, *(data + i), comp);
0123 viter.push_back(it1);
0124 linf = it1;
0125 };
0126
0127
0128 viter.push_back(mid);
0129 for (uint32_t i = viter.size() - 1; i != 0; --i)
0130 {
0131 Iter1_t src = viter[i], limit = viter[i - 1];
0132 Iter1_t dest = src + (i);
0133 while (src != limit) *(--dest) = std::move(*(--src));
0134 *(viter[i - 1] + (i - 1)) = std::move(*(data + (i - 1)));
0135 };
0136 }
0137 ;
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154 template<class Iter1_t, class Iter2_t, class Compare>
0155 static bool check_stable_sort(const range<Iter1_t> &rng_data,
0156 const range<Iter2_t> &rng_aux, Compare comp)
0157 {
0158
0159
0160
0161 typedef value_iter<Iter1_t> value_t;
0162 typedef value_iter<Iter2_t> value2_t;
0163 static_assert (std::is_same<value_t, value2_t>::value,
0164 "Incompatible iterators\n");
0165
0166
0167
0168
0169
0170
0171
0172 const size_t ndata = rng_data.size();
0173 if (ndata < 32)
0174 {
0175 insert_sort(rng_data.first, rng_data.last, comp);
0176 return true;
0177 };
0178 const size_t min_insert_partial_sort =
0179 ((ndata >> 3) < 33) ? 32 : (ndata >> 3);
0180 if (ndata < 2) return true;
0181
0182
0183 bool sw = true;
0184 Iter1_t it2 = rng_data.first + 1;
0185 for (Iter1_t it1 = rng_data.first;
0186 it2 != rng_data.last and (sw = not comp(*it2, *it1)); it1 =
0187 it2++)
0188 ;
0189 if (sw) return true;
0190
0191
0192 if (size_t(rng_data.last - it2) < min_insert_partial_sort)
0193 {
0194 sort_range_sort(range<Iter1_t>(it2, rng_data.last), rng_aux, comp);
0195 insert_partial_sort(rng_data.first, it2, rng_data.last, comp, rng_aux);
0196 return true;
0197 };
0198
0199
0200 if ((it2 != (rng_data.first + 1))) return false;
0201 sw = true;
0202 for (Iter1_t it1 = rng_data.first;
0203 it2 != rng_data.last and (sw = comp(*it2, *it1)); it1 =
0204 it2++)
0205 ;
0206 if (size_t(rng_data.last - it2) >= min_insert_partial_sort) return false;
0207
0208
0209 size_t nreverse = it2 - rng_data.first;
0210 Iter1_t alpha(rng_data.first), beta(it2 - 1), mid(
0211 rng_data.first + (nreverse >> 1));
0212 while (alpha != mid) {
0213 using std::swap;
0214 swap(*(alpha++), *(beta--));
0215 }
0216
0217
0218 if (it2 != rng_data.last)
0219 {
0220 sort_range_sort(range<Iter1_t>(it2, rng_data.last), rng_aux, comp);
0221 insert_partial_sort(rng_data.first, it2, rng_data.last, comp, rng_aux);
0222 };
0223 return true;
0224 }
0225 ;
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242 template<class Iter1_t, class Iter2_t, class Compare>
0243 static void range_sort(const range<Iter1_t> &range1,
0244 const range<Iter2_t> &range2, Compare comp,
0245 uint32_t level)
0246 {
0247
0248
0249
0250 typedef value_iter<Iter1_t> value_t;
0251 typedef value_iter<Iter2_t> value2_t;
0252 static_assert (std::is_same<value_t, value2_t>::value,
0253 "Incompatible iterators\n");
0254
0255
0256
0257
0258 typedef range<Iter1_t> range_it1;
0259 typedef range<Iter2_t> range_it2;
0260 assert(range1.size() == range2.size() and level != 0);
0261
0262
0263 if (range1.size() > 1024)
0264 {
0265 if ((level & 1) == 0)
0266 {
0267 if (check_stable_sort(range2, range1, comp)) return;
0268 }
0269 else
0270 {
0271 if (check_stable_sort(range1, range2, comp))
0272 {
0273 move_forward(range2, range1);
0274 return;
0275 };
0276 };
0277 };
0278
0279
0280 size_t nelem1 = (range1.size() + 1) >> 1;
0281 range_it1 range_input1(range1.first, range1.first + nelem1),
0282 range_input2(range1.first + nelem1, range1.last);
0283
0284 if (level < 2)
0285 {
0286 insert_sort(range_input1.first, range_input1.last, comp);
0287 insert_sort(range_input2.first, range_input2.last, comp);
0288 }
0289 else
0290 {
0291 range_sort (range_it2(range2.first, range2.first + nelem1),
0292 range_input1, comp, level - 1);
0293
0294 range_sort (range_it2(range2.first + nelem1, range2.last),
0295 range_input2, comp, level - 1);
0296 };
0297
0298 merge(range2, range_input1, range_input2, comp);
0299 }
0300 ;
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310 template<class Iter1_t, class Iter2_t, class Compare>
0311 static void sort_range_sort(const range<Iter1_t> &rng_data,
0312 const range<Iter2_t> &rng_aux, Compare comp)
0313 {
0314
0315
0316
0317 typedef value_iter<Iter1_t> value_t;
0318 typedef value_iter<Iter2_t> value2_t;
0319 static_assert (std::is_same<value_t, value2_t>::value,
0320 "Incompatible iterators\n");
0321
0322
0323
0324
0325
0326 static const uint32_t sort_min = 32;
0327 if (rng_data.size() <= sort_min)
0328 {
0329 insert_sort(rng_data.first, rng_data.last, comp);
0330 return;
0331 };
0332
0333 #ifdef __BS_DEBUG
0334 assert (rng_aux.size () >= rng_data.size ());
0335 #endif
0336
0337 range<Iter2_t> rng_buffer(rng_aux.first, rng_aux.first + rng_data.size());
0338 uint32_t nlevel =
0339 nbits64(((rng_data.size() + sort_min - 1) / sort_min) - 1);
0340
0341
0342 if ((nlevel & 1) == 0)
0343 {
0344 range_sort(rng_buffer, rng_data, comp, nlevel);
0345 }
0346 else
0347 {
0348 range_sort(rng_data, rng_buffer, comp, nlevel);
0349 move_forward(rng_data, rng_buffer);
0350 };
0351 }
0352 ;
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366 template<class Iter_t, typename Compare = compare_iter<Iter_t>>
0367 class spinsort
0368 {
0369
0370
0371
0372 typedef value_iter<Iter_t> value_t;
0373 typedef range<Iter_t> range_it;
0374 typedef range<value_t *> range_buf;
0375
0376
0377 static const uint32_t Sort_min = 36;
0378
0379
0380
0381
0382
0383 value_t *ptr;
0384
0385
0386 size_t nptr;
0387
0388
0389
0390
0391
0392 bool construct = false, owner = false;
0393
0394
0395
0396
0397 spinsort (Iter_t first, Iter_t last, Compare comp, value_t *paux,
0398 size_t naux);
0399
0400 public:
0401
0402
0403
0404 spinsort(Iter_t first, Iter_t last, Compare comp = Compare())
0405 : spinsort(first, last, comp, nullptr, 0) { };
0406
0407 spinsort(Iter_t first, Iter_t last, Compare comp, range_buf range_aux)
0408 : spinsort(first, last, comp, range_aux.first, range_aux.size()) { };
0409
0410
0411
0412
0413
0414
0415
0416 ~spinsort(void)
0417 {
0418 if (construct)
0419 {
0420 destroy(range<value_t *>(ptr, ptr + nptr));
0421 construct = false;
0422 };
0423 if (owner and ptr != nullptr) std::free (ptr);
0424 };
0425 };
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442 template <class Iter_t, typename Compare>
0443 spinsort <Iter_t, Compare>
0444 ::spinsort (Iter_t first, Iter_t last, Compare comp, value_t *paux, size_t naux)
0445 : ptr(paux), nptr(naux), construct(false), owner(false)
0446 {
0447 range<Iter_t> range_input(first, last);
0448 assert(range_input.valid());
0449
0450 size_t nelem = range_input.size();
0451 owner = construct = false;
0452
0453 nptr = (nelem + 1) >> 1;
0454 size_t nelem_1 = nptr;
0455 size_t nelem_2 = nelem - nelem_1;
0456
0457 if (nelem <= (Sort_min << 1))
0458 {
0459 insert_sort(range_input.first, range_input.last, comp);
0460 return;
0461 };
0462
0463
0464 bool sw = true;
0465 for (Iter_t it1 = first, it2 = first + 1; it2 != last
0466 and (sw = not comp(*it2, *it1)); it1 = it2++) ;
0467 if (sw) return;
0468
0469
0470 sw = true;
0471 for (Iter_t it1 = first, it2 = first + 1;
0472 it2 != last and (sw = comp(*it2, *it1)); it1 = it2++);
0473 if (sw)
0474 {
0475 using std::swap;
0476 size_t nelem2 = nelem >> 1;
0477 Iter_t it1 = first, it2 = last - 1;
0478 for (size_t i = 0; i < nelem2; ++i)
0479 swap(*(it1++), *(it2--));
0480 return;
0481 };
0482
0483 if (ptr == nullptr)
0484 {
0485 ptr = reinterpret_cast <value_t*>
0486 (std::malloc (nptr * sizeof(value_t)));
0487
0488 if (ptr == nullptr) throw std::bad_alloc();
0489 owner = true;
0490 };
0491 range_buf range_aux(ptr, (ptr + nptr));
0492
0493
0494
0495
0496 uint32_t nlevel = nbits64(((nelem + Sort_min - 1) / Sort_min) - 1) - 1;
0497 assert(nlevel != 0);
0498
0499 if ((nlevel & 1) == 1)
0500 {
0501
0502
0503
0504
0505
0506 range_it range_1(first, first + nelem_2), range_2(first + nelem_2,
0507 last);
0508 range_aux = move_construct(range_aux, range_2);
0509 construct = true;
0510
0511 range_sort(range_aux, range_2, comp, nlevel);
0512 range_buf rng_bx(range_aux.first, range_aux.first + nelem_2);
0513
0514 range_sort(range_1, rng_bx, comp, nlevel);
0515 merge_half(range_input, rng_bx, range_2, comp);
0516 }
0517 else
0518 {
0519
0520
0521
0522
0523
0524 range_it range_1(first, first + nelem_1), range_2(first + nelem_1,
0525 last);
0526 range_aux = move_construct(range_aux, range_1);
0527 construct = true;
0528
0529 range_sort(range_1, range_aux, comp, nlevel);
0530
0531 range_1.last = range_1.first + range_2.size();
0532 range_sort(range_1, range_2, comp, nlevel);
0533 merge_half(range_input, range_aux, range_2, comp);
0534 };
0535 };
0536
0537
0538 };
0539
0540
0541 namespace bsc = boost::sort::common;
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551 template <class Iter_t, class Compare = compare_iter<Iter_t>>
0552 inline void spinsort (Iter_t first, Iter_t last, Compare comp = Compare())
0553 {
0554 spin_detail::spinsort <Iter_t, Compare> (first, last, comp);
0555 };
0556
0557 template <class Iter_t, class Compare = compare_iter<Iter_t>>
0558 inline void indirect_spinsort (Iter_t first, Iter_t last,
0559 Compare comp = Compare())
0560 {
0561 typedef typename std::vector<Iter_t>::iterator itx_iter;
0562 typedef common::less_ptr_no_null <Iter_t, Compare> itx_comp;
0563 common::indirect_sort (spinsort<itx_iter, itx_comp>, first, last, comp);
0564 };
0565
0566
0567 };
0568 };
0569
0570
0571 #endif