forked from boostorg/move
Add merge_adaptive_ONlogN for tests
This commit is contained in:
@@ -23,6 +23,257 @@
|
||||
namespace boost {
|
||||
namespace movelib {
|
||||
|
||||
template<class T, class RandRawIt = T*>
|
||||
class adaptive_xbuf
|
||||
{
|
||||
adaptive_xbuf(const adaptive_xbuf &);
|
||||
adaptive_xbuf & operator=(const adaptive_xbuf &);
|
||||
|
||||
#if !defined(UINTPTR_MAX)
|
||||
typedef std::size_t uintptr_t;
|
||||
#endif
|
||||
|
||||
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){
|
||||
BOOST_TRY
|
||||
{
|
||||
::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]);
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
while(m_size)
|
||||
{
|
||||
--m_size;
|
||||
m_ptr[m_size].~T();
|
||||
}
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
}
|
||||
|
||||
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 begin() 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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// @cond
|
||||
|
||||
/*
|
||||
@@ -256,6 +507,45 @@ void swap_merge_right
|
||||
op_merge_right(first1, last1, last2, buf_last, comp, swap_op());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: min(len1,len2)^2 + max(len1,len2)
|
||||
template<class RandIt, class Compare>
|
||||
void merge_bufferless_ON2(RandIt first, RandIt middle, RandIt last, Compare comp)
|
||||
@@ -289,13 +579,13 @@ void merge_bufferless_ON2(RandIt first, RandIt middle, RandIt last, Compare comp
|
||||
}
|
||||
}
|
||||
|
||||
static const std::size_t MergeBufferlessONLogNRotationThreshold = 32;
|
||||
static const std::size_t MergeBufferlessONLogNRotationThreshold = 16u;
|
||||
|
||||
template <class RandIt, class Distance, class Compare>
|
||||
template <class RandIt, class SizeType, class Compare>
|
||||
void merge_bufferless_ONlogN_recursive
|
||||
(RandIt first, RandIt middle, RandIt last, Distance len1, Distance len2, Compare comp)
|
||||
(RandIt first, RandIt middle, RandIt last, SizeType len1, SizeType len2, Compare comp)
|
||||
{
|
||||
typedef typename iterator_traits<RandIt>::size_type size_type;
|
||||
typedef SizeType size_type;
|
||||
|
||||
while(1) {
|
||||
//trivial cases
|
||||
@@ -317,8 +607,8 @@ void merge_bufferless_ONlogN_recursive
|
||||
|
||||
RandIt first_cut = first;
|
||||
RandIt second_cut = middle;
|
||||
Distance len11 = 0;
|
||||
Distance len22 = 0;
|
||||
size_type len11 = 0;
|
||||
size_type len22 = 0;
|
||||
if (len1 > len2) {
|
||||
len11 = len1 / 2;
|
||||
first_cut += len11;
|
||||
@@ -334,16 +624,16 @@ void merge_bufferless_ONlogN_recursive
|
||||
RandIt new_middle = rotate_gcd(first_cut, middle, second_cut);
|
||||
|
||||
//Avoid one recursive call doing a manual tail call elimination on the biggest range
|
||||
const Distance len_internal = len11+len22;
|
||||
const size_type len_internal = len11+len22;
|
||||
if( len_internal < (len1 + len2 - len_internal) ) {
|
||||
merge_bufferless_ONlogN_recursive(first, first_cut, new_middle, len11, len22, comp);
|
||||
merge_bufferless_ONlogN_recursive(first, first_cut, new_middle, len11, len22, comp);
|
||||
first = new_middle;
|
||||
middle = second_cut;
|
||||
len1 -= len11;
|
||||
len2 -= len22;
|
||||
}
|
||||
else {
|
||||
merge_bufferless_ONlogN_recursive(new_middle, second_cut, last, len1 - len11, len2 - len22, comp);
|
||||
merge_bufferless_ONlogN_recursive(new_middle, second_cut, last, len1 - len11, len2 - len22, comp);
|
||||
middle = first_cut;
|
||||
last = new_middle;
|
||||
len1 = len11;
|
||||
@@ -352,12 +642,14 @@ void merge_bufferless_ONlogN_recursive
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Complexity: NlogN
|
||||
template<class RandIt, class Compare>
|
||||
void merge_bufferless_ONlogN(RandIt first, RandIt middle, RandIt last, Compare comp)
|
||||
{
|
||||
typedef typename iterator_traits<RandIt>::size_type size_type;
|
||||
merge_bufferless_ONlogN_recursive
|
||||
(first, middle, last, middle - first, last - middle, comp);
|
||||
(first, middle, last, size_type(middle - first), size_type(last - middle), comp);
|
||||
}
|
||||
|
||||
template<class RandIt, class Compare>
|
||||
@@ -441,7 +733,7 @@ void op_merge_with_left_placed
|
||||
|
||||
// @endcond
|
||||
|
||||
// [irst, last) are already in the right part of the destination range.
|
||||
// [first, last) are already in the right part of the destination range.
|
||||
template <class Compare, class BidirIterator, class BidirOutIterator>
|
||||
void merge_with_left_placed
|
||||
( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
|
||||
@@ -547,6 +839,131 @@ void uninitialized_merge_with_left_placed
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/// This is a helper function for the merge routines.
|
||||
template<typename BidirectionalIterator1, typename BidirectionalIterator2,
|
||||
typename SizeType>
|
||||
BidirectionalIterator1
|
||||
rotate_adaptive(BidirectionalIterator1 first,
|
||||
BidirectionalIterator1 middle,
|
||||
BidirectionalIterator1 last,
|
||||
SizeType len1, SizeType len2,
|
||||
BidirectionalIterator2 buffer,
|
||||
SizeType buffer_size)
|
||||
{
|
||||
if (len1 > len2 && len2 <= buffer_size)
|
||||
{
|
||||
BidirectionalIterator2 buffer_end = boost::move(middle, last, buffer);
|
||||
boost::move_backward(first, middle, last);
|
||||
return boost::move(buffer, buffer_end, first);
|
||||
}
|
||||
else if (len1 <= buffer_size)
|
||||
{
|
||||
BidirectionalIterator2 buffer_end = boost::move(first, middle, buffer);
|
||||
boost::move(middle, last, first);
|
||||
return boost::move_backward(buffer, buffer_end, last);
|
||||
}
|
||||
else
|
||||
return rotate_gcd(first, middle, last);
|
||||
}
|
||||
|
||||
template<typename BidirectionalIterator, typename SizeType,
|
||||
typename Pointer, typename Compare>
|
||||
void merge_adaptive_ONlogN_recursive
|
||||
(BidirectionalIterator first,
|
||||
BidirectionalIterator middle,
|
||||
BidirectionalIterator last,
|
||||
SizeType len1, SizeType len2,
|
||||
Pointer buffer, SizeType buffer_size,
|
||||
Compare comp)
|
||||
{
|
||||
typedef typename iterator_traits<BidirectionalIterator>::size_type size_type;
|
||||
if (len1 <= buffer_size || len2 <= buffer_size)
|
||||
{
|
||||
range_xbuf<Pointer, move_op> rxbuf(buffer, buffer + buffer_size);
|
||||
buffered_merge(first, middle, last, comp, rxbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
//trivial cases
|
||||
if (!len2) {
|
||||
return;
|
||||
}
|
||||
else if (!len1) {
|
||||
return;
|
||||
}
|
||||
else if (size_type(len1 | len2) == 1u) {
|
||||
if (comp(*middle, *first))
|
||||
adl_move_swap(*first, *middle);
|
||||
return;
|
||||
}
|
||||
else if (size_type(len1 + len2) < MergeBufferlessONLogNRotationThreshold) {
|
||||
merge_bufferless_ON2(first, middle, last, comp);
|
||||
return;
|
||||
}
|
||||
BidirectionalIterator first_cut = first;
|
||||
BidirectionalIterator second_cut = middle;
|
||||
size_type len11 = 0;
|
||||
size_type len22 = 0;
|
||||
if (len1 > len2) //(len1 < len2)
|
||||
{
|
||||
len11 = len1 / 2;
|
||||
//len11 = buffer_size;
|
||||
first_cut += len11;
|
||||
second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
|
||||
len22 = second_cut - middle;
|
||||
}
|
||||
else
|
||||
{
|
||||
//len22 = len2 / 2;
|
||||
len22 = buffer_size;
|
||||
second_cut += len22;
|
||||
first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
|
||||
len11 = first_cut - first;
|
||||
}
|
||||
|
||||
BidirectionalIterator new_middle
|
||||
= rotate_adaptive(first_cut, middle, second_cut,
|
||||
len1 - len11, len22, buffer,
|
||||
buffer_size);
|
||||
merge_adaptive_ONlogN_recursive(first, first_cut, new_middle, len11,
|
||||
len22, buffer, buffer_size, comp);
|
||||
merge_adaptive_ONlogN_recursive(new_middle, second_cut, last,
|
||||
len1 - len11, len2 - len22, buffer, buffer_size, comp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename BidirectionalIterator, typename Compare, typename RandRawIt>
|
||||
void merge_adaptive_ONlogN(BidirectionalIterator first,
|
||||
BidirectionalIterator middle,
|
||||
BidirectionalIterator last,
|
||||
Compare comp,
|
||||
RandRawIt uninitialized,
|
||||
std::size_t uninitialized_len)
|
||||
{
|
||||
typedef typename iterator_traits<BidirectionalIterator>::value_type value_type;
|
||||
typedef typename iterator_traits<BidirectionalIterator>::size_type size_type;
|
||||
|
||||
if (first == middle || middle == last)
|
||||
return;
|
||||
|
||||
if(uninitialized_len)
|
||||
{
|
||||
const size_type len1 = size_type(middle - first);
|
||||
const size_type len2 = size_type(last - middle);
|
||||
|
||||
::boost::movelib::adaptive_xbuf<value_type, RandRawIt> xbuf(uninitialized, uninitialized_len);
|
||||
xbuf.initialize_until(uninitialized_len, *first);
|
||||
merge_adaptive_ONlogN_recursive(first, middle, last, len1, len2, xbuf.begin(), uninitialized_len, comp);
|
||||
}
|
||||
else
|
||||
{
|
||||
merge_bufferless(first, middle, last, comp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} //namespace movelib {
|
||||
} //namespace boost {
|
||||
|
||||
|
Reference in New Issue
Block a user