From 580ec87d09ce6706955ae5aa3afe1d95b99b375f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 31 Dec 2018 00:56:51 +0100 Subject: [PATCH] Fix bug in merge_blocks_bufferless and improve bufer performance with buffer_and_update_key --- .../move/algo/detail/adaptive_sort_merge.hpp | 346 ++++-------------- 1 file changed, 65 insertions(+), 281 deletions(-) diff --git a/include/boost/move/algo/detail/adaptive_sort_merge.hpp b/include/boost/move/algo/detail/adaptive_sort_merge.hpp index 4c28086..6b2aa8f 100644 --- a/include/boost/move/algo/detail/adaptive_sort_merge.hpp +++ b/include/boost/move/algo/detail/adaptive_sort_merge.hpp @@ -143,236 +143,6 @@ typename iterator_traits::size_type return count; } -template -class adaptive_xbuf -{ - adaptive_xbuf(const adaptive_xbuf &); - adaptive_xbuf & operator=(const adaptive_xbuf &); - - public: - typedef RandRawIt iterator; - - adaptive_xbuf() - : m_ptr(), m_size(0), m_capacity(0) - {} - - adaptive_xbuf(RandRawIt raw_memory, std::size_t capacity) - : m_ptr(raw_memory), m_size(0), m_capacity(capacity) - {} - - template - void move_assign(RandIt first, std::size_t n) - { - if(n <= m_size){ - boost::move(first, first+n, m_ptr); - std::size_t size = m_size; - while(size-- != n){ - m_ptr[size].~T(); - } - m_size = n; - } - else{ - RandRawIt result = boost::move(first, first+m_size, m_ptr); - boost::uninitialized_move(first+m_size, first+n, result); - m_size = n; - } - } - - template - void push_back(RandIt first, std::size_t n) - { - BOOST_ASSERT(m_capacity - m_size >= n); - boost::uninitialized_move(first, first+n, m_ptr+m_size); - m_size += n; - } - - template - iterator add(RandIt it) - { - BOOST_ASSERT(m_size < m_capacity); - RandRawIt p_ret = m_ptr + m_size; - ::new(&*p_ret) T(::boost::move(*it)); - ++m_size; - return p_ret; - } - - template - void insert(iterator pos, RandIt it) - { - if(pos == (m_ptr + m_size)){ - this->add(it); - } - else{ - this->add(m_ptr+m_size-1); - //m_size updated - boost::move_backward(pos, m_ptr+m_size-2, m_ptr+m_size-1); - *pos = boost::move(*it); - } - } - - void set_size(std::size_t size) - { - m_size = size; - } - - void shrink_to_fit(std::size_t const size) - { - if(m_size > size){ - for(std::size_t szt_i = size; szt_i != m_size; ++szt_i){ - m_ptr[szt_i].~T(); - } - m_size = size; - } - } - - void initialize_until(std::size_t const size, T &t) - { - BOOST_ASSERT(m_size < m_capacity); - if(m_size < size){ - ::new((void*)&m_ptr[m_size]) T(::boost::move(t)); - ++m_size; - for(; m_size != size; ++m_size){ - ::new((void*)&m_ptr[m_size]) T(::boost::move(m_ptr[m_size-1])); - } - t = ::boost::move(m_ptr[m_size-1]); - } - } - - private: - template - static bool is_raw_ptr(RIt) - { - return false; - } - - static bool is_raw_ptr(T*) - { - return true; - } - - public: - template - bool supports_aligned_trailing(std::size_t size, std::size_t trail_count) const - { - if(this->is_raw_ptr(this->data()) && m_capacity){ - uintptr_t u_addr_sz = uintptr_t(&*(this->data()+size)); - uintptr_t u_addr_cp = uintptr_t(&*(this->data()+this->capacity())); - u_addr_sz = ((u_addr_sz + sizeof(U)-1)/sizeof(U))*sizeof(U); - return (u_addr_cp >= u_addr_sz) && ((u_addr_cp - u_addr_sz)/sizeof(U) >= trail_count); - } - return false; - } - - template - U *aligned_trailing() const - { - return this->aligned_trailing(this->size()); - } - - template - U *aligned_trailing(std::size_t pos) const - { - uintptr_t u_addr = uintptr_t(&*(this->data()+pos)); - u_addr = ((u_addr + sizeof(U)-1)/sizeof(U))*sizeof(U); - return (U*)u_addr; - } - - ~adaptive_xbuf() - { - this->clear(); - } - - std::size_t capacity() const - { return m_capacity; } - - iterator data() const - { return m_ptr; } - - iterator end() const - { return m_ptr+m_size; } - - std::size_t size() const - { return m_size; } - - bool empty() const - { return !m_size; } - - void clear() - { - this->shrink_to_fit(0u); - } - - private: - RandRawIt m_ptr; - std::size_t m_size; - std::size_t m_capacity; -}; - -template -class range_xbuf -{ - range_xbuf(const range_xbuf &); - range_xbuf & operator=(const range_xbuf &); - - public: - typedef typename iterator_traits::size_type size_type; - typedef Iterator iterator; - - range_xbuf(Iterator first, Iterator last) - : m_first(first), m_last(first), m_cap(last) - {} - - template - void move_assign(RandIt first, std::size_t n) - { - BOOST_ASSERT(size_type(n) <= size_type(m_cap-m_first)); - m_last = Op()(forward_t(), first, first+n, m_first); - } - - ~range_xbuf() - {} - - std::size_t capacity() const - { return m_cap-m_first; } - - Iterator data() const - { return m_first; } - - Iterator end() const - { return m_last; } - - std::size_t size() const - { return m_last-m_first; } - - bool empty() const - { return m_first == m_last; } - - void clear() - { - m_last = m_first; - } - - template - iterator add(RandIt it) - { - Iterator pos(m_last); - *pos = boost::move(*it); - ++m_last; - return pos; - } - - void set_size(std::size_t size) - { - m_last = m_first; - m_last += size; - } - - private: - Iterator const m_first; - Iterator m_last; - Iterator const m_cap; -}; - template RandIt skip_until_merge @@ -407,6 +177,49 @@ void swap_and_update_key } } +template +void update_key +(RandItKeys const key_next + , RandItKeys const key_range2 + , RandItKeys &key_mid) +{ + if (key_next != key_range2) { + ::boost::adl_move_swap(*key_next, *key_range2); + if (key_next == key_mid) { + key_mid = key_range2; + } + else if (key_mid == key_range2) { + key_mid = key_next; + } + } +} + +template +RandIt2 buffer_and_update_key +(RandItKeys const key_next + , RandItKeys const key_range2 + , RandItKeys &key_mid + , RandIt begin + , RandIt end + , RandIt with + , RandIt2 buffer + , Op op) +{ + if (begin != with) { + while(begin != end) { + op(three_way_t(), begin++, with++, buffer++); + } + ::boost::adl_move_swap(*key_next, *key_range2); + if (key_next == key_mid) { + key_mid = key_range2; + } + else if (key_mid == key_range2) { + key_mid = key_next; + } + } + return buffer; +} + /////////////////////////////////////////////////////////////////////////////// // // MERGE BUFFERLESS @@ -457,7 +270,7 @@ static SizeType needed_keys_count(SizeType n_block_a, SizeType n_block_b) template typename iterator_traits::size_type find_next_block - ( RandItKeys key_first + ( RandItKeys const key_first , KeyCompare key_comp , RandIt const first , typename iterator_traits::size_type const l_block @@ -488,7 +301,7 @@ typename iterator_traits::size_type template void merge_blocks_bufferless - ( RandItKeys key_first + ( RandItKeys const key_first , KeyCompare key_comp , RandIt const first , typename iterator_traits::size_type const l_block @@ -543,8 +356,8 @@ void merge_blocks_bufferless RandItKeys const key_end (key_first+n_bef_irreg2); bool is_range1_A = true; - for( ; key_first != key_end; ++key_first){ - bool is_range2_A = key_mid == (key_first+key_count) || key_comp(*key_first, *key_mid); + for(RandItKeys key_next = key_first; key_next != key_end; ++key_next){ + bool is_range2_A = key_mid == (key_first+key_count) || key_comp(*key_next, *key_mid); first1 = is_range1_A == is_range2_A ? last1 : partial_merge_bufferless(first1, last1, last1 + l_block, &is_range1_A, comp); last1 += l_block; @@ -555,45 +368,6 @@ void merge_blocks_bufferless BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(is_sorted(first, last_irr2, comp)); } -/////////////////////////////////////////////////////////////////////////////// -// -// BUFFERED MERGE -// -/////////////////////////////////////////////////////////////////////////////// -template -void op_buffered_merge - ( RandIt first, RandIt const middle, RandIt last - , Compare comp, Op op - , Buf &xbuf) -{ - if(first != middle && middle != last && comp(*middle, middle[-1])){ - typedef typename iterator_traits::size_type size_type; - size_type const len1 = size_type(middle-first); - size_type const len2 = size_type(last-middle); - if(len1 <= len2){ - first = boost::movelib::upper_bound(first, middle, *middle, comp); - xbuf.move_assign(first, size_type(middle-first)); - op_merge_with_right_placed - (xbuf.data(), xbuf.end(), first, middle, last, comp, op); - } - else{ - last = boost::movelib::lower_bound(middle, last, middle[-1], comp); - xbuf.move_assign(middle, size_type(last-middle)); - op_merge_with_left_placed - (first, middle, last, xbuf.data(), xbuf.end(), comp, op); - } - } -} - -template -void buffered_merge - ( RandIt first, RandIt const middle, RandIt last - , Compare comp - , XBuf &xbuf) -{ - op_buffered_merge(first, middle, last, comp, move_op(), xbuf); -} - // Complexity: 2*distance(first, last)+max_collected^2/2 // // Tries to collect at most n_keys unique elements from [first, last), @@ -847,7 +621,8 @@ void stable_merge xbuf.clear(); } else{ - merge_bufferless(first, middle, last, comp); + //merge_bufferless(first, middle, last, comp); + merge_adaptive_ONlogN(first, middle, last, comp, xbuf.begin(), xbuf.capacity()); } } @@ -1457,6 +1232,7 @@ void op_merge_blocks_with_buf RandIt first2 = last1; RandIt const first_irr2 = first2 + n_block_left*l_block; bool is_range1_A = true; + const size_type len = l_block * n_block_a + l_block * n_block_b + l_irreg1 + l_irreg2; (void)len; RandItKeys key_range2(key_first); @@ -1491,9 +1267,12 @@ void op_merge_blocks_with_buf BOOST_MOVE_ADAPTIVE_SORT_INVARIANT((first1 == last1) || (buffer_empty ? !comp(*first_min, last1[-1]) : !comp(*first_min, buffer_end[-1]))); //If buffered, put those elements in place RandIt res = op(forward_t(), buffer, buffer_end, first1); + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_fwd: ", len); buffer = buffer_end = buf_first; BOOST_ASSERT(buffer_empty || res == last1); (void)res; - swap_and_update_key(key_next, key_range2, key_mid, first2, last2, first_min); + //swap_and_update_key(key_next, key_range2, key_mid, first2, last2, first_min); + buffer_end = buffer_and_update_key(key_next, key_range2, key_mid, first2, last2, first_min, buffer = buf_first, op); + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_swp: ", len); BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(is_sorted(first2, last2, comp)); BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(is_sorted(first_min, last_min, comp)); first1 = first2; @@ -1501,18 +1280,22 @@ void op_merge_blocks_with_buf } else { RandIt const unmerged = op_partial_merge_and_save(first1, last1, first2, last2, first_min, buffer, buffer_end, comp, op, is_range1_A); + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_mrs: ", len); bool const is_range_1_empty = buffer == buffer_end; BOOST_ASSERT(is_range_1_empty || (buffer_end-buffer) == (last1+l_block-unmerged)); if(is_range_1_empty){ buffer = buffer_end = buf_first; first_min = last_min - (last2 - first2); + //swap_and_update_key(key_next, key_range2, key_mid, first2, last2, first_min); + buffer_end = buffer_and_update_key(key_next, key_range2, key_mid, first2, last2, first_min, buf_first, op); } else{ first_min = last_min; + //swap_and_update_key(key_next, key_range2, key_mid, first2, last2, first_min); + update_key(key_next, key_range2, key_mid); } BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(!is_range_1_empty || (last_min-first_min) == (last2-unmerged)); - swap_and_update_key(key_next, key_range2, key_mid, first2, last2, first_min); - + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_swp: ", len); BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(is_sorted(first_min, last_min, comp)); is_range1_A ^= is_range_1_empty; first1 = unmerged; @@ -1523,31 +1306,32 @@ void op_merge_blocks_with_buf last1 += l_block; first2 = last2; } - RandIt res = op(forward_t(), buffer, buffer_end, first1); (void)res; BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(is_sorted(first, res, comp)); + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_fwd: ", len); //////////////////////////////////////////////////////////////////////////// //Process irregular B block and remaining A blocks //////////////////////////////////////////////////////////////////////////// RandIt const last_irr2 = first_irr2 + l_irreg2; op(forward_t(), first_irr2, first_irr2+l_irreg2, buf_first); + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_fwir:", len); buffer = buf_first; buffer_end = buffer+l_irreg2; reverse_iterator rbuf_beg(buffer_end); RandIt dest = op_merge_blocks_with_irreg ((make_reverse_iterator)(key_first + n_block_b + n_block_a), (make_reverse_iterator)(key_mid), inverse(key_comp) - , (make_reverse_iterator)(first_irr2), rbuf_beg - , (make_reverse_iterator)(buffer), (make_reverse_iterator)(last_irr2) + , (make_reverse_iterator)(first_irr2), rbuf_beg, (make_reverse_iterator)(buffer), (make_reverse_iterator)(last_irr2) , l_block, n_block_left, 0, n_block_left , inverse(comp), true, op).base(); BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(is_sorted(dest, last_irr2, comp)); + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_blocks_w_irg: ", len); buffer_end = rbuf_beg.base(); BOOST_ASSERT((dest-last1) == (buffer_end-buffer)); op_merge_with_left_placed(is_range1_A ? first1 : last1, last1, dest, buffer, buffer_end, comp, op); - + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" merge_with_left_plc:", len); BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(is_sorted(first, last_irr2, comp)); }