File indexing completed on 2025-01-18 09:40:51
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #ifndef BOOST_MOVE_ADAPTIVE_SORT_MERGE_HPP
0043 #define BOOST_MOVE_ADAPTIVE_SORT_MERGE_HPP
0044
0045 #include <boost/move/detail/config_begin.hpp>
0046
0047 #include <boost/move/detail/reverse_iterator.hpp>
0048 #include <boost/move/algo/move.hpp>
0049 #include <boost/move/algo/detail/merge.hpp>
0050 #include <boost/move/adl_move_swap.hpp>
0051 #include <boost/move/algo/detail/insertion_sort.hpp>
0052 #include <boost/move/algo/detail/merge_sort.hpp>
0053 #include <boost/move/algo/detail/heap_sort.hpp>
0054 #include <boost/move/algo/detail/merge.hpp>
0055 #include <boost/move/algo/detail/is_sorted.hpp>
0056 #include <cassert>
0057 #include <boost/cstdint.hpp>
0058 #include <limits.h>
0059
0060 #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
0061 #pragma GCC diagnostic push
0062 #pragma GCC diagnostic ignored "-Wsign-conversion"
0063 #endif
0064
0065 #ifndef BOOST_MOVE_ADAPTIVE_SORT_STATS_LEVEL
0066 #define BOOST_MOVE_ADAPTIVE_SORT_STATS_LEVEL 1
0067 #endif
0068
0069 #ifdef BOOST_MOVE_ADAPTIVE_SORT_STATS
0070 #if BOOST_MOVE_ADAPTIVE_SORT_STATS_LEVEL == 2
0071 #define BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(STR, L) \
0072 print_stats(STR, L)\
0073
0074
0075 #define BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(STR, L) \
0076 print_stats(STR, L)\
0077
0078 #else
0079 #define BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(STR, L) \
0080 print_stats(STR, L)\
0081
0082
0083 #define BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(STR, L)
0084 #endif
0085 #else
0086 #define BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(STR, L)
0087 #define BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(STR, L)
0088 #endif
0089
0090 #ifdef BOOST_MOVE_ADAPTIVE_SORT_INVARIANTS
0091 #define BOOST_MOVE_ADAPTIVE_SORT_INVARIANT assert
0092 #else
0093 #define BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(L)
0094 #endif
0095
0096 namespace boost {
0097 namespace movelib {
0098
0099 #if defined(BOOST_MOVE_ADAPTIVE_SORT_INVARIANTS)
0100
0101 bool is_sorted(::order_perf_type *first, ::order_perf_type *last, ::order_type_less)
0102 {
0103 if (first != last) {
0104 const order_perf_type *next = first, *cur(first);
0105 while (++next != last) {
0106 if (!(cur->key < next->key || (cur->key == next->key && cur->val < next->val)))
0107 return false;
0108 cur = next;
0109 }
0110 }
0111 return true;
0112 }
0113
0114 #endif
0115
0116 namespace detail_adaptive {
0117
0118 static const std::size_t AdaptiveSortInsertionSortThreshold = 16;
0119
0120 BOOST_MOVE_STATIC_ASSERT((AdaptiveSortInsertionSortThreshold&(AdaptiveSortInsertionSortThreshold-1)) == 0);
0121
0122 #if defined BOOST_HAS_INTPTR_T
0123 typedef ::boost::uintptr_t uintptr_t;
0124 #else
0125 typedef std::size_t uintptr_t;
0126 #endif
0127
0128 template<class T>
0129 const T &min_value(const T &a, const T &b)
0130 {
0131 return a < b ? a : b;
0132 }
0133
0134 template<class T>
0135 const T &max_value(const T &a, const T &b)
0136 {
0137 return a > b ? a : b;
0138 }
0139
0140 template<class ForwardIt, class Pred, class V>
0141 typename iter_size<ForwardIt>::type
0142 count_if_with(ForwardIt first, ForwardIt last, Pred pred, const V &v)
0143 {
0144 typedef typename iter_size<ForwardIt>::type size_type;
0145 size_type count = 0;
0146 while(first != last) {
0147 count = size_type(count + static_cast<size_type>(0 != pred(*first, v)));
0148 ++first;
0149 }
0150 return count;
0151 }
0152
0153
0154 template<class RandIt, class Compare>
0155 RandIt skip_until_merge
0156 ( RandIt first1, RandIt const last1
0157 , const typename iterator_traits<RandIt>::value_type &next_key, Compare comp)
0158 {
0159 while(first1 != last1 && !comp(next_key, *first1)){
0160 ++first1;
0161 }
0162 return first1;
0163 }
0164
0165
0166 template<class RandItKeys, class RandIt>
0167 void swap_and_update_key
0168 ( RandItKeys const key_next
0169 , RandItKeys const key_range2
0170 , RandItKeys &key_mid
0171 , RandIt const begin
0172 , RandIt const end
0173 , RandIt const with)
0174 {
0175 if(begin != with){
0176 ::boost::adl_move_swap_ranges(begin, end, with);
0177 if(key_next != key_range2)
0178 ::boost::adl_move_swap(*key_next, *key_range2);
0179 if(key_next == key_mid){
0180 key_mid = key_range2;
0181 }
0182 else if(key_mid == key_range2){
0183 key_mid = key_next;
0184 }
0185 }
0186 }
0187
0188 template<class RandItKeys>
0189 void update_key
0190 (RandItKeys const key_next
0191 , RandItKeys const key_range2
0192 , RandItKeys &key_mid)
0193 {
0194 if (key_next != key_range2) {
0195 ::boost::adl_move_swap(*key_next, *key_range2);
0196 if (key_next == key_mid) {
0197 key_mid = key_range2;
0198 }
0199 else if (key_mid == key_range2) {
0200 key_mid = key_next;
0201 }
0202 }
0203 }
0204
0205 template<class RandItKeys, class RandIt, class RandIt2, class Op>
0206 RandIt2 buffer_and_update_key
0207 (RandItKeys const key_next
0208 , RandItKeys const key_range2
0209 , RandItKeys &key_mid
0210 , RandIt begin
0211 , RandIt end
0212 , RandIt with
0213 , RandIt2 buffer
0214 , Op op)
0215 {
0216 if (begin != with) {
0217 while(begin != end) {
0218 op(three_way_t(), begin++, with++, buffer++);
0219 }
0220 if (key_next != key_range2)
0221 ::boost::adl_move_swap(*key_next, *key_range2);
0222 if (key_next == key_mid) {
0223 key_mid = key_range2;
0224 }
0225 else if (key_mid == key_range2) {
0226 key_mid = key_next;
0227 }
0228 }
0229 return buffer;
0230 }
0231
0232
0233
0234
0235
0236
0237
0238
0239 template<class RandIt, class Compare>
0240 RandIt partial_merge_bufferless_impl
0241 (RandIt first1, RandIt last1, RandIt const last2, bool *const pis_range1_A, Compare comp)
0242 {
0243 if(last1 == last2){
0244 return first1;
0245 }
0246 bool const is_range1_A = *pis_range1_A;
0247 if(first1 != last1 && comp(*last1, last1[-1])){
0248 do{
0249 RandIt const old_last1 = last1;
0250 last1 = boost::movelib::lower_bound(last1, last2, *first1, comp);
0251 first1 = rotate_gcd(first1, old_last1, last1);
0252 if(last1 == last2){
0253 return first1;
0254 }
0255 do{
0256 ++first1;
0257 } while(last1 != first1 && !comp(*last1, *first1) );
0258 } while(first1 != last1);
0259 }
0260 *pis_range1_A = !is_range1_A;
0261 return last1;
0262 }
0263
0264
0265 template<class RandIt, class Compare>
0266 RandIt partial_merge_bufferless
0267 (RandIt first1, RandIt last1, RandIt const last2, bool *const pis_range1_A, Compare comp)
0268 {
0269 return *pis_range1_A ? partial_merge_bufferless_impl(first1, last1, last2, pis_range1_A, comp)
0270 : partial_merge_bufferless_impl(first1, last1, last2, pis_range1_A, antistable<Compare>(comp));
0271 }
0272
0273 template<class SizeType>
0274 static SizeType needed_keys_count(SizeType n_block_a, SizeType n_block_b)
0275 {
0276 return SizeType(n_block_a + n_block_b);
0277 }
0278
0279 template<class RandItKeys, class KeyCompare, class RandIt, class Compare>
0280 typename iter_size<RandIt>::type
0281 find_next_block
0282 ( RandItKeys const key_first
0283 , KeyCompare key_comp
0284 , RandIt const first
0285 , typename iter_size<RandIt>::type const l_block
0286 , typename iter_size<RandIt>::type const ix_first_block
0287 , typename iter_size<RandIt>::type const ix_last_block
0288 , Compare comp)
0289 {
0290 typedef typename iter_size<RandIt>::type size_type;
0291 typedef typename iterator_traits<RandIt>::value_type value_type;
0292 typedef typename iterator_traits<RandItKeys>::value_type key_type;
0293 assert(ix_first_block <= ix_last_block);
0294 size_type ix_min_block = 0u;
0295 for (size_type szt_i = ix_first_block; szt_i < ix_last_block; ++szt_i) {
0296 const value_type &min_val = first[size_type(ix_min_block*l_block)];
0297 const value_type &cur_val = first[size_type(szt_i*l_block)];
0298 const key_type &min_key = key_first[ix_min_block];
0299 const key_type &cur_key = key_first[szt_i];
0300
0301 bool const less_than_minimum = comp(cur_val, min_val) ||
0302 (!comp(min_val, cur_val) && key_comp(cur_key, min_key));
0303
0304 if (less_than_minimum) {
0305 ix_min_block = szt_i;
0306 }
0307 }
0308 return ix_min_block;
0309 }
0310
0311 template<class RandItKeys, class KeyCompare, class RandIt, class Compare>
0312 void merge_blocks_bufferless
0313 ( RandItKeys const key_first
0314 , KeyCompare key_comp
0315 , RandIt const first
0316 , typename iter_size<RandIt>::type const l_block
0317 , typename iter_size<RandIt>::type const l_irreg1
0318 , typename iter_size<RandIt>::type const n_block_a
0319 , typename iter_size<RandIt>::type const n_block_b
0320 , typename iter_size<RandIt>::type const l_irreg2
0321 , Compare comp)
0322 {
0323 typedef typename iter_size<RandIt>::type size_type;
0324 size_type const key_count = needed_keys_count(n_block_a, n_block_b);
0325 ::boost::movelib::ignore(key_count);
0326
0327 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted_and_unique(key_first, key_first + key_count, key_comp));
0328 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(!n_block_b || n_block_a == count_if_with(key_first, key_first + key_count, key_comp, key_first[n_block_a]));
0329
0330 size_type n_bef_irreg2 = 0;
0331 bool l_irreg_pos_count = true;
0332 RandItKeys key_mid(key_first + n_block_a);
0333 RandIt const first_irr2 = first + size_type(l_irreg1 + (n_block_a+n_block_b)*l_block);
0334 RandIt const last_irr2 = first_irr2 + l_irreg2;
0335
0336 {
0337 size_type n_block_left = size_type(n_block_b + n_block_a);
0338 RandItKeys key_range2(key_first);
0339
0340 size_type min_check = n_block_a == n_block_left ? 0u : n_block_a;
0341 size_type max_check = min_value<size_type>(size_type(min_check+1), n_block_left);
0342 for ( RandIt f = first+l_irreg1; n_block_left; --n_block_left) {
0343 size_type const next_key_idx = find_next_block(key_range2, key_comp, f, l_block, min_check, max_check, comp);
0344 RandItKeys const key_next(key_range2 + next_key_idx);
0345 max_check = min_value<size_type>(max_value<size_type>(max_check, size_type(next_key_idx+2)), n_block_left);
0346
0347 RandIt const first_min = f + size_type(next_key_idx*l_block);
0348
0349
0350
0351 if (l_irreg_pos_count && l_irreg2 && comp(*first_irr2, *first_min)){
0352 l_irreg_pos_count = false;
0353 }
0354 n_bef_irreg2 = size_type(n_bef_irreg2+l_irreg_pos_count);
0355
0356 swap_and_update_key(key_next, key_range2, key_mid, f, f + l_block, first_min);
0357 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(f, f+l_block, comp));
0358 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first_min, first_min + l_block, comp));
0359 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT((f == (first+l_irreg1)) || !comp(*f, *(f-l_block)));
0360
0361 ++key_range2;
0362 f += l_block;
0363 min_check = size_type(min_check - (min_check != 0));
0364 max_check = size_type(max_check - (max_check != 0));
0365 }
0366 }
0367 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first+l_irreg1+n_bef_irreg2*l_block, first_irr2, comp));
0368
0369 RandIt first1 = first;
0370 RandIt last1 = first+l_irreg1;
0371 RandItKeys const key_end (key_first+n_bef_irreg2);
0372 bool is_range1_A = true;
0373
0374 for(RandItKeys key_next = key_first; key_next != key_end; ++key_next){
0375 bool is_range2_A = key_mid == (key_first+key_count) || key_comp(*key_next, *key_mid);
0376 first1 = is_range1_A == is_range2_A
0377 ? last1 : partial_merge_bufferless(first1, last1, last1 + l_block, &is_range1_A, comp);
0378 last1 += l_block;
0379 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first, first1, comp));
0380 }
0381
0382 merge_bufferless(is_range1_A ? first1 : last1, first_irr2, last_irr2, comp);
0383 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first, last_irr2, comp));
0384 }
0385
0386
0387
0388
0389
0390
0391
0392 template<class RandIt, class Compare, class XBuf>
0393 typename iter_size<RandIt>::type
0394 collect_unique
0395 ( RandIt const first, RandIt const last
0396 , typename iter_size<RandIt>::type const max_collected, Compare comp
0397 , XBuf & xbuf)
0398 {
0399 typedef typename iter_size<RandIt>::type size_type;
0400 size_type h = 0;
0401
0402 if(max_collected){
0403 ++h;
0404 RandIt h0 = first;
0405 RandIt u = first; ++u;
0406 RandIt search_end = u;
0407
0408 if(xbuf.capacity() >= max_collected){
0409 typename XBuf::iterator const ph0 = xbuf.add(first);
0410 while(u != last && h < max_collected){
0411 typename XBuf::iterator const r = boost::movelib::lower_bound(ph0, xbuf.end(), *u, comp);
0412
0413 if(r == xbuf.end() || comp(*u, *r) ){
0414 RandIt const new_h0 = boost::move(search_end, u, h0);
0415 search_end = u;
0416 ++search_end;
0417 ++h;
0418 xbuf.insert(r, u);
0419 h0 = new_h0;
0420 }
0421 ++u;
0422 }
0423 boost::move_backward(first, h0, h0+h);
0424 boost::move(xbuf.data(), xbuf.end(), first);
0425 }
0426 else{
0427 while(u != last && h < max_collected){
0428 RandIt const r = boost::movelib::lower_bound(h0, search_end, *u, comp);
0429
0430 if(r == search_end || comp(*u, *r) ){
0431 RandIt const new_h0 = rotate_gcd(h0, search_end, u);
0432 search_end = u;
0433 ++search_end;
0434 ++h;
0435 rotate_gcd(r+(new_h0-h0), u, search_end);
0436 h0 = new_h0;
0437 }
0438 ++u;
0439 }
0440 rotate_gcd(first, h0, h0+h);
0441 }
0442 }
0443 return h;
0444 }
0445
0446 template<class Unsigned>
0447 Unsigned floor_sqrt(Unsigned n)
0448 {
0449 Unsigned rem = 0, root = 0;
0450 const unsigned bits = sizeof(Unsigned)*CHAR_BIT;
0451
0452 for (unsigned i = bits / 2; i > 0; i--) {
0453 root = Unsigned(root << 1u);
0454 rem = Unsigned(Unsigned(rem << 2u) | Unsigned(n >> (bits - 2u)));
0455 n = Unsigned(n << 2u);
0456 if (root < rem) {
0457 rem = Unsigned(rem - Unsigned(root | 1u));
0458 root = Unsigned(root + 2u);
0459 }
0460 }
0461 return Unsigned(root >> 1u);
0462 }
0463
0464 template<class Unsigned>
0465 Unsigned ceil_sqrt(Unsigned const n)
0466 {
0467 Unsigned r = floor_sqrt(n);
0468 return Unsigned(r + Unsigned((n%r) != 0));
0469 }
0470
0471 template<class Unsigned>
0472 Unsigned floor_merge_multiple(Unsigned const n, Unsigned &base, Unsigned &pow)
0473 {
0474 Unsigned s = n;
0475 Unsigned p = 0;
0476 while(s > AdaptiveSortInsertionSortThreshold){
0477 s /= 2;
0478 ++p;
0479 }
0480 base = s;
0481 pow = p;
0482 return Unsigned(s << p);
0483 }
0484
0485 template<class Unsigned>
0486 Unsigned ceil_merge_multiple(Unsigned const n, Unsigned &base, Unsigned &pow)
0487 {
0488 Unsigned fm = floor_merge_multiple(n, base, pow);
0489
0490 if(fm != n){
0491 if(base < AdaptiveSortInsertionSortThreshold){
0492 ++base;
0493 }
0494 else{
0495 base = AdaptiveSortInsertionSortThreshold/2 + 1;
0496 ++pow;
0497 }
0498 }
0499 return Unsigned(base << pow);
0500 }
0501
0502 template<class Unsigned>
0503 Unsigned ceil_sqrt_multiple(Unsigned const n, Unsigned *pbase = 0)
0504 {
0505 Unsigned const r = ceil_sqrt(n);
0506 Unsigned pow = 0;
0507 Unsigned base = 0;
0508 Unsigned const res = ceil_merge_multiple(r, base, pow);
0509 if(pbase) *pbase = base;
0510 return res;
0511 }
0512
0513 struct less
0514 {
0515 template<class T>
0516 bool operator()(const T &l, const T &r)
0517 { return l < r; }
0518 };
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528 #if defined ADAPTIVE_SORT_MERGE_SLOW_STABLE_SORT_IS_NLOGN
0529 template<class RandIt, class Compare>
0530 void slow_stable_sort
0531 ( RandIt const first, RandIt const last, Compare comp)
0532 {
0533 boost::movelib::inplace_stable_sort(first, last, comp);
0534 }
0535
0536 #else
0537
0538 template<class RandIt, class Compare>
0539 void slow_stable_sort
0540 ( RandIt const first, RandIt const last, Compare comp)
0541 {
0542 typedef typename iter_size<RandIt>::type size_type;
0543
0544 size_type L = size_type(last - first);
0545 {
0546 size_type m = 0;
0547 while((L - m) > size_type(AdaptiveSortInsertionSortThreshold)){
0548 insertion_sort(first+m, first+m+size_type(AdaptiveSortInsertionSortThreshold), comp);
0549 m = size_type(m + AdaptiveSortInsertionSortThreshold);
0550 }
0551 insertion_sort(first+m, last, comp);
0552 }
0553
0554 size_type h = AdaptiveSortInsertionSortThreshold;
0555 for(bool do_merge = L > h; do_merge; h = size_type(h*2)){
0556 do_merge = (L - h) > h;
0557 size_type p0 = 0;
0558 if(do_merge){
0559 size_type const h_2 = size_type(2*h);
0560 while((L-p0) > h_2){
0561 merge_bufferless(first+p0, first+p0+h, first+p0+h_2, comp);
0562 p0 = size_type(p0 + h_2);
0563 }
0564 }
0565 if((L-p0) > h){
0566 merge_bufferless(first+p0, first+p0+h, last, comp);
0567 }
0568 }
0569 }
0570
0571 #endif
0572
0573
0574 template<class Unsigned>
0575 Unsigned lblock_for_combine
0576 (Unsigned const l_block, Unsigned const n_keys, Unsigned const l_data, bool &use_buf)
0577 {
0578 assert(l_data > 1);
0579
0580
0581
0582
0583
0584
0585
0586 if(!l_block){
0587
0588
0589 assert(n_keys >= 4);
0590
0591
0592
0593 Unsigned const new_buf = n_keys/2;
0594 Unsigned const new_keys = Unsigned(n_keys-new_buf);
0595 use_buf = new_keys >= 4 && new_keys >= l_data/new_buf;
0596 if(use_buf){
0597 return new_buf;
0598 }
0599 else{
0600 return l_data/n_keys;
0601 }
0602 }
0603 else{
0604 use_buf = true;
0605 return l_block;
0606 }
0607 }
0608
0609 template<class RandIt, class Compare, class XBuf>
0610 void stable_sort( RandIt first, RandIt last, Compare comp, XBuf & xbuf)
0611 {
0612 typedef typename iter_size<RandIt>::type size_type;
0613 size_type const len = size_type(last - first);
0614 size_type const half_len = size_type(len/2u + (len&1u));
0615 if(std::size_t(xbuf.capacity() - xbuf.size()) >= half_len) {
0616 merge_sort(first, last, comp, xbuf.data()+xbuf.size());
0617 }
0618 else{
0619 slow_stable_sort(first, last, comp);
0620 }
0621 }
0622
0623 template<class RandIt, class Comp, class XBuf>
0624 void unstable_sort( RandIt first, RandIt last
0625 , Comp comp
0626 , XBuf & xbuf)
0627 {
0628 heap_sort(first, last, comp);
0629 ::boost::movelib::ignore(xbuf);
0630 }
0631
0632 template<class RandIt, class Compare, class XBuf>
0633 void stable_merge
0634 ( RandIt first, RandIt const middle, RandIt last
0635 , Compare comp
0636 , XBuf &xbuf)
0637 {
0638 assert(xbuf.empty());
0639 typedef typename iter_size<RandIt>::type size_type;
0640 size_type const len1 = size_type(middle-first);
0641 size_type const len2 = size_type(last-middle);
0642 size_type const l_min = min_value<size_type>(len1, len2);
0643 if(xbuf.capacity() >= l_min){
0644 buffered_merge(first, middle, last, comp, xbuf);
0645 xbuf.clear();
0646 }
0647 else{
0648
0649 merge_adaptive_ONlogN(first, middle, last, comp, xbuf.begin(), xbuf.capacity());
0650 }
0651 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first, last, boost::movelib::unantistable(comp)));
0652 }
0653
0654 template<class RandIt, class Comp, class XBuf>
0655 void initialize_keys( RandIt first, RandIt last
0656 , Comp comp
0657 , XBuf & xbuf)
0658 {
0659 unstable_sort(first, last, comp, xbuf);
0660 assert(boost::movelib::is_sorted_and_unique(first, last, comp));
0661 }
0662
0663 template<class RandIt, class U>
0664 void initialize_keys( RandIt first, RandIt last
0665 , less
0666 , U &)
0667 {
0668 typedef typename iterator_traits<RandIt>::value_type value_type;
0669 std::size_t count = std::size_t(last - first);
0670 for(std::size_t i = 0; i != count; ++i){
0671 *first = static_cast<value_type>(i);
0672 ++first;
0673 }
0674 }
0675
0676 template <class Unsigned>
0677 Unsigned calculate_total_combined(Unsigned const len, Unsigned const l_prev_merged, Unsigned *pl_irreg_combined = 0)
0678 {
0679 typedef Unsigned size_type;
0680
0681 size_type const l_combined = size_type(2*l_prev_merged);
0682 size_type l_irreg_combined = size_type(len%l_combined);
0683 size_type l_total_combined = len;
0684 if(l_irreg_combined <= l_prev_merged){
0685 l_total_combined = size_type(l_total_combined - l_irreg_combined);
0686 l_irreg_combined = 0;
0687 }
0688 if(pl_irreg_combined)
0689 *pl_irreg_combined = l_irreg_combined;
0690 return l_total_combined;
0691 }
0692
0693 template<class RandItKeys, class KeyCompare, class SizeType, class XBuf>
0694 void combine_params
0695 ( RandItKeys const keys
0696 , KeyCompare key_comp
0697 , SizeType l_combined
0698 , SizeType const l_prev_merged
0699 , SizeType const l_block
0700 , XBuf & xbuf
0701
0702 , SizeType &n_block_a
0703 , SizeType &n_block_b
0704 , SizeType &l_irreg1
0705 , SizeType &l_irreg2
0706
0707 , bool do_initialize_keys = true)
0708 {
0709 typedef SizeType size_type;
0710
0711
0712 l_irreg1 = size_type(l_prev_merged%l_block);
0713 l_irreg2 = size_type((l_combined-l_irreg1)%l_block);
0714 assert(((l_combined-l_irreg1-l_irreg2)%l_block) == 0);
0715 size_type const n_reg_block = size_type((l_combined-l_irreg1-l_irreg2)/l_block);
0716 n_block_a = l_prev_merged/l_block;
0717 n_block_b = size_type(n_reg_block - n_block_a);
0718 assert(n_reg_block>=n_block_a);
0719
0720
0721 if (do_initialize_keys) {
0722 initialize_keys(keys, keys + needed_keys_count(n_block_a, n_block_b), key_comp, xbuf);
0723 }
0724 }
0725
0726
0727
0728
0729
0730
0731
0732
0733 template<class InputIt1, class InputIt2, class OutputIt, class Compare, class Op>
0734 OutputIt op_partial_merge_impl
0735 (InputIt1 &r_first1, InputIt1 const last1, InputIt2 &r_first2, InputIt2 const last2, OutputIt d_first, Compare comp, Op op)
0736 {
0737 InputIt1 first1(r_first1);
0738 InputIt2 first2(r_first2);
0739 if(first2 != last2 && last1 != first1)
0740 while(1){
0741 if(comp(*first2, *first1)) {
0742 op(first2++, d_first++);
0743 if(first2 == last2){
0744 break;
0745 }
0746 }
0747 else{
0748 op(first1++, d_first++);
0749 if(first1 == last1){
0750 break;
0751 }
0752 }
0753 }
0754 r_first1 = first1;
0755 r_first2 = first2;
0756 return d_first;
0757 }
0758
0759 template<class InputIt1, class InputIt2, class OutputIt, class Compare, class Op>
0760 OutputIt op_partial_merge
0761 (InputIt1 &r_first1, InputIt1 const last1, InputIt2 &r_first2, InputIt2 const last2, OutputIt d_first, Compare comp, Op op, bool is_stable)
0762 {
0763 return is_stable ? op_partial_merge_impl(r_first1, last1, r_first2, last2, d_first, comp, op)
0764 : op_partial_merge_impl(r_first1, last1, r_first2, last2, d_first, antistable<Compare>(comp), op);
0765 }
0766
0767
0768
0769
0770
0771
0772
0773
0774
0775
0776 template<class InputIt1, class InputIt2, class OutputIt, class Compare, class Op>
0777 OutputIt op_partial_merge_and_swap_impl
0778 (InputIt1 &r_first1, InputIt1 const last1, InputIt2 &r_first2, InputIt2 const last2, InputIt2 &r_first_min, OutputIt d_first, Compare comp, Op op)
0779 {
0780 InputIt1 first1(r_first1);
0781 InputIt2 first2(r_first2);
0782
0783 if(first2 != last2 && last1 != first1) {
0784 InputIt2 first_min(r_first_min);
0785 bool non_empty_ranges = true;
0786 do{
0787 if(comp(*first_min, *first1)) {
0788 op(three_way_t(), first2++, first_min++, d_first++);
0789 non_empty_ranges = first2 != last2;
0790 }
0791 else{
0792 op(first1++, d_first++);
0793 non_empty_ranges = first1 != last1;
0794 }
0795 } while(non_empty_ranges);
0796 r_first_min = first_min;
0797 r_first1 = first1;
0798 r_first2 = first2;
0799 }
0800 return d_first;
0801 }
0802
0803 template<class RandIt, class InputIt2, class OutputIt, class Compare, class Op>
0804 OutputIt op_partial_merge_and_swap
0805 (RandIt &r_first1, RandIt const last1, InputIt2 &r_first2, InputIt2 const last2, InputIt2 &r_first_min, OutputIt d_first, Compare comp, Op op, bool is_stable)
0806 {
0807 return is_stable ? op_partial_merge_and_swap_impl(r_first1, last1, r_first2, last2, r_first_min, d_first, comp, op)
0808 : op_partial_merge_and_swap_impl(r_first1, last1, r_first2, last2, r_first_min, d_first, antistable<Compare>(comp), op);
0809 }
0810
0811 template<class RandIt1, class RandIt2, class RandItB, class Compare, class Op>
0812 RandItB op_buffered_partial_merge_and_swap_to_range1_and_buffer
0813 ( RandIt1 first1, RandIt1 const last1
0814 , RandIt2 &rfirst2, RandIt2 const last2, RandIt2 &rfirst_min
0815 , RandItB &rfirstb, Compare comp, Op op )
0816 {
0817 RandItB firstb = rfirstb;
0818 RandItB lastb = firstb;
0819 RandIt2 first2 = rfirst2;
0820
0821
0822
0823
0824 if(first1 != last1 && first2 != last2){
0825 RandIt2 first_min = rfirst_min;
0826 op(four_way_t(), first2++, first_min++, first1++, lastb++);
0827
0828 while(first1 != last1){
0829 if(first2 == last2){
0830 lastb = op(forward_t(), first1, last1, firstb);
0831 break;
0832 }
0833
0834 if(comp(*first_min, *firstb)){
0835 op( four_way_t(), first2++, first_min++, first1++, lastb++);
0836 }
0837 else{
0838 op(three_way_t(), firstb++, first1++, lastb++);
0839 }
0840 }
0841 rfirst2 = first2;
0842 rfirstb = firstb;
0843 rfirst_min = first_min;
0844 }
0845
0846 return lastb;
0847 }
0848
0849 template<class RandIt1, class RandIt2, class RandItB, class Compare, class Op>
0850 RandItB op_buffered_partial_merge_to_range1_and_buffer
0851 ( RandIt1 first1, RandIt1 const last1
0852 , RandIt2 &rfirst2, RandIt2 const last2
0853 , RandItB &rfirstb, Compare comp, Op op )
0854 {
0855 RandItB firstb = rfirstb;
0856 RandItB lastb = firstb;
0857 RandIt2 first2 = rfirst2;
0858
0859
0860
0861
0862 if(first1 != last1 && first2 != last2){
0863 op(three_way_t(), first2++, first1++, lastb++);
0864
0865 while(true){
0866 if(first1 == last1){
0867 break;
0868 }
0869 if(first2 == last2){
0870 lastb = op(forward_t(), first1, last1, firstb);
0871 break;
0872 }
0873 if (comp(*first2, *firstb)) {
0874 op(three_way_t(), first2++, first1++, lastb++);
0875 }
0876 else {
0877 op(three_way_t(), firstb++, first1++, lastb++);
0878 }
0879 }
0880 rfirst2 = first2;
0881 rfirstb = firstb;
0882 }
0883
0884 return lastb;
0885 }
0886
0887 template<class RandIt, class RandItBuf, class Compare, class Op>
0888 RandIt op_partial_merge_and_save_impl
0889 ( RandIt first1, RandIt const last1, RandIt &rfirst2, RandIt last2, RandIt first_min
0890 , RandItBuf &buf_first1_in_out, RandItBuf &buf_last1_in_out
0891 , Compare comp, Op op
0892 )
0893 {
0894 RandItBuf buf_first1 = buf_first1_in_out;
0895 RandItBuf buf_last1 = buf_last1_in_out;
0896 RandIt first2(rfirst2);
0897
0898 bool const do_swap = first2 != first_min;
0899 if(buf_first1 == buf_last1){
0900
0901 RandIt new_first1 = skip_until_merge(first1, last1, *first_min, comp);
0902 buf_first1 += (new_first1-first1);
0903 first1 = new_first1;
0904 buf_last1 = do_swap ? op_buffered_partial_merge_and_swap_to_range1_and_buffer(first1, last1, first2, last2, first_min, buf_first1, comp, op)
0905 : op_buffered_partial_merge_to_range1_and_buffer (first1, last1, first2, last2, buf_first1, comp, op);
0906 first1 = last1;
0907 }
0908 else{
0909 assert((last1-first1) == (buf_last1 - buf_first1));
0910 }
0911
0912
0913 first1 = do_swap ? op_partial_merge_and_swap_impl(buf_first1, buf_last1, first2, last2, first_min, first1, comp, op)
0914 : op_partial_merge_impl (buf_first1, buf_last1, first2, last2, first1, comp, op);
0915 buf_first1_in_out = buf_first1;
0916 buf_last1_in_out = buf_last1;
0917 rfirst2 = first2;
0918 return first1;
0919 }
0920
0921 template<class RandIt, class RandItBuf, class Compare, class Op>
0922 RandIt op_partial_merge_and_save
0923 ( RandIt first1, RandIt const last1, RandIt &rfirst2, RandIt last2, RandIt first_min
0924 , RandItBuf &buf_first1_in_out
0925 , RandItBuf &buf_last1_in_out
0926 , Compare comp
0927 , Op op
0928 , bool is_stable)
0929 {
0930 return is_stable
0931 ? op_partial_merge_and_save_impl
0932 (first1, last1, rfirst2, last2, first_min, buf_first1_in_out, buf_last1_in_out, comp, op)
0933 : op_partial_merge_and_save_impl
0934 (first1, last1, rfirst2, last2, first_min, buf_first1_in_out, buf_last1_in_out, antistable<Compare>(comp), op)
0935 ;
0936 }
0937
0938
0939
0940
0941
0942
0943
0944
0945
0946
0947
0948 template<class RandItKeys, class KeyCompare, class RandIt, class RandIt2, class OutputIt, class Compare, class Op>
0949 OutputIt op_merge_blocks_with_irreg
0950 ( RandItKeys key_first
0951 , RandItKeys key_mid
0952 , KeyCompare key_comp
0953 , RandIt first_reg
0954 , RandIt2 &first_irr
0955 , RandIt2 const last_irr
0956 , OutputIt dest
0957 , typename iter_size<RandIt>::type const l_block
0958 , typename iter_size<RandIt>::type n_block_left
0959 , typename iter_size<RandIt>::type min_check
0960 , typename iter_size<RandIt>::type max_check
0961 , Compare comp, bool const is_stable, Op op)
0962 {
0963 typedef typename iter_size<RandIt>::type size_type;
0964
0965 for(; n_block_left; --n_block_left){
0966 size_type next_key_idx = find_next_block(key_first, key_comp, first_reg, l_block, min_check, max_check, comp);
0967 max_check = min_value(max_value(max_check, size_type(next_key_idx+2u)), n_block_left);
0968 RandIt const last_reg = first_reg + l_block;
0969 RandIt first_min = first_reg + size_type(next_key_idx*l_block);
0970 RandIt const last_min = first_min + l_block;
0971 boost::movelib::ignore(last_min);
0972
0973 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first_reg, last_reg, comp));
0974 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(!next_key_idx || boost::movelib::is_sorted(first_min, last_min, comp));
0975 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT((!next_key_idx || !comp(*first_reg, *first_min )));
0976
0977 OutputIt orig_dest = dest;
0978 boost::movelib::ignore(orig_dest);
0979 dest = next_key_idx ? op_partial_merge_and_swap(first_irr, last_irr, first_reg, last_reg, first_min, dest, comp, op, is_stable)
0980 : op_partial_merge (first_irr, last_irr, first_reg, last_reg, dest, comp, op, is_stable);
0981 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(orig_dest, dest, comp));
0982
0983 if(first_reg == dest){
0984 dest = next_key_idx ? ::boost::adl_move_swap_ranges(first_min, last_min, first_reg)
0985 : last_reg;
0986 }
0987 else{
0988 dest = next_key_idx ? op(three_way_forward_t(), first_reg, last_reg, first_min, dest)
0989 : op(forward_t(), first_reg, last_reg, dest);
0990 }
0991
0992 RandItKeys const key_next(key_first + next_key_idx);
0993 swap_and_update_key(key_next, key_first, key_mid, last_reg, last_reg, first_min);
0994
0995 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(orig_dest, dest, comp));
0996 first_reg = last_reg;
0997 ++key_first;
0998 min_check = size_type(min_check - (min_check != 0));
0999 max_check = size_type(max_check - (max_check != 0));
1000 }
1001 return dest;
1002 }
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014 template<class RandItKeys, class KeyCompare, class RandIt, class Compare, class Op>
1015 void op_merge_blocks_left
1016 ( RandItKeys const key_first
1017 , KeyCompare key_comp
1018 , RandIt const first
1019 , typename iter_size<RandIt>::type const l_block
1020 , typename iter_size<RandIt>::type const l_irreg1
1021 , typename iter_size<RandIt>::type const n_block_a
1022 , typename iter_size<RandIt>::type const n_block_b
1023 , typename iter_size<RandIt>::type const l_irreg2
1024 , Compare comp, Op op)
1025 {
1026 typedef typename iter_size<RandIt>::type size_type;
1027
1028 size_type const key_count = needed_keys_count(n_block_a, n_block_b);
1029 boost::movelib::ignore(key_count);
1030
1031
1032 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted_and_unique(key_first, key_first + key_count, key_comp));
1033 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(!n_block_b || n_block_a == count_if_with(key_first, key_first + key_count, key_comp, key_first[n_block_a]));
1034
1035 size_type n_block_b_left = n_block_b;
1036 size_type n_block_a_left = n_block_a;
1037 size_type n_block_left = size_type(n_block_b + n_block_a);
1038 RandItKeys key_mid(key_first + n_block_a);
1039
1040 RandIt buffer = first - l_block;
1041 RandIt first1 = first;
1042 RandIt last1 = first1 + l_irreg1;
1043 RandIt first2 = last1;
1044 RandIt const irreg2 = first2 + size_type(n_block_left*l_block);
1045 bool is_range1_A = true;
1046
1047 RandItKeys key_range2(key_first);
1048
1049
1050
1051
1052 size_type min_check = n_block_a == n_block_left ? 0u : n_block_a;
1053 size_type max_check = min_value<size_type>(size_type(min_check+1u), n_block_left);
1054 for (; n_block_left; --n_block_left) {
1055 size_type const next_key_idx = find_next_block(key_range2, key_comp, first2, l_block, min_check, max_check, comp);
1056 max_check = min_value<size_type>(max_value<size_type>(max_check, size_type(next_key_idx+2u)), n_block_left);
1057 RandIt const first_min = first2 + size_type(next_key_idx*l_block);
1058 RandIt const last_min = first_min + l_block;
1059
1060 boost::movelib::ignore(last_min);
1061 RandIt const last2 = first2 + l_block;
1062
1063 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first1, last1, comp));
1064 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first2, last2, comp));
1065 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(!n_block_left || boost::movelib::is_sorted(first_min, last_min, comp));
1066
1067
1068
1069 if (!n_block_b_left &&
1070 ( (l_irreg2 && comp(*irreg2, *first_min)) || (!l_irreg2 && is_range1_A)) ){
1071 break;
1072 }
1073
1074 RandItKeys const key_next(key_range2 + next_key_idx);
1075 bool const is_range2_A = key_mid == (key_first+key_count) || key_comp(*key_next, *key_mid);
1076
1077 bool const is_buffer_middle = last1 == buffer;
1078 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT( ( is_buffer_middle && size_type(first2-buffer) == l_block && buffer == last1) ||
1079 (!is_buffer_middle && size_type(first1-buffer) == l_block && first2 == last1));
1080
1081 if(is_range1_A == is_range2_A){
1082 assert((first1 == last1) || !comp(*first_min, last1[typename iterator_traits<RandIt>::difference_type(-1)]));
1083 if(!is_buffer_middle){
1084 buffer = op(forward_t(), first1, last1, buffer);
1085 }
1086 swap_and_update_key(key_next, key_range2, key_mid, first2, last2, first_min);
1087 first1 = first2;
1088 last1 = last2;
1089 }
1090 else {
1091 RandIt unmerged;
1092 RandIt buf_beg;
1093 RandIt buf_end;
1094 if(is_buffer_middle){
1095 buf_end = buf_beg = first2 - (last1-first1);
1096 unmerged = op_partial_merge_and_save( first1, last1, first2, last2, first_min
1097 , buf_beg, buf_end, comp, op, is_range1_A);
1098 }
1099 else{
1100 buf_beg = first1;
1101 buf_end = last1;
1102 unmerged = op_partial_merge_and_save
1103 (buffer, buffer+(last1-first1), first2, last2, first_min, buf_beg, buf_end, comp, op, is_range1_A);
1104 }
1105
1106 boost::movelib::ignore(unmerged);
1107 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first-l_block, unmerged, comp));
1108
1109 swap_and_update_key( key_next, key_range2, key_mid, first2, last2
1110 , last_min - size_type(last2 - first2));
1111
1112 if(buf_beg != buf_end){
1113 first1 = buf_beg;
1114 last1 = buf_end;
1115 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(buf_end == (last2-l_block));
1116 buffer = last1;
1117 }
1118 else{
1119 first1 = first2;
1120 last1 = last2;
1121 buffer = first2 - l_block;
1122 is_range1_A = is_range2_A;
1123 }
1124 }
1125 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT( (is_range2_A && n_block_a_left) || (!is_range2_A && n_block_b_left));
1126 is_range2_A ? --n_block_a_left : --n_block_b_left;
1127 first2 = last2;
1128
1129 ++key_range2;
1130 min_check = size_type(min_check - (min_check != 0));
1131 max_check = size_type(max_check - (max_check != 0));
1132 }
1133
1134 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(!n_block_b || n_block_a == count_if_with(key_first, key_range2 + n_block_left, key_comp, *key_mid));
1135 assert(!n_block_b_left);
1136
1137
1138
1139
1140 bool const is_buffer_middle = last1 == buffer;
1141 RandIt first_irr2 = irreg2;
1142 RandIt const last_irr2 = first_irr2 + l_irreg2;
1143 if(l_irreg2 && is_range1_A){
1144 if(is_buffer_middle){
1145 first1 = skip_until_merge(first1, last1, *first_irr2, comp);
1146
1147
1148 RandIt const new_first1 = first2 - (last1 - first1);
1149 op(forward_t(), first1, last1, new_first1);
1150 first1 = new_first1;
1151 last1 = first2;
1152 buffer = first1 - l_block;
1153 }
1154 buffer = op_partial_merge_impl(first1, last1, first_irr2, last_irr2, buffer, comp, op);
1155 buffer = op(forward_t(), first1, last1, buffer);
1156 }
1157 else if(!is_buffer_middle){
1158 buffer = op(forward_t(), first1, last1, buffer);
1159 }
1160 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first-l_block, buffer, comp));
1161
1162
1163
1164
1165 buffer = op_merge_blocks_with_irreg
1166 ( key_range2, key_mid, key_comp, first2, first_irr2, last_irr2
1167 , buffer, l_block, n_block_left, min_check, max_check, comp, false, op);
1168 buffer = op(forward_t(), first_irr2, last_irr2, buffer);
1169 boost::movelib::ignore(buffer);
1170 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first-l_block, buffer, comp));
1171 }
1172
1173
1174
1175
1176
1177
1178
1179
1180 template<class RandItKeys, class KeyCompare, class RandIt, class Compare>
1181 void merge_blocks_left
1182 ( RandItKeys const key_first
1183 , KeyCompare key_comp
1184 , RandIt const first
1185 , typename iter_size<RandIt>::type const l_block
1186 , typename iter_size<RandIt>::type const l_irreg1
1187 , typename iter_size<RandIt>::type const n_block_a
1188 , typename iter_size<RandIt>::type const n_block_b
1189 , typename iter_size<RandIt>::type const l_irreg2
1190 , Compare comp
1191 , bool const xbuf_used)
1192 {
1193 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(!n_block_b || n_block_a == count_if_with(key_first, key_first + needed_keys_count(n_block_a, n_block_b), key_comp, key_first[n_block_a]));
1194 if(xbuf_used){
1195 op_merge_blocks_left
1196 (key_first, key_comp, first, l_block, l_irreg1, n_block_a, n_block_b, l_irreg2, comp, move_op());
1197 }
1198 else{
1199 op_merge_blocks_left
1200 (key_first, key_comp, first, l_block, l_irreg1, n_block_a, n_block_b, l_irreg2, comp, swap_op());
1201 }
1202 }
1203
1204
1205
1206
1207
1208
1209
1210
1211 template<class RandItKeys, class KeyCompare, class RandIt, class Compare>
1212 void merge_blocks_right
1213 ( RandItKeys const key_first
1214 , KeyCompare key_comp
1215 , RandIt const first
1216 , typename iter_size<RandIt>::type const l_block
1217 , typename iter_size<RandIt>::type const n_block_a
1218 , typename iter_size<RandIt>::type const n_block_b
1219 , typename iter_size<RandIt>::type const l_irreg2
1220 , Compare comp
1221 , bool const xbuf_used)
1222 {
1223 typedef typename iter_size<RandIt>::type size_type;
1224 merge_blocks_left
1225 ( (make_reverse_iterator)(key_first + needed_keys_count(n_block_a, n_block_b))
1226 , inverse<KeyCompare>(key_comp)
1227 , (make_reverse_iterator)(first + size_type((n_block_a+n_block_b)*l_block+l_irreg2))
1228 , l_block
1229 , l_irreg2
1230 , n_block_b
1231 , n_block_a
1232 , 0
1233 , inverse<Compare>(comp), xbuf_used);
1234 }
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245 template<class RandItKeys, class KeyCompare, class RandIt, class Compare, class Op, class RandItBuf>
1246 void op_merge_blocks_with_buf
1247 ( RandItKeys key_first
1248 , KeyCompare key_comp
1249 , RandIt const first
1250 , typename iter_size<RandIt>::type const l_block
1251 , typename iter_size<RandIt>::type const l_irreg1
1252 , typename iter_size<RandIt>::type const n_block_a
1253 , typename iter_size<RandIt>::type const n_block_b
1254 , typename iter_size<RandIt>::type const l_irreg2
1255 , Compare comp
1256 , Op op
1257 , RandItBuf const buf_first)
1258 {
1259 typedef typename iter_size<RandIt>::type size_type;
1260 size_type const key_count = needed_keys_count(n_block_a, n_block_b);
1261 boost::movelib::ignore(key_count);
1262
1263 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted_and_unique(key_first, key_first + key_count, key_comp));
1264 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(!n_block_b || n_block_a == count_if_with(key_first, key_first + key_count, key_comp, key_first[n_block_a]));
1265
1266 size_type n_block_b_left = n_block_b;
1267 size_type n_block_a_left = n_block_a;
1268 size_type n_block_left = size_type(n_block_b + n_block_a);
1269 RandItKeys key_mid(key_first + n_block_a);
1270
1271 RandItBuf buffer = buf_first;
1272 RandItBuf buffer_end = buffer;
1273 RandIt first1 = first;
1274 RandIt last1 = first1 + l_irreg1;
1275 RandIt first2 = last1;
1276 RandIt const first_irr2 = first2 + size_type(n_block_left*l_block);
1277 bool is_range1_A = true;
1278 const size_type len = size_type(l_block * n_block_a + l_block * n_block_b + l_irreg1 + l_irreg2);
1279 boost::movelib::ignore(len);
1280
1281 RandItKeys key_range2(key_first);
1282
1283
1284
1285
1286 size_type min_check = n_block_a == n_block_left ? 0u : n_block_a;
1287 size_type max_check = min_value(size_type(min_check+1), n_block_left);
1288 for (; n_block_left; --n_block_left) {
1289 size_type const next_key_idx = find_next_block(key_range2, key_comp, first2, l_block, min_check, max_check, comp);
1290 max_check = min_value(max_value(max_check, size_type(next_key_idx+2)), n_block_left);
1291 RandIt first_min = first2 + size_type(next_key_idx*l_block);
1292 RandIt const last_min = first_min + l_block;
1293 boost::movelib::ignore(last_min);
1294 RandIt const last2 = first2 + l_block;
1295
1296 bool const buffer_empty = buffer == buffer_end;
1297 boost::movelib::ignore(buffer_empty);
1298 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(buffer_empty ? boost::movelib::is_sorted(first1, last1, comp) : boost::movelib::is_sorted(buffer, buffer_end, comp));
1299 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first2, last2, comp));
1300 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(!n_block_left || boost::movelib::is_sorted(first_min, last_min, comp));
1301
1302
1303
1304 if (!n_block_b_left &&
1305 ( (l_irreg2 && comp(*first_irr2, *first_min)) || (!l_irreg2 && is_range1_A)) ){
1306 break;
1307 }
1308
1309 RandItKeys const key_next(key_range2 + next_key_idx);
1310 bool const is_range2_A = key_mid == (key_first+key_count) || key_comp(*key_next, *key_mid);
1311
1312 if(is_range1_A == is_range2_A){
1313 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT((first1 == last1) || (buffer_empty ? !comp(*first_min, last1[-1]) : !comp(*first_min, buffer_end[-1])));
1314
1315 RandIt res = op(forward_t(), buffer, buffer_end, first1);
1316 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_fwd: ", len);
1317 buffer = buffer_end = buf_first;
1318 assert(buffer_empty || res == last1);
1319 boost::movelib::ignore(res);
1320
1321 buffer_end = buffer_and_update_key(key_next, key_range2, key_mid, first2, last2, first_min, buffer = buf_first, op);
1322 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_swp: ", len);
1323 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first2, last2, comp));
1324 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first_min, last_min, comp));
1325 first1 = first2;
1326 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first, first1, comp));
1327 }
1328 else {
1329 RandIt const unmerged = op_partial_merge_and_save(first1, last1, first2, last2, first_min, buffer, buffer_end, comp, op, is_range1_A);
1330 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_mrs: ", len);
1331 bool const is_range_1_empty = buffer == buffer_end;
1332 assert(is_range_1_empty || (buffer_end-buffer) == (last1+l_block-unmerged));
1333 if(is_range_1_empty){
1334 buffer = buffer_end = buf_first;
1335 first_min = last_min - (last2 - first2);
1336
1337 buffer_end = buffer_and_update_key(key_next, key_range2, key_mid, first2, last2, first_min, buf_first, op);
1338 }
1339 else{
1340 first_min = last_min;
1341
1342 update_key(key_next, key_range2, key_mid);
1343 }
1344 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(!is_range_1_empty || (last_min-first_min) == (last2-unmerged));
1345 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_swp: ", len);
1346 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first_min, last_min, comp));
1347 is_range1_A ^= is_range_1_empty;
1348 first1 = unmerged;
1349 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first, unmerged, comp));
1350 }
1351 assert( (is_range2_A && n_block_a_left) || (!is_range2_A && n_block_b_left));
1352 is_range2_A ? --n_block_a_left : --n_block_b_left;
1353 last1 += l_block;
1354 first2 = last2;
1355
1356 ++key_range2;
1357 min_check = size_type(min_check - (min_check != 0));
1358 max_check = size_type(max_check - (max_check != 0));
1359 }
1360 RandIt res = op(forward_t(), buffer, buffer_end, first1);
1361 boost::movelib::ignore(res);
1362 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first, res, comp));
1363 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_fwd: ", len);
1364
1365
1366
1367
1368 RandIt const last_irr2 = first_irr2 + l_irreg2;
1369 op(forward_t(), first_irr2, first_irr2+l_irreg2, buf_first);
1370 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_fwir:", len);
1371 buffer = buf_first;
1372 buffer_end = buffer+l_irreg2;
1373
1374 reverse_iterator<RandItBuf> rbuf_beg(buffer_end);
1375 RandIt dest = op_merge_blocks_with_irreg
1376 ((make_reverse_iterator)(key_first + n_block_b + n_block_a), (make_reverse_iterator)(key_mid), inverse<KeyCompare>(key_comp)
1377 , (make_reverse_iterator)(first_irr2), rbuf_beg, (make_reverse_iterator)(buffer), (make_reverse_iterator)(last_irr2)
1378 , l_block, n_block_left, 0, n_block_left
1379 , inverse<Compare>(comp), true, op).base();
1380 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(dest, last_irr2, comp));
1381 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_irg: ", len);
1382
1383 buffer_end = rbuf_beg.base();
1384 assert((dest-last1) == (buffer_end-buffer));
1385 op_merge_with_left_placed(is_range1_A ? first1 : last1, last1, dest, buffer, buffer_end, comp, op);
1386 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_with_left_plc:", len);
1387 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(first, last_irr2, comp));
1388 }
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400 template<class RandIt, class Compare, class Op>
1401 typename iter_size<RandIt>::type
1402 op_insertion_sort_step_left
1403 ( RandIt const first
1404 , typename iter_size<RandIt>::type const length
1405 , typename iter_size<RandIt>::type const step
1406 , Compare comp, Op op)
1407 {
1408 typedef typename iter_size<RandIt>::type size_type;
1409
1410 size_type const s = min_value<size_type>(step, AdaptiveSortInsertionSortThreshold);
1411 size_type m = 0;
1412
1413 while(size_type(length - m) > s){
1414 insertion_sort_op(first+m, first+m+s, first+m-s, comp, op);
1415 m = size_type(m + s);
1416 }
1417 insertion_sort_op(first+m, first+length, first+m-s, comp, op);
1418 return s;
1419 }
1420
1421 template<class RandIt, class Compare, class Op>
1422 void op_merge_right_step_once
1423 ( RandIt first_block
1424 , typename iter_size<RandIt>::type const elements_in_blocks
1425 , typename iter_size<RandIt>::type const l_build_buf
1426 , Compare comp
1427 , Op op)
1428 {
1429 typedef typename iter_size<RandIt>::type size_type;
1430 size_type restk = size_type(elements_in_blocks%(2*l_build_buf));
1431 size_type p = size_type(elements_in_blocks - restk);
1432 assert(0 == (p%(2*l_build_buf)));
1433
1434 if(restk <= l_build_buf){
1435 op(backward_t(),first_block+p, first_block+p+restk, first_block+p+restk+l_build_buf);
1436 }
1437 else{
1438 op_merge_right(first_block+p, first_block+p+l_build_buf, first_block+p+restk, first_block+p+restk+l_build_buf, comp, op);
1439 }
1440 while(p>0){
1441 p = size_type(p - 2u*l_build_buf);
1442 op_merge_right( first_block+p, first_block+size_type(p+l_build_buf)
1443 , first_block+size_type(p+2*l_build_buf)
1444 , first_block+size_type(p+3*l_build_buf), comp, op);
1445 }
1446 }
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458 template<class RandIt, class Compare>
1459 typename iter_size<RandIt>::type
1460 insertion_sort_step
1461 ( RandIt const first
1462 , typename iter_size<RandIt>::type const length
1463 , typename iter_size<RandIt>::type const step
1464 , Compare comp)
1465 {
1466 typedef typename iter_size<RandIt>::type size_type;
1467 size_type const s = min_value<size_type>(step, AdaptiveSortInsertionSortThreshold);
1468 size_type m = 0;
1469
1470 while((length - m) > s){
1471 insertion_sort(first+m, first+m+s, comp);
1472 m = size_type(m + s);
1473 }
1474 insertion_sort(first+m, first+length, comp);
1475 return s;
1476 }
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487 template<class RandIt, class Compare, class Op>
1488 typename iter_size<RandIt>::type
1489 op_merge_left_step_multiple
1490 ( RandIt first_block
1491 , typename iter_size<RandIt>::type const elements_in_blocks
1492 , typename iter_size<RandIt>::type l_merged
1493 , typename iter_size<RandIt>::type const l_build_buf
1494 , typename iter_size<RandIt>::type l_left_space
1495 , Compare comp
1496 , Op op)
1497 {
1498 typedef typename iter_size<RandIt>::type size_type;
1499 for(; l_merged < l_build_buf && l_left_space >= l_merged; l_merged = size_type(l_merged*2u)){
1500 size_type p0=0;
1501 RandIt pos = first_block;
1502 while((elements_in_blocks - p0) > 2*l_merged) {
1503 op_merge_left(pos-l_merged, pos, pos+l_merged, pos+size_type(2*l_merged), comp, op);
1504 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(pos-l_merged, pos+l_merged, comp));
1505 p0 = size_type(p0 + 2u*l_merged);
1506 pos = first_block+p0;
1507 }
1508 if((elements_in_blocks-p0) > l_merged) {
1509 op_merge_left(pos-l_merged, pos, pos+l_merged, first_block+elements_in_blocks, comp, op);
1510 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT
1511 (boost::movelib::is_sorted
1512 (pos-l_merged, pos+size_type((first_block+elements_in_blocks-pos))-l_merged, comp));
1513 }
1514 else {
1515 op(forward_t(), pos, first_block+elements_in_blocks, pos-l_merged);
1516 BOOST_MOVE_ADAPTIVE_SORT_INVARIANT
1517 (boost::movelib::is_sorted
1518 (pos-l_merged, first_block+size_type(elements_in_blocks-l_merged), comp));
1519 }
1520 first_block -= l_merged;
1521 l_left_space = size_type(l_left_space - l_merged);
1522 }
1523 return l_merged;
1524 }
1525
1526
1527 }
1528 }
1529 }
1530
1531 #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
1532 #pragma GCC diagnostic pop
1533 #endif
1534
1535 #include <boost/move/detail/config_end.hpp>
1536
1537 #endif