123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654 |
- #ifndef BOOST_MOVE_ADAPTIVE_SORT_HPP
- #define BOOST_MOVE_ADAPTIVE_SORT_HPP
- #include <boost/move/detail/config_begin.hpp>
- #include <boost/move/algo/detail/adaptive_sort_merge.hpp>
- #include <cassert>
- #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wsign-conversion"
- #endif
- namespace boost {
- namespace movelib {
- namespace detail_adaptive {
- template<class RandIt>
- void move_data_backward( RandIt cur_pos
- , typename iter_size<RandIt>::type const l_data
- , RandIt new_pos
- , bool const xbuf_used)
- {
-
- if(xbuf_used){
- boost::move_backward(cur_pos, cur_pos+l_data, new_pos+l_data);
- }
- else{
- boost::adl_move_swap_ranges_backward(cur_pos, cur_pos+l_data, new_pos+l_data);
-
-
- }
- }
- template<class RandIt>
- void move_data_forward( RandIt cur_pos
- , typename iter_size<RandIt>::type const l_data
- , RandIt new_pos
- , bool const xbuf_used)
- {
-
- if(xbuf_used){
- boost::move(cur_pos, cur_pos+l_data, new_pos);
- }
- else{
- boost::adl_move_swap_ranges(cur_pos, cur_pos+l_data, new_pos);
-
-
- }
- }
- template<class RandIt, class Compare, class XBuf>
- typename iter_size<RandIt>::type
- adaptive_sort_build_blocks
- ( RandIt const first
- , typename iter_size<RandIt>::type const len
- , typename iter_size<RandIt>::type const l_base
- , typename iter_size<RandIt>::type const l_build_buf
- , XBuf & xbuf
- , Compare comp)
- {
- typedef typename iter_size<RandIt>::type size_type;
- assert(l_build_buf <= len);
- assert(0 == ((l_build_buf / l_base)&(l_build_buf/l_base-1)));
-
- RandIt first_block = first + l_build_buf;
- size_type const elements_in_blocks = size_type(len - l_build_buf);
-
-
-
- size_type l_merged = 0u;
- assert(l_build_buf);
-
- size_type kbuf = min_value<size_type>(l_build_buf, size_type(xbuf.capacity()));
- kbuf = kbuf < l_base ? 0 : kbuf;
- if(kbuf){
-
- xbuf.move_assign(first+l_build_buf-kbuf, kbuf);
- l_merged = op_insertion_sort_step_left(first_block, elements_in_blocks, l_base, comp, move_op());
-
-
- l_merged = op_merge_left_step_multiple
- ( first_block - l_merged, elements_in_blocks, l_merged, l_build_buf, size_type(kbuf - l_merged), comp, move_op());
-
-
- if(kbuf != l_build_buf){
- boost::move(xbuf.data()+kbuf-l_merged, xbuf.data() + kbuf, first_block-l_merged+elements_in_blocks);
- }
- }
- else{
- l_merged = insertion_sort_step(first_block, elements_in_blocks, l_base, comp);
- rotate_gcd(first_block-l_merged, first_block, first_block+elements_in_blocks);
- }
-
-
- l_merged = op_merge_left_step_multiple
- (first_block-l_merged, elements_in_blocks, l_merged, l_build_buf, size_type(l_build_buf - l_merged), comp, swap_op());
- assert(l_merged == l_build_buf);
-
-
-
-
-
- if(kbuf && kbuf == l_build_buf){
- op_merge_right_step_once(first, elements_in_blocks, l_build_buf, comp, move_op());
-
-
- boost::move(xbuf.data(), xbuf.data() + kbuf, first);
- }
- else{
- op_merge_right_step_once(first, elements_in_blocks, l_build_buf, comp, swap_op());
- }
- xbuf.clear();
-
- return min_value<size_type>(elements_in_blocks, size_type(2u*l_build_buf));
- }
- template<class RandItKeys, class KeyCompare, class RandIt, class Compare, class XBuf>
- void adaptive_sort_combine_blocks
- ( RandItKeys const keys
- , KeyCompare key_comp
- , RandIt const first
- , typename iter_size<RandIt>::type const len
- , typename iter_size<RandIt>::type const l_prev_merged
- , typename iter_size<RandIt>::type const l_block
- , bool const use_buf
- , bool const xbuf_used
- , XBuf & xbuf
- , Compare comp
- , bool merge_left)
- {
- boost::movelib::ignore(xbuf);
- typedef typename iter_size<RandIt>::type size_type;
- size_type const l_reg_combined = size_type(2u*l_prev_merged);
- size_type l_irreg_combined = 0;
- size_type const l_total_combined = calculate_total_combined(len, l_prev_merged, &l_irreg_combined);
- size_type const n_reg_combined = len/l_reg_combined;
- RandIt combined_first = first;
- boost::movelib::ignore(l_total_combined);
- assert(l_total_combined <= len);
- size_type const max_i = size_type(n_reg_combined + (l_irreg_combined != 0));
- if(merge_left || !use_buf) {
- for( size_type combined_i = 0; combined_i != max_i; ) {
-
- bool const is_last = combined_i==n_reg_combined;
- size_type const l_cur_combined = is_last ? l_irreg_combined : l_reg_combined;
- range_xbuf<RandIt, size_type, move_op> rbuf( (use_buf && xbuf_used) ? (combined_first-l_block) : combined_first, combined_first);
- size_type n_block_a, n_block_b, l_irreg1, l_irreg2;
- combine_params( keys, key_comp, l_cur_combined
- , l_prev_merged, l_block, rbuf
- , n_block_a, n_block_b, l_irreg1, l_irreg2);
- BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" A combpar: ", len + l_block);
- BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(combined_first, combined_first + n_block_a*l_block+l_irreg1, comp));
- BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(combined_first + n_block_a*l_block+l_irreg1, combined_first + n_block_a*l_block+l_irreg1+n_block_b*l_block+l_irreg2, comp));
- if(!use_buf){
- merge_blocks_bufferless
- (keys, key_comp, combined_first, l_block, 0u, n_block_a, n_block_b, l_irreg2, comp);
- }
- else{
- merge_blocks_left
- (keys, key_comp, combined_first, l_block, 0u, n_block_a, n_block_b, l_irreg2, comp, xbuf_used);
- }
- BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" After merge_blocks_L: ", len + l_block);
- ++combined_i;
- if(combined_i != max_i)
- combined_first += l_reg_combined;
- }
- }
- else{
- combined_first += size_type(l_reg_combined*(max_i-1u));
- for( size_type combined_i = max_i; combined_i; ) {
- --combined_i;
- bool const is_last = combined_i==n_reg_combined;
- size_type const l_cur_combined = is_last ? l_irreg_combined : l_reg_combined;
- RandIt const combined_last(combined_first+l_cur_combined);
- range_xbuf<RandIt, size_type, move_op> rbuf(combined_last, xbuf_used ? (combined_last+l_block) : combined_last);
- size_type n_block_a, n_block_b, l_irreg1, l_irreg2;
- combine_params( keys, key_comp, l_cur_combined
- , l_prev_merged, l_block, rbuf
- , n_block_a, n_block_b, l_irreg1, l_irreg2);
- BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" A combpar: ", len + l_block);
- BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(combined_first, combined_first + n_block_a*l_block+l_irreg1, comp));
- BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(combined_first + n_block_a*l_block+l_irreg1, combined_first + n_block_a*l_block+l_irreg1+n_block_b*l_block+l_irreg2, comp));
- merge_blocks_right
- (keys, key_comp, combined_first, l_block, n_block_a, n_block_b, l_irreg2, comp, xbuf_used);
- BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" After merge_blocks_R: ", len + l_block);
- if(combined_i)
- combined_first -= l_reg_combined;
- }
- }
- }
- template<class RandIt, class Compare, class XBuf>
- bool adaptive_sort_combine_all_blocks
- ( RandIt keys
- , typename iter_size<RandIt>::type &n_keys
- , RandIt const buffer
- , typename iter_size<RandIt>::type const l_buf_plus_data
- , typename iter_size<RandIt>::type l_merged
- , typename iter_size<RandIt>::type &l_intbuf
- , XBuf & xbuf
- , Compare comp)
- {
- typedef typename iter_size<RandIt>::type size_type;
- RandIt const first = buffer + l_intbuf;
- size_type const l_data = size_type(l_buf_plus_data - l_intbuf);
- size_type const l_unique = size_type(l_intbuf + n_keys);
-
- bool const common_xbuf = l_data > l_merged && l_intbuf && l_intbuf <= xbuf.capacity();
- if(common_xbuf){
- xbuf.move_assign(buffer, l_intbuf);
- }
- bool prev_merge_left = true;
- size_type l_prev_total_combined = l_merged, l_prev_block = 0;
- bool prev_use_internal_buf = true;
- for( size_type n = 0; l_data > l_merged
- ; l_merged = size_type(2u*l_merged)
- , ++n){
-
-
-
-
-
- bool use_internal_buf = false;
- size_type const l_block = lblock_for_combine(l_intbuf, n_keys, size_type(2*l_merged), use_internal_buf);
- assert(!l_intbuf || (l_block == l_intbuf));
- assert(n == 0 || (!use_internal_buf || prev_use_internal_buf) );
- assert(n == 0 || (!use_internal_buf || l_prev_block == l_block) );
-
- bool const is_merge_left = (n&1) == 0;
- size_type const l_total_combined = calculate_total_combined(l_data, l_merged);
- if(n && prev_use_internal_buf && prev_merge_left){
- if(is_merge_left || !use_internal_buf){
- move_data_backward(first-l_prev_block, l_prev_total_combined, first, common_xbuf);
- }
- else{
-
- RandIt const buf_end = first+l_prev_total_combined;
- RandIt const buf_beg = buf_end-l_block;
- if(l_prev_total_combined > l_total_combined){
- size_type const l_diff = size_type(l_prev_total_combined - l_total_combined);
- move_data_backward(buf_beg-l_diff, l_diff, buf_end-l_diff, common_xbuf);
- }
- else if(l_prev_total_combined < l_total_combined){
- size_type const l_diff = size_type(l_total_combined - l_prev_total_combined);
- move_data_forward(buf_end, l_diff, buf_beg, common_xbuf);
- }
- }
- BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" After move_data : ", l_data + l_intbuf);
- }
-
- if(n_keys){
- size_type upper_n_keys_this_iter = size_type(2u*l_merged/l_block);
- if(upper_n_keys_this_iter > 256){
- adaptive_sort_combine_blocks
- ( keys, comp, !use_internal_buf || is_merge_left ? first : first-l_block
- , l_data, l_merged, l_block, use_internal_buf, common_xbuf, xbuf, comp, is_merge_left);
- }
- else{
- unsigned char uint_keys[256];
- adaptive_sort_combine_blocks
- ( uint_keys, less(), !use_internal_buf || is_merge_left ? first : first-l_block
- , l_data, l_merged, l_block, use_internal_buf, common_xbuf, xbuf, comp, is_merge_left);
- }
- }
- else{
- size_type *const uint_keys = xbuf.template aligned_trailing<size_type>();
- adaptive_sort_combine_blocks
- ( uint_keys, less(), !use_internal_buf || is_merge_left ? first : first-l_block
- , l_data, l_merged, l_block, use_internal_buf, common_xbuf, xbuf, comp, is_merge_left);
- }
- BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(is_merge_left ? " After comb blocks L: " : " After comb blocks R: ", l_data + l_intbuf);
- prev_merge_left = is_merge_left;
- l_prev_total_combined = l_total_combined;
- l_prev_block = l_block;
- prev_use_internal_buf = use_internal_buf;
- }
- assert(l_prev_total_combined == l_data);
- bool const buffer_right = prev_use_internal_buf && prev_merge_left;
- l_intbuf = prev_use_internal_buf ? l_prev_block : 0u;
- n_keys = size_type(l_unique - l_intbuf);
-
- if(common_xbuf){
- if(buffer_right){
- boost::move(xbuf.data(), xbuf.data() + l_intbuf, buffer+l_data);
- }
- else{
- boost::move(xbuf.data(), xbuf.data() + l_intbuf, buffer);
- }
- }
- return buffer_right;
- }
- template<class RandIt, class Compare, class XBuf>
- void adaptive_sort_final_merge( bool buffer_right
- , RandIt const first
- , typename iter_size<RandIt>::type const l_intbuf
- , typename iter_size<RandIt>::type const n_keys
- , typename iter_size<RandIt>::type const len
- , XBuf & xbuf
- , Compare comp)
- {
-
- xbuf.clear();
- typedef typename iter_size<RandIt>::type size_type;
- size_type const n_key_plus_buf = size_type(l_intbuf+n_keys);
- if(buffer_right){
-
- stable_sort(first+len-l_intbuf, first+len, comp, xbuf);
- stable_merge( first+n_keys, first+len-l_intbuf, first+len, antistable<Compare>(comp), xbuf);
- unstable_sort(first, first+n_keys, comp, xbuf);
- stable_merge(first, first+n_keys, first+len, comp, xbuf);
- }
- else{
-
- stable_sort(first, first+n_key_plus_buf, comp, xbuf);
- if(xbuf.capacity() >= n_key_plus_buf){
- buffered_merge(first, first+n_key_plus_buf, first+len, comp, xbuf);
- }
- else if(xbuf.capacity() >= min_value<size_type>(l_intbuf, n_keys)){
- stable_merge( first+n_keys, first+n_key_plus_buf
- , first+len, comp, xbuf);
- stable_merge(first, first+n_keys, first+len, comp, xbuf);
- }
- else{
- stable_merge(first, first+n_key_plus_buf, first+len, comp, xbuf);
- }
- }
- BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(" After final_merge : ", len);
- }
- template<class RandIt, class Compare, class Unsigned, class XBuf>
- bool adaptive_sort_build_params
- (RandIt first, Unsigned const len, Compare comp
- , Unsigned &n_keys, Unsigned &l_intbuf, Unsigned &l_base, Unsigned &l_build_buf
- , XBuf & xbuf
- )
- {
- typedef typename iter_size<RandIt>::type size_type;
-
- l_base = 0u;
-
-
-
-
-
-
- l_intbuf = size_type(ceil_sqrt_multiple(len, &l_base));
-
- while(xbuf.capacity() >= l_intbuf*2){
- l_intbuf = size_type(2u*l_intbuf);
- }
-
-
-
- size_type n_min_ideal_keys = size_type(l_intbuf-1u);
- while(n_min_ideal_keys >= (len-l_intbuf-n_min_ideal_keys)/l_intbuf){
- --n_min_ideal_keys;
- }
- ++n_min_ideal_keys;
- assert(n_min_ideal_keys <= l_intbuf);
- if(xbuf.template supports_aligned_trailing<size_type>
- (l_intbuf, size_type((size_type(len-l_intbuf)-1u)/l_intbuf+1u))){
- n_keys = 0u;
- l_build_buf = l_intbuf;
- }
- else{
-
-
-
-
-
-
-
- bool const non_unique_buf = xbuf.capacity() >= l_intbuf;
- size_type const to_collect = non_unique_buf ? n_min_ideal_keys : size_type(l_intbuf*2u);
- size_type collected = collect_unique(first, first+len, to_collect, comp, xbuf);
-
-
- if(non_unique_buf && collected == n_min_ideal_keys){
- l_build_buf = l_intbuf;
- n_keys = n_min_ideal_keys;
- }
- else if(collected == 2*l_intbuf){
-
- l_build_buf = size_type(l_intbuf*2);
- n_keys = l_intbuf;
- }
- else if(collected >= (n_min_ideal_keys+l_intbuf)){
- l_build_buf = l_intbuf;
- n_keys = size_type(collected - l_intbuf);
- }
-
-
- else{
- assert(collected < (n_min_ideal_keys+l_intbuf));
- if(collected < 4){
- return false;
- }
- n_keys = l_intbuf;
- while(n_keys & (n_keys-1u)){
- n_keys &= size_type(n_keys-1u);
- }
- while(n_keys > collected){
- n_keys/=2;
- }
-
- l_base = min_value<Unsigned>(n_keys, AdaptiveSortInsertionSortThreshold);
- l_intbuf = 0;
- l_build_buf = n_keys;
- }
- assert((n_keys+l_intbuf) >= l_build_buf);
- }
- return true;
- }
- template<class RandIt, class Compare, class XBuf>
- void adaptive_sort_impl
- ( RandIt first
- , typename iter_size<RandIt>::type const len
- , Compare comp
- , XBuf & xbuf
- )
- {
- typedef typename iter_size<RandIt>::type size_type;
-
- if(len <= size_type(AdaptiveSortInsertionSortThreshold)){
- insertion_sort(first, first + len, comp);
- }
- else if((len-len/2) <= xbuf.capacity()){
- merge_sort(first, first+len, comp, xbuf.data());
- }
- else{
-
- BOOST_MOVE_STATIC_ASSERT(AdaptiveSortInsertionSortThreshold >= 4);
- size_type l_base = 0;
- size_type l_intbuf = 0;
- size_type n_keys = 0;
- size_type l_build_buf = 0;
-
-
- if(!adaptive_sort_build_params(first, len, comp, n_keys, l_intbuf, l_base, l_build_buf, xbuf)){
- stable_sort(first, first+len, comp, xbuf);
- }
- else{
- assert(l_build_buf);
-
- BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1("\n After collect_unique: ", len);
- size_type const n_key_plus_buf = size_type(l_intbuf+n_keys);
-
- assert(l_intbuf || (0 == (l_build_buf & (l_build_buf-1))));
-
- size_type const l_merged = adaptive_sort_build_blocks
- ( first + n_key_plus_buf-l_build_buf
- , size_type(len-n_key_plus_buf+l_build_buf)
- , l_base, l_build_buf, xbuf, comp);
- BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(" After build_blocks: ", len);
-
- bool const buffer_right = adaptive_sort_combine_all_blocks
- (first, n_keys, first+n_keys, size_type(len-n_keys), l_merged, l_intbuf, xbuf, comp);
-
- adaptive_sort_final_merge(buffer_right, first, l_intbuf, n_keys, len, xbuf, comp);
- }
- }
- }
- }
- template<class RandIt, class RandRawIt, class Compare>
- void adaptive_sort( RandIt first, RandIt last, Compare comp
- , RandRawIt uninitialized
- , typename iter_size<RandIt>::type uninitialized_len)
- {
- typedef typename iter_size<RandIt>::type size_type;
- typedef typename iterator_traits<RandIt>::value_type value_type;
- ::boost::movelib::adaptive_xbuf<value_type, RandRawIt, size_type> xbuf(uninitialized, uninitialized_len);
- ::boost::movelib::detail_adaptive::adaptive_sort_impl(first, size_type(last - first), comp, xbuf);
- }
- template<class RandIt, class Compare>
- void adaptive_sort( RandIt first, RandIt last, Compare comp)
- {
- typedef typename iterator_traits<RandIt>::value_type value_type;
- adaptive_sort(first, last, comp, (value_type*)0, 0u);
- }
- }
- }
- #include <boost/move/detail/config_end.hpp>
- #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
- #pragma GCC diagnostic pop
- #endif
- #endif
|