forked from boostorg/move
Fix bug in merge_blocks_bufferless and improve bufer performance with buffer_and_update_key
This commit is contained in:
@@ -143,236 +143,6 @@ typename iterator_traits<ForwardIt>::size_type
|
||||
return count;
|
||||
}
|
||||
|
||||
template<class T, class RandRawIt = T*>
|
||||
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<class RandIt>
|
||||
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<class RandIt>
|
||||
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<class RandIt>
|
||||
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<class RandIt>
|
||||
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<class RIt>
|
||||
static bool is_raw_ptr(RIt)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_raw_ptr(T*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
template<class U>
|
||||
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<class U>
|
||||
U *aligned_trailing() const
|
||||
{
|
||||
return this->aligned_trailing<U>(this->size());
|
||||
}
|
||||
|
||||
template<class U>
|
||||
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 Iterator, class Op>
|
||||
class range_xbuf
|
||||
{
|
||||
range_xbuf(const range_xbuf &);
|
||||
range_xbuf & operator=(const range_xbuf &);
|
||||
|
||||
public:
|
||||
typedef typename iterator_traits<Iterator>::size_type size_type;
|
||||
typedef Iterator iterator;
|
||||
|
||||
range_xbuf(Iterator first, Iterator last)
|
||||
: m_first(first), m_last(first), m_cap(last)
|
||||
{}
|
||||
|
||||
template<class RandIt>
|
||||
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<class RandIt>
|
||||
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<class RandIt, class Compare>
|
||||
RandIt skip_until_merge
|
||||
@@ -407,6 +177,49 @@ void swap_and_update_key
|
||||
}
|
||||
}
|
||||
|
||||
template<class RandItKeys>
|
||||
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<class RandItKeys, class RandIt, class RandIt2, class Op>
|
||||
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<class RandItKeys, class KeyCompare, class RandIt, class Compare>
|
||||
typename iterator_traits<RandIt>::size_type
|
||||
find_next_block
|
||||
( RandItKeys key_first
|
||||
( RandItKeys const key_first
|
||||
, KeyCompare key_comp
|
||||
, RandIt const first
|
||||
, typename iterator_traits<RandIt>::size_type const l_block
|
||||
@@ -488,7 +301,7 @@ typename iterator_traits<RandIt>::size_type
|
||||
|
||||
template<class RandItKeys, class KeyCompare, class RandIt, class Compare>
|
||||
void merge_blocks_bufferless
|
||||
( RandItKeys key_first
|
||||
( RandItKeys const key_first
|
||||
, KeyCompare key_comp
|
||||
, RandIt const first
|
||||
, typename iterator_traits<RandIt>::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<class RandIt, class Compare, class Op, class Buf>
|
||||
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<RandIt>::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<class RandIt, class Compare, class XBuf>
|
||||
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<RandItBuf> 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<KeyCompare>(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<Compare>(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));
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user