1
0
forked from boostorg/move

Add merge_adaptive_ONlogN for tests

This commit is contained in:
Ion Gaztañaga
2018-12-31 00:52:38 +01:00
parent fcd33baf1f
commit df08df2d9d

View File

@@ -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 {