整理
This commit is contained in:
1523
include/boost/move/algo/detail/adaptive_sort_merge.hpp
Normal file
1523
include/boost/move/algo/detail/adaptive_sort_merge.hpp
Normal file
File diff suppressed because it is too large
Load Diff
122
include/boost/move/algo/detail/basic_op.hpp
Normal file
122
include/boost/move/algo/detail/basic_op.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2015-2016.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/move for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef BOOST_MOVE_ALGO_BASIC_OP
|
||||
#define BOOST_MOVE_ALGO_BASIC_OP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/move/utility_core.hpp>
|
||||
#include <boost/move/adl_move_swap.hpp>
|
||||
#include <boost/move/detail/iterator_traits.hpp>
|
||||
#include <boost/move/algo/move.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace movelib {
|
||||
|
||||
struct forward_t{};
|
||||
struct backward_t{};
|
||||
struct three_way_t{};
|
||||
struct three_way_forward_t{};
|
||||
struct four_way_t{};
|
||||
|
||||
struct move_op
|
||||
{
|
||||
template <class SourceIt, class DestinationIt>
|
||||
inline void operator()(SourceIt source, DestinationIt dest)
|
||||
{ *dest = ::boost::move(*source); }
|
||||
|
||||
template <class SourceIt, class DestinationIt>
|
||||
inline DestinationIt operator()(forward_t, SourceIt first, SourceIt last, DestinationIt dest_begin)
|
||||
{ return ::boost::move(first, last, dest_begin); }
|
||||
|
||||
template <class SourceIt, class DestinationIt>
|
||||
inline DestinationIt operator()(backward_t, SourceIt first, SourceIt last, DestinationIt dest_last)
|
||||
{ return ::boost::move_backward(first, last, dest_last); }
|
||||
|
||||
template <class SourceIt, class DestinationIt1, class DestinationIt2>
|
||||
inline void operator()(three_way_t, SourceIt srcit, DestinationIt1 dest1it, DestinationIt2 dest2it)
|
||||
{
|
||||
*dest2it = boost::move(*dest1it);
|
||||
*dest1it = boost::move(*srcit);
|
||||
}
|
||||
|
||||
template <class SourceIt, class DestinationIt1, class DestinationIt2>
|
||||
DestinationIt2 operator()(three_way_forward_t, SourceIt srcit, SourceIt srcitend, DestinationIt1 dest1it, DestinationIt2 dest2it)
|
||||
{
|
||||
//Destination2 range can overlap SourceIt range so avoid boost::move
|
||||
while(srcit != srcitend){
|
||||
this->operator()(three_way_t(), srcit++, dest1it++, dest2it++);
|
||||
}
|
||||
return dest2it;
|
||||
}
|
||||
|
||||
template <class SourceIt, class DestinationIt1, class DestinationIt2, class DestinationIt3>
|
||||
inline void operator()(four_way_t, SourceIt srcit, DestinationIt1 dest1it, DestinationIt2 dest2it, DestinationIt3 dest3it)
|
||||
{
|
||||
*dest3it = boost::move(*dest2it);
|
||||
*dest2it = boost::move(*dest1it);
|
||||
*dest1it = boost::move(*srcit);
|
||||
}
|
||||
};
|
||||
|
||||
struct swap_op
|
||||
{
|
||||
template <class SourceIt, class DestinationIt>
|
||||
inline void operator()(SourceIt source, DestinationIt dest)
|
||||
{ boost::adl_move_swap(*dest, *source); }
|
||||
|
||||
template <class SourceIt, class DestinationIt>
|
||||
inline DestinationIt operator()(forward_t, SourceIt first, SourceIt last, DestinationIt dest_begin)
|
||||
{ return boost::adl_move_swap_ranges(first, last, dest_begin); }
|
||||
|
||||
template <class SourceIt, class DestinationIt>
|
||||
inline DestinationIt operator()(backward_t, SourceIt first, SourceIt last, DestinationIt dest_begin)
|
||||
{ return boost::adl_move_swap_ranges_backward(first, last, dest_begin); }
|
||||
|
||||
template <class SourceIt, class DestinationIt1, class DestinationIt2>
|
||||
inline void operator()(three_way_t, SourceIt srcit, DestinationIt1 dest1it, DestinationIt2 dest2it)
|
||||
{
|
||||
typename ::boost::movelib::iterator_traits<SourceIt>::value_type tmp(boost::move(*dest2it));
|
||||
*dest2it = boost::move(*dest1it);
|
||||
*dest1it = boost::move(*srcit);
|
||||
*srcit = boost::move(tmp);
|
||||
}
|
||||
|
||||
template <class SourceIt, class DestinationIt1, class DestinationIt2>
|
||||
DestinationIt2 operator()(three_way_forward_t, SourceIt srcit, SourceIt srcitend, DestinationIt1 dest1it, DestinationIt2 dest2it)
|
||||
{
|
||||
while(srcit != srcitend){
|
||||
this->operator()(three_way_t(), srcit++, dest1it++, dest2it++);
|
||||
}
|
||||
return dest2it;
|
||||
}
|
||||
|
||||
template <class SourceIt, class DestinationIt1, class DestinationIt2, class DestinationIt3>
|
||||
inline void operator()(four_way_t, SourceIt srcit, DestinationIt1 dest1it, DestinationIt2 dest2it, DestinationIt3 dest3it)
|
||||
{
|
||||
typename ::boost::movelib::iterator_traits<SourceIt>::value_type tmp(boost::move(*dest3it));
|
||||
*dest3it = boost::move(*dest2it);
|
||||
*dest2it = boost::move(*dest1it);
|
||||
*dest1it = boost::move(*srcit);
|
||||
*srcit = boost::move(tmp);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}} //namespace boost::movelib
|
||||
|
||||
#endif //BOOST_MOVE_ALGO_BASIC_OP
|
||||
122
include/boost/move/algo/detail/heap_sort.hpp
Normal file
122
include/boost/move/algo/detail/heap_sort.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2017-2018.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/move for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BOOST_MOVE_DETAIL_HEAP_SORT_HPP
|
||||
#define BOOST_MOVE_DETAIL_HEAP_SORT_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/move/detail/config_begin.hpp>
|
||||
|
||||
#include <boost/move/detail/workaround.hpp>
|
||||
#include <boost/move/detail/iterator_traits.hpp>
|
||||
#include <boost/move/algo/detail/is_sorted.hpp>
|
||||
#include <boost/move/utility_core.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{
|
||||
|
||||
template <class RandomAccessIterator, class Compare>
|
||||
class heap_sort_helper
|
||||
{
|
||||
typedef typename boost::movelib::iter_size<RandomAccessIterator>::type size_type;
|
||||
typedef typename boost::movelib::iterator_traits<RandomAccessIterator>::value_type value_type;
|
||||
|
||||
static void adjust_heap(RandomAccessIterator first, size_type hole_index, size_type const len, value_type &value, Compare comp)
|
||||
{
|
||||
size_type const top_index = hole_index;
|
||||
size_type second_child = size_type(2u*(hole_index + 1u));
|
||||
|
||||
while (second_child < len) {
|
||||
if (comp(*(first + second_child), *(first + size_type(second_child - 1u))))
|
||||
second_child--;
|
||||
*(first + hole_index) = boost::move(*(first + second_child));
|
||||
hole_index = second_child;
|
||||
second_child = size_type(2u * (second_child + 1u));
|
||||
}
|
||||
if (second_child == len) {
|
||||
*(first + hole_index) = boost::move(*(first + size_type(second_child - 1u)));
|
||||
hole_index = size_type(second_child - 1);
|
||||
}
|
||||
|
||||
{ //push_heap-like ending
|
||||
size_type parent = size_type((hole_index - 1u) / 2u);
|
||||
while (hole_index > top_index && comp(*(first + parent), value)) {
|
||||
*(first + hole_index) = boost::move(*(first + parent));
|
||||
hole_index = parent;
|
||||
parent = size_type((hole_index - 1u) / 2u);
|
||||
}
|
||||
*(first + hole_index) = boost::move(value);
|
||||
}
|
||||
}
|
||||
|
||||
static void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
|
||||
{
|
||||
size_type const len = size_type(last - first);
|
||||
if (len > 1) {
|
||||
size_type parent = size_type(len/2u - 1u);
|
||||
|
||||
do {
|
||||
value_type v(boost::move(*(first + parent)));
|
||||
adjust_heap(first, parent, len, v, comp);
|
||||
}while (parent--);
|
||||
}
|
||||
}
|
||||
|
||||
static void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
|
||||
{
|
||||
size_type len = size_type(last - first);
|
||||
while (len > 1) {
|
||||
//move biggest to the safe zone
|
||||
--last;
|
||||
value_type v(boost::move(*last));
|
||||
*last = boost::move(*first);
|
||||
adjust_heap(first, size_type(0), --len, v, comp);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
static void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
|
||||
{
|
||||
make_heap(first, last, comp);
|
||||
sort_heap(first, last, comp);
|
||||
assert(boost::movelib::is_sorted(first, last, comp));
|
||||
}
|
||||
};
|
||||
|
||||
template <class RandomAccessIterator, class Compare>
|
||||
inline void heap_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
|
||||
{
|
||||
heap_sort_helper<RandomAccessIterator, Compare>::sort(first, last, comp);
|
||||
}
|
||||
|
||||
}} //namespace boost { namespace movelib{
|
||||
|
||||
#if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <boost/move/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_MOVE_DETAIL_HEAP_SORT_HPP
|
||||
137
include/boost/move/algo/detail/insertion_sort.hpp
Normal file
137
include/boost/move/algo/detail/insertion_sort.hpp
Normal file
@@ -0,0 +1,137 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2014-2014.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/move for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BOOST_MOVE_DETAIL_INSERT_SORT_HPP
|
||||
#define BOOST_MOVE_DETAIL_INSERT_SORT_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/move/utility_core.hpp>
|
||||
#include <boost/move/algo/move.hpp>
|
||||
#include <boost/move/detail/iterator_traits.hpp>
|
||||
#include <boost/move/adl_move_swap.hpp>
|
||||
#include <boost/move/utility_core.hpp>
|
||||
#include <boost/move/detail/placement_new.hpp>
|
||||
#include <boost/move/detail/destruct_n.hpp>
|
||||
#include <boost/move/algo/detail/basic_op.hpp>
|
||||
#include <boost/move/detail/placement_new.hpp>
|
||||
#include <boost/move/detail/iterator_to_raw_pointer.hpp>
|
||||
|
||||
#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{
|
||||
|
||||
// @cond
|
||||
|
||||
template <class Compare, class ForwardIterator, class BirdirectionalIterator, class Op>
|
||||
void insertion_sort_op(ForwardIterator first1, ForwardIterator last1, BirdirectionalIterator first2, Compare comp, Op op)
|
||||
{
|
||||
if (first1 != last1){
|
||||
BirdirectionalIterator last2 = first2;
|
||||
op(first1, last2);
|
||||
for (++last2; ++first1 != last1; ++last2){
|
||||
BirdirectionalIterator j2 = last2;
|
||||
BirdirectionalIterator i2 = j2;
|
||||
if (comp(*first1, *--i2)){
|
||||
op(i2, j2);
|
||||
for (--j2; i2 != first2 && comp(*first1, *--i2); --j2) {
|
||||
op(i2, j2);
|
||||
}
|
||||
}
|
||||
op(first1, j2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Compare, class ForwardIterator, class BirdirectionalIterator>
|
||||
void insertion_sort_swap(ForwardIterator first1, ForwardIterator last1, BirdirectionalIterator first2, Compare comp)
|
||||
{
|
||||
insertion_sort_op(first1, last1, first2, comp, swap_op());
|
||||
}
|
||||
|
||||
|
||||
template <class Compare, class ForwardIterator, class BirdirectionalIterator>
|
||||
void insertion_sort_copy(ForwardIterator first1, ForwardIterator last1, BirdirectionalIterator first2, Compare comp)
|
||||
{
|
||||
insertion_sort_op(first1, last1, first2, comp, move_op());
|
||||
}
|
||||
|
||||
// @endcond
|
||||
|
||||
template <class Compare, class BirdirectionalIterator>
|
||||
void insertion_sort(BirdirectionalIterator first, BirdirectionalIterator last, Compare comp)
|
||||
{
|
||||
typedef typename boost::movelib::iterator_traits<BirdirectionalIterator>::value_type value_type;
|
||||
if (first != last){
|
||||
BirdirectionalIterator i = first;
|
||||
for (++i; i != last; ++i){
|
||||
BirdirectionalIterator j = i;
|
||||
if (comp(*i, *--j)) {
|
||||
value_type tmp(::boost::move(*i));
|
||||
*i = ::boost::move(*j);
|
||||
for (BirdirectionalIterator k = j; k != first && comp(tmp, *--k); --j) {
|
||||
*j = ::boost::move(*k);
|
||||
}
|
||||
*j = ::boost::move(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Compare, class BirdirectionalIterator, class BirdirectionalRawIterator>
|
||||
void insertion_sort_uninitialized_copy
|
||||
(BirdirectionalIterator first1, BirdirectionalIterator const last1
|
||||
, BirdirectionalRawIterator const first2
|
||||
, Compare comp)
|
||||
{
|
||||
typedef typename iterator_traits<BirdirectionalIterator>::value_type value_type;
|
||||
if (first1 != last1){
|
||||
BirdirectionalRawIterator last2 = first2;
|
||||
::new((iterator_to_raw_pointer)(last2), boost_move_new_t()) value_type(::boost::move(*first1));
|
||||
destruct_n<value_type, BirdirectionalRawIterator> d(first2);
|
||||
d.incr();
|
||||
for (++last2; ++first1 != last1; ++last2){
|
||||
BirdirectionalRawIterator j2 = last2;
|
||||
BirdirectionalRawIterator k2 = j2;
|
||||
if (comp(*first1, *--k2)){
|
||||
::new((iterator_to_raw_pointer)(j2), boost_move_new_t()) value_type(::boost::move(*k2));
|
||||
d.incr();
|
||||
for (--j2; k2 != first2 && comp(*first1, *--k2); --j2)
|
||||
*j2 = ::boost::move(*k2);
|
||||
*j2 = ::boost::move(*first1);
|
||||
}
|
||||
else{
|
||||
::new((iterator_to_raw_pointer)(j2), boost_move_new_t()) value_type(::boost::move(*first1));
|
||||
d.incr();
|
||||
}
|
||||
}
|
||||
d.release();
|
||||
}
|
||||
}
|
||||
|
||||
}} //namespace boost { namespace movelib{
|
||||
|
||||
#if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif //#ifndef BOOST_MOVE_DETAIL_INSERT_SORT_HPP
|
||||
55
include/boost/move/algo/detail/is_sorted.hpp
Normal file
55
include/boost/move/algo/detail/is_sorted.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef BOOST_MOVE_DETAIL_IS_SORTED_HPP
|
||||
#define BOOST_MOVE_DETAIL_IS_SORTED_HPP
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2017-2018. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/container for documentation.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace movelib {
|
||||
|
||||
template<class ForwardIt, class Pred>
|
||||
bool is_sorted(ForwardIt const first, ForwardIt last, Pred pred)
|
||||
{
|
||||
if (first != last) {
|
||||
ForwardIt next = first, cur(first);
|
||||
while (++next != last) {
|
||||
if (pred(*next, *cur))
|
||||
return false;
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class ForwardIt, class Pred>
|
||||
bool is_sorted_and_unique(ForwardIt first, ForwardIt last, Pred pred)
|
||||
{
|
||||
if (first != last) {
|
||||
ForwardIt next = first;
|
||||
while (++next != last) {
|
||||
if (!pred(*first, *next))
|
||||
return false;
|
||||
first = next;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} //namespace movelib {
|
||||
} //namespace boost {
|
||||
|
||||
#endif //BOOST_MOVE_DETAIL_IS_SORTED_HPP
|
||||
896
include/boost/move/algo/detail/merge.hpp
Normal file
896
include/boost/move/algo/detail/merge.hpp
Normal file
@@ -0,0 +1,896 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2015-2016.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/move for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef BOOST_MOVE_MERGE_HPP
|
||||
#define BOOST_MOVE_MERGE_HPP
|
||||
|
||||
#include <boost/move/adl_move_swap.hpp>
|
||||
#include <boost/move/algo/detail/basic_op.hpp>
|
||||
#include <boost/move/detail/iterator_traits.hpp>
|
||||
#include <boost/move/detail/destruct_n.hpp>
|
||||
#include <boost/move/algo/predicate.hpp>
|
||||
#include <boost/move/algo/detail/search.hpp>
|
||||
#include <boost/move/detail/iterator_to_raw_pointer.hpp>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
#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 {
|
||||
|
||||
template<class T, class RandRawIt = T*, class SizeType = typename iter_size<RandRawIt>::type>
|
||||
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;
|
||||
typedef SizeType size_type;
|
||||
|
||||
inline adaptive_xbuf()
|
||||
: m_ptr(), m_size(0), m_capacity(0)
|
||||
{}
|
||||
|
||||
inline adaptive_xbuf(RandRawIt raw_memory, size_type cap)
|
||||
: m_ptr(raw_memory), m_size(0), m_capacity(cap)
|
||||
{}
|
||||
|
||||
template<class RandIt>
|
||||
void move_assign(RandIt first, size_type n)
|
||||
{
|
||||
typedef typename iterator_traits<RandIt>::difference_type rand_diff_t;
|
||||
if(n <= m_size){
|
||||
boost::move(first, first+rand_diff_t(n), m_ptr);
|
||||
size_type sz = m_size;
|
||||
while(sz-- != n){
|
||||
m_ptr[sz].~T();
|
||||
}
|
||||
m_size = n;
|
||||
}
|
||||
else{
|
||||
RandRawIt result = boost::move(first, first+rand_diff_t(m_size), m_ptr);
|
||||
boost::uninitialized_move(first+rand_diff_t(m_size), first+rand_diff_t(n), result);
|
||||
m_size = n;
|
||||
}
|
||||
}
|
||||
|
||||
template<class RandIt>
|
||||
void push_back(RandIt first, size_type n)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
inline void set_size(size_type sz)
|
||||
{
|
||||
m_size = sz;
|
||||
}
|
||||
|
||||
void shrink_to_fit(size_type const sz)
|
||||
{
|
||||
if(m_size > sz){
|
||||
for(size_type szt_i = sz; szt_i != m_size; ++szt_i){
|
||||
m_ptr[szt_i].~T();
|
||||
}
|
||||
m_size = sz;
|
||||
}
|
||||
}
|
||||
|
||||
void initialize_until(size_type const sz, T &t)
|
||||
{
|
||||
assert(m_size < m_capacity);
|
||||
if(m_size < sz){
|
||||
BOOST_MOVE_TRY
|
||||
{
|
||||
::new((void*)&m_ptr[m_size]) T(::boost::move(t));
|
||||
++m_size;
|
||||
for(; m_size != sz; ++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_MOVE_CATCH(...)
|
||||
{
|
||||
while(m_size)
|
||||
{
|
||||
--m_size;
|
||||
m_ptr[m_size].~T();
|
||||
}
|
||||
}
|
||||
BOOST_MOVE_CATCH_END
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template<class RIt>
|
||||
inline static bool is_raw_ptr(RIt)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
inline static bool is_raw_ptr(T*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
template<class U>
|
||||
bool supports_aligned_trailing(size_type sz, size_type trail_count) const
|
||||
{
|
||||
if(this->is_raw_ptr(this->data()) && m_capacity){
|
||||
uintptr_t u_addr_sz = uintptr_t(&*(this->data()+sz));
|
||||
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>
|
||||
inline U *aligned_trailing() const
|
||||
{
|
||||
return this->aligned_trailing<U>(this->size());
|
||||
}
|
||||
|
||||
template<class U>
|
||||
inline U *aligned_trailing(size_type 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;
|
||||
}
|
||||
|
||||
inline ~adaptive_xbuf()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
inline size_type capacity() const
|
||||
{ return m_capacity; }
|
||||
|
||||
inline iterator data() const
|
||||
{ return m_ptr; }
|
||||
|
||||
inline iterator begin() const
|
||||
{ return m_ptr; }
|
||||
|
||||
inline iterator end() const
|
||||
{ return m_ptr+m_size; }
|
||||
|
||||
inline size_type size() const
|
||||
{ return m_size; }
|
||||
|
||||
inline bool empty() const
|
||||
{ return !m_size; }
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
this->shrink_to_fit(0u);
|
||||
}
|
||||
|
||||
private:
|
||||
RandRawIt m_ptr;
|
||||
size_type m_size;
|
||||
size_type m_capacity;
|
||||
};
|
||||
|
||||
template<class Iterator, class SizeType, class Op>
|
||||
class range_xbuf
|
||||
{
|
||||
range_xbuf(const range_xbuf &);
|
||||
range_xbuf & operator=(const range_xbuf &);
|
||||
|
||||
public:
|
||||
typedef SizeType 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, size_type n)
|
||||
{
|
||||
assert(size_type(n) <= size_type(m_cap-m_first));
|
||||
typedef typename iter_difference<RandIt>::type d_type;
|
||||
m_last = Op()(forward_t(), first, first+d_type(n), m_first);
|
||||
}
|
||||
|
||||
~range_xbuf()
|
||||
{}
|
||||
|
||||
size_type capacity() const
|
||||
{ return m_cap-m_first; }
|
||||
|
||||
Iterator data() const
|
||||
{ return m_first; }
|
||||
|
||||
Iterator end() const
|
||||
{ return m_last; }
|
||||
|
||||
size_type 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(size_type sz)
|
||||
{
|
||||
m_last = m_first;
|
||||
m_last += sz;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator const m_first;
|
||||
Iterator m_last;
|
||||
Iterator const m_cap;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// @cond
|
||||
|
||||
/*
|
||||
template<typename Unsigned>
|
||||
inline Unsigned gcd(Unsigned x, Unsigned y)
|
||||
{
|
||||
if(0 == ((x &(x-1)) | (y & (y-1)))){
|
||||
return x < y ? x : y;
|
||||
}
|
||||
else{
|
||||
do
|
||||
{
|
||||
Unsigned t = x % y;
|
||||
x = y;
|
||||
y = t;
|
||||
} while (y);
|
||||
return x;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//Modified version from "An Optimal In-Place Array Rotation Algorithm", Ching-Kuang Shene
|
||||
template<typename Unsigned>
|
||||
Unsigned gcd(Unsigned x, Unsigned y)
|
||||
{
|
||||
if(0 == ((x &(x-1)) | (y & (y-1)))){
|
||||
return x < y ? x : y;
|
||||
}
|
||||
else{
|
||||
Unsigned z = 1;
|
||||
while((!(x&1)) & (!(y&1))){
|
||||
z = Unsigned(z << 1);
|
||||
x = Unsigned(x >> 1);
|
||||
y = Unsigned(y >> 1);
|
||||
}
|
||||
while(x && y){
|
||||
if(!(x&1))
|
||||
x = Unsigned(x >> 1);
|
||||
else if(!(y&1))
|
||||
y = Unsigned (y >> 1);
|
||||
else if(x >=y)
|
||||
x = Unsigned((x-y) >> 1u);
|
||||
else
|
||||
y = Unsigned((y-x) >> 1);
|
||||
}
|
||||
return Unsigned(z*(x+y));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RandIt>
|
||||
RandIt rotate_gcd(RandIt first, RandIt middle, RandIt last)
|
||||
{
|
||||
typedef typename iter_size<RandIt>::type size_type;
|
||||
typedef typename iterator_traits<RandIt>::value_type value_type;
|
||||
|
||||
if(first == middle)
|
||||
return last;
|
||||
if(middle == last)
|
||||
return first;
|
||||
const size_type middle_pos = size_type(middle - first);
|
||||
RandIt ret = last - middle_pos;
|
||||
if (middle == ret){
|
||||
boost::adl_move_swap_ranges(first, middle, middle);
|
||||
}
|
||||
else{
|
||||
const size_type length = size_type(last - first);
|
||||
for( RandIt it_i(first), it_gcd(it_i + gcd(length, middle_pos))
|
||||
; it_i != it_gcd
|
||||
; ++it_i){
|
||||
value_type temp(boost::move(*it_i));
|
||||
RandIt it_j = it_i;
|
||||
RandIt it_k = it_j+middle_pos;
|
||||
do{
|
||||
*it_j = boost::move(*it_k);
|
||||
it_j = it_k;
|
||||
size_type const left = size_type(last - it_j);
|
||||
it_k = left > middle_pos ? it_j + middle_pos : first + middle_pos - left;
|
||||
} while(it_k != it_i);
|
||||
*it_j = boost::move(temp);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<class RandIt, class Compare, class Op>
|
||||
void op_merge_left( RandIt buf_first
|
||||
, RandIt first1
|
||||
, RandIt const last1
|
||||
, RandIt const last2
|
||||
, Compare comp
|
||||
, Op op)
|
||||
{
|
||||
for(RandIt first2=last1; first2 != last2; ++buf_first){
|
||||
if(first1 == last1){
|
||||
op(forward_t(), first2, last2, buf_first);
|
||||
return;
|
||||
}
|
||||
else if(comp(*first2, *first1)){
|
||||
op(first2, buf_first);
|
||||
++first2;
|
||||
}
|
||||
else{
|
||||
op(first1, buf_first);
|
||||
++first1;
|
||||
}
|
||||
}
|
||||
if(buf_first != first1){//In case all remaining elements are in the same place
|
||||
//(e.g. buffer is exactly the size of the second half
|
||||
//and all elements from the second half are less)
|
||||
op(forward_t(), first1, last1, buf_first);
|
||||
}
|
||||
}
|
||||
|
||||
// [buf_first, first1) -> buffer
|
||||
// [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
|
||||
// Elements from buffer are moved to [last2 - (first1-buf_first), last2)
|
||||
// Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
|
||||
template<class RandIt, class Compare>
|
||||
void merge_left
|
||||
(RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
|
||||
{
|
||||
op_merge_left(buf_first, first1, last1, last2, comp, move_op());
|
||||
}
|
||||
|
||||
// [buf_first, first1) -> buffer
|
||||
// [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
|
||||
// Elements from buffer are swapped to [last2 - (first1-buf_first), last2)
|
||||
// Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
|
||||
template<class RandIt, class Compare>
|
||||
void swap_merge_left
|
||||
(RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
|
||||
{
|
||||
op_merge_left(buf_first, first1, last1, last2, comp, swap_op());
|
||||
}
|
||||
|
||||
template<class RandIt, class Compare, class Op>
|
||||
void op_merge_right
|
||||
(RandIt const first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp, Op op)
|
||||
{
|
||||
RandIt const first2 = last1;
|
||||
while(first1 != last1){
|
||||
if(last2 == first2){
|
||||
op(backward_t(), first1, last1, buf_last);
|
||||
return;
|
||||
}
|
||||
--last2;
|
||||
--last1;
|
||||
--buf_last;
|
||||
if(comp(*last2, *last1)){
|
||||
op(last1, buf_last);
|
||||
++last2;
|
||||
}
|
||||
else{
|
||||
op(last2, buf_last);
|
||||
++last1;
|
||||
}
|
||||
}
|
||||
if(last2 != buf_last){ //In case all remaining elements are in the same place
|
||||
//(e.g. buffer is exactly the size of the first half
|
||||
//and all elements from the second half are less)
|
||||
op(backward_t(), first2, last2, buf_last);
|
||||
}
|
||||
}
|
||||
|
||||
// [last2, buf_last) - buffer
|
||||
// [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
|
||||
// Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
|
||||
template<class RandIt, class Compare>
|
||||
void merge_right
|
||||
(RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
|
||||
{
|
||||
op_merge_right(first1, last1, last2, buf_last, comp, move_op());
|
||||
}
|
||||
|
||||
// [last2, buf_last) - buffer
|
||||
// [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
|
||||
// Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
|
||||
template<class RandIt, class Compare>
|
||||
void swap_merge_right
|
||||
(RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
|
||||
{
|
||||
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 iter_size<RandIt>::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)
|
||||
{
|
||||
if((middle - first) < (last - middle)){
|
||||
while(first != middle){
|
||||
RandIt const old_last1 = middle;
|
||||
middle = boost::movelib::lower_bound(middle, last, *first, comp);
|
||||
first = rotate_gcd(first, old_last1, middle);
|
||||
if(middle == last){
|
||||
break;
|
||||
}
|
||||
do{
|
||||
++first;
|
||||
} while(first != middle && !comp(*middle, *first));
|
||||
}
|
||||
}
|
||||
else{
|
||||
while(middle != last){
|
||||
RandIt p = boost::movelib::upper_bound(first, middle, last[-1], comp);
|
||||
last = rotate_gcd(p, middle, last);
|
||||
middle = p;
|
||||
if(middle == first){
|
||||
break;
|
||||
}
|
||||
--p;
|
||||
do{
|
||||
--last;
|
||||
} while(middle != last && !comp(last[-1], *p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const std::size_t MergeBufferlessONLogNRotationThreshold = 16u;
|
||||
|
||||
template <class RandIt, class Compare>
|
||||
void merge_bufferless_ONlogN_recursive
|
||||
( RandIt first, RandIt middle, RandIt last
|
||||
, typename iter_size<RandIt>::type len1
|
||||
, typename iter_size<RandIt>::type len2
|
||||
, Compare comp)
|
||||
{
|
||||
typedef typename iter_size<RandIt>::type size_type;
|
||||
|
||||
while(1) {
|
||||
//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;
|
||||
}
|
||||
|
||||
RandIt first_cut = first;
|
||||
RandIt second_cut = middle;
|
||||
size_type len11 = 0;
|
||||
size_type len22 = 0;
|
||||
if (len1 > len2) {
|
||||
len11 = len1 / 2;
|
||||
first_cut += len11;
|
||||
second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
|
||||
len22 = size_type(second_cut - middle);
|
||||
}
|
||||
else {
|
||||
len22 = len2 / 2;
|
||||
second_cut += len22;
|
||||
first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
|
||||
len11 = size_type(first_cut - first);
|
||||
}
|
||||
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 size_type len_internal = size_type(len11+len22);
|
||||
if( len_internal < (len1 + len2 - len_internal) ) {
|
||||
merge_bufferless_ONlogN_recursive(first, first_cut, new_middle, len11, len22, comp);
|
||||
first = new_middle;
|
||||
middle = second_cut;
|
||||
len1 = size_type(len1-len11);
|
||||
len2 = size_type(len2-len22);
|
||||
}
|
||||
else {
|
||||
merge_bufferless_ONlogN_recursive
|
||||
(new_middle, second_cut, last, size_type(len1 - len11), size_type(len2 - len22), comp);
|
||||
middle = first_cut;
|
||||
last = new_middle;
|
||||
len1 = len11;
|
||||
len2 = len22;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Complexity: NlogN
|
||||
template<class RandIt, class Compare>
|
||||
void merge_bufferless_ONlogN(RandIt first, RandIt middle, RandIt last, Compare comp)
|
||||
{
|
||||
typedef typename iter_size<RandIt>::type size_type;
|
||||
merge_bufferless_ONlogN_recursive
|
||||
(first, middle, last, size_type(middle - first), size_type(last - middle), comp);
|
||||
}
|
||||
|
||||
template<class RandIt, class Compare>
|
||||
void merge_bufferless(RandIt first, RandIt middle, RandIt last, Compare comp)
|
||||
{
|
||||
#define BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
|
||||
#ifdef BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
|
||||
merge_bufferless_ONlogN(first, middle, last, comp);
|
||||
#else
|
||||
merge_bufferless_ON2(first, middle, last, comp);
|
||||
#endif //BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
|
||||
}
|
||||
|
||||
// [r_first, r_last) are already in the right part of the destination range.
|
||||
template <class Compare, class InputIterator, class InputOutIterator, class Op>
|
||||
void op_merge_with_right_placed
|
||||
( InputIterator first, InputIterator last
|
||||
, InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
|
||||
, Compare comp, Op op)
|
||||
{
|
||||
assert((last - first) == (r_first - dest_first));
|
||||
while ( first != last ) {
|
||||
if (r_first == r_last) {
|
||||
InputOutIterator end = op(forward_t(), first, last, dest_first);
|
||||
assert(end == r_last);
|
||||
boost::movelib::ignore(end);
|
||||
return;
|
||||
}
|
||||
else if (comp(*r_first, *first)) {
|
||||
op(r_first, dest_first);
|
||||
++r_first;
|
||||
}
|
||||
else {
|
||||
op(first, dest_first);
|
||||
++first;
|
||||
}
|
||||
++dest_first;
|
||||
}
|
||||
// Remaining [r_first, r_last) already in the correct place
|
||||
}
|
||||
|
||||
template <class Compare, class InputIterator, class InputOutIterator>
|
||||
void swap_merge_with_right_placed
|
||||
( InputIterator first, InputIterator last
|
||||
, InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
|
||||
, Compare comp)
|
||||
{
|
||||
op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, swap_op());
|
||||
}
|
||||
|
||||
// [first, last) are already in the right part of the destination range.
|
||||
template <class Compare, class Op, class BidirIterator, class BidirOutIterator>
|
||||
void op_merge_with_left_placed
|
||||
( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
|
||||
, BidirIterator const r_first, BidirIterator r_last
|
||||
, Compare comp, Op op)
|
||||
{
|
||||
assert((dest_last - last) == (r_last - r_first));
|
||||
while( r_first != r_last ) {
|
||||
if(first == last) {
|
||||
BidirOutIterator res = op(backward_t(), r_first, r_last, dest_last);
|
||||
assert(last == res);
|
||||
boost::movelib::ignore(res);
|
||||
return;
|
||||
}
|
||||
--r_last;
|
||||
--last;
|
||||
if(comp(*r_last, *last)){
|
||||
++r_last;
|
||||
--dest_last;
|
||||
op(last, dest_last);
|
||||
}
|
||||
else{
|
||||
++last;
|
||||
--dest_last;
|
||||
op(r_last, dest_last);
|
||||
}
|
||||
}
|
||||
// Remaining [first, last) already in the correct place
|
||||
}
|
||||
|
||||
// @endcond
|
||||
|
||||
// [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
|
||||
, BidirIterator const r_first, BidirIterator r_last
|
||||
, Compare comp)
|
||||
{
|
||||
op_merge_with_left_placed(first, last, dest_last, r_first, r_last, comp, move_op());
|
||||
}
|
||||
|
||||
// [r_first, r_last) are already in the right part of the destination range.
|
||||
template <class Compare, class InputIterator, class InputOutIterator>
|
||||
void merge_with_right_placed
|
||||
( InputIterator first, InputIterator last
|
||||
, InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
|
||||
, Compare comp)
|
||||
{
|
||||
op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, move_op());
|
||||
}
|
||||
|
||||
// [r_first, r_last) are already in the right part of the destination range.
|
||||
// [dest_first, r_first) is uninitialized memory
|
||||
template <class Compare, class InputIterator, class InputOutIterator>
|
||||
void uninitialized_merge_with_right_placed
|
||||
( InputIterator first, InputIterator last
|
||||
, InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
|
||||
, Compare comp)
|
||||
{
|
||||
assert((last - first) == (r_first - dest_first));
|
||||
typedef typename iterator_traits<InputOutIterator>::value_type value_type;
|
||||
InputOutIterator const original_r_first = r_first;
|
||||
|
||||
destruct_n<value_type, InputOutIterator> d(dest_first);
|
||||
|
||||
while ( first != last && dest_first != original_r_first ) {
|
||||
if (r_first == r_last) {
|
||||
for(; dest_first != original_r_first; ++dest_first, ++first){
|
||||
::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
|
||||
d.incr();
|
||||
}
|
||||
d.release();
|
||||
InputOutIterator end = ::boost::move(first, last, original_r_first);
|
||||
assert(end == r_last);
|
||||
boost::movelib::ignore(end);
|
||||
return;
|
||||
}
|
||||
else if (comp(*r_first, *first)) {
|
||||
::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*r_first));
|
||||
d.incr();
|
||||
++r_first;
|
||||
}
|
||||
else {
|
||||
::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
|
||||
d.incr();
|
||||
++first;
|
||||
}
|
||||
++dest_first;
|
||||
}
|
||||
d.release();
|
||||
merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp);
|
||||
}
|
||||
|
||||
/// This is a helper function for the merge routines.
|
||||
template<typename BidirectionalIterator1, typename BidirectionalIterator2>
|
||||
BidirectionalIterator1
|
||||
rotate_adaptive(BidirectionalIterator1 first,
|
||||
BidirectionalIterator1 middle,
|
||||
BidirectionalIterator1 last,
|
||||
typename iter_size<BidirectionalIterator1>::type len1,
|
||||
typename iter_size<BidirectionalIterator1>::type len2,
|
||||
BidirectionalIterator2 buffer,
|
||||
typename iter_size<BidirectionalIterator1>::type buffer_size)
|
||||
{
|
||||
if (len1 > len2 && len2 <= buffer_size)
|
||||
{
|
||||
if(len2) //Protect against self-move ranges
|
||||
{
|
||||
BidirectionalIterator2 buffer_end = boost::move(middle, last, buffer);
|
||||
boost::move_backward(first, middle, last);
|
||||
return boost::move(buffer, buffer_end, first);
|
||||
}
|
||||
else
|
||||
return first;
|
||||
}
|
||||
else if (len1 <= buffer_size)
|
||||
{
|
||||
if(len1) //Protect against self-move ranges
|
||||
{
|
||||
BidirectionalIterator2 buffer_end = boost::move(first, middle, buffer);
|
||||
BidirectionalIterator1 ret = boost::move(middle, last, first);
|
||||
boost::move(buffer, buffer_end, ret);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
return last;
|
||||
}
|
||||
else
|
||||
return rotate_gcd(first, middle, last);
|
||||
}
|
||||
|
||||
template<typename BidirectionalIterator,
|
||||
typename Pointer, typename Compare>
|
||||
void merge_adaptive_ONlogN_recursive
|
||||
(BidirectionalIterator first,
|
||||
BidirectionalIterator middle,
|
||||
BidirectionalIterator last,
|
||||
typename iter_size<BidirectionalIterator>::type len1,
|
||||
typename iter_size<BidirectionalIterator>::type len2,
|
||||
Pointer buffer,
|
||||
typename iter_size<BidirectionalIterator>::type buffer_size,
|
||||
Compare comp)
|
||||
{
|
||||
typedef typename iter_size<BidirectionalIterator>::type size_type;
|
||||
//trivial cases
|
||||
if (!len2 || !len1) {
|
||||
// no-op
|
||||
}
|
||||
else if (len1 <= buffer_size || len2 <= buffer_size) {
|
||||
range_xbuf<Pointer, size_type, move_op> rxbuf(buffer, buffer + buffer_size);
|
||||
buffered_merge(first, middle, last, comp, rxbuf);
|
||||
}
|
||||
else if (size_type(len1 + len2) == 2u) {
|
||||
if (comp(*middle, *first))
|
||||
adl_move_swap(*first, *middle);
|
||||
}
|
||||
else if (size_type(len1 + len2) < MergeBufferlessONLogNRotationThreshold) {
|
||||
merge_bufferless_ON2(first, middle, last, comp);
|
||||
}
|
||||
else {
|
||||
BidirectionalIterator first_cut = first;
|
||||
BidirectionalIterator second_cut = middle;
|
||||
size_type len11 = 0;
|
||||
size_type len22 = 0;
|
||||
if (len1 > len2) //(len1 < len2)
|
||||
{
|
||||
len11 = len1 / 2;
|
||||
first_cut += len11;
|
||||
second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
|
||||
len22 = size_type(second_cut - middle);
|
||||
}
|
||||
else
|
||||
{
|
||||
len22 = len2 / 2;
|
||||
second_cut += len22;
|
||||
first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
|
||||
len11 = size_type(first_cut - first);
|
||||
}
|
||||
|
||||
BidirectionalIterator new_middle
|
||||
= rotate_adaptive(first_cut, middle, second_cut,
|
||||
size_type(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,
|
||||
size_type(len1 - len11), size_type(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,
|
||||
typename iter_size<BidirectionalIterator>::type uninitialized_len)
|
||||
{
|
||||
typedef typename iterator_traits<BidirectionalIterator>::value_type value_type;
|
||||
typedef typename iter_size<BidirectionalIterator>::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 {
|
||||
|
||||
#if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif //#define BOOST_MOVE_MERGE_HPP
|
||||
216
include/boost/move/algo/detail/merge_sort.hpp
Normal file
216
include/boost/move/algo/detail/merge_sort.hpp
Normal file
@@ -0,0 +1,216 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2015-2016.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/move for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BOOST_MOVE_DETAIL_MERGE_SORT_HPP
|
||||
#define BOOST_MOVE_DETAIL_MERGE_SORT_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/move/detail/config_begin.hpp>
|
||||
#include <boost/move/detail/workaround.hpp>
|
||||
|
||||
#include <boost/move/utility_core.hpp>
|
||||
#include <boost/move/algo/move.hpp>
|
||||
#include <boost/move/algo/detail/merge.hpp>
|
||||
#include <boost/move/detail/iterator_traits.hpp>
|
||||
#include <boost/move/adl_move_swap.hpp>
|
||||
#include <boost/move/detail/destruct_n.hpp>
|
||||
#include <boost/move/algo/detail/insertion_sort.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 {
|
||||
|
||||
// @cond
|
||||
|
||||
static const unsigned MergeSortInsertionSortThreshold = 16;
|
||||
|
||||
template <class RandIt, class Compare>
|
||||
void inplace_stable_sort(RandIt first, RandIt last, Compare comp)
|
||||
{
|
||||
typedef typename iter_size<RandIt>::type size_type;
|
||||
if (size_type(last - first) <= size_type(MergeSortInsertionSortThreshold)) {
|
||||
insertion_sort(first, last, comp);
|
||||
return;
|
||||
}
|
||||
RandIt middle = first + (last - first) / 2;
|
||||
inplace_stable_sort(first, middle, comp);
|
||||
inplace_stable_sort(middle, last, comp);
|
||||
merge_bufferless_ONlogN_recursive
|
||||
(first, middle, last, size_type(middle - first), size_type(last - middle), comp);
|
||||
}
|
||||
|
||||
// @endcond
|
||||
|
||||
template<class RandIt, class RandIt2, class Compare>
|
||||
void merge_sort_copy( RandIt first, RandIt last
|
||||
, RandIt2 dest, Compare comp)
|
||||
{
|
||||
typedef typename iter_size<RandIt>::type size_type;
|
||||
|
||||
size_type const count = size_type(last - first);
|
||||
if(count <= MergeSortInsertionSortThreshold){
|
||||
insertion_sort_copy(first, last, dest, comp);
|
||||
}
|
||||
else{
|
||||
size_type const half = size_type(count/2u);
|
||||
merge_sort_copy(first + half, last , dest+half , comp);
|
||||
merge_sort_copy(first , first + half, first + half, comp);
|
||||
merge_with_right_placed
|
||||
( first + half, first + half + half
|
||||
, dest, dest+half, dest + count
|
||||
, comp);
|
||||
}
|
||||
}
|
||||
|
||||
template<class RandIt, class RandItRaw, class Compare>
|
||||
void merge_sort_uninitialized_copy( RandIt first, RandIt last
|
||||
, RandItRaw uninitialized
|
||||
, Compare comp)
|
||||
{
|
||||
typedef typename iter_size<RandIt>::type size_type;
|
||||
typedef typename iterator_traits<RandIt>::value_type value_type;
|
||||
|
||||
size_type const count = size_type(last - first);
|
||||
if(count <= MergeSortInsertionSortThreshold){
|
||||
insertion_sort_uninitialized_copy(first, last, uninitialized, comp);
|
||||
}
|
||||
else{
|
||||
size_type const half = count/2;
|
||||
merge_sort_uninitialized_copy(first + half, last, uninitialized + half, comp);
|
||||
destruct_n<value_type, RandItRaw> d(uninitialized+half);
|
||||
d.incr(size_type(count-half));
|
||||
merge_sort_copy(first, first + half, first + half, comp);
|
||||
uninitialized_merge_with_right_placed
|
||||
( first + half, first + half + half
|
||||
, uninitialized, uninitialized+half, uninitialized+count
|
||||
, comp);
|
||||
d.release();
|
||||
}
|
||||
}
|
||||
|
||||
template<class RandIt, class RandItRaw, class Compare>
|
||||
void merge_sort( RandIt first, RandIt last, Compare comp
|
||||
, RandItRaw uninitialized)
|
||||
{
|
||||
typedef typename iter_size<RandIt>::type size_type;
|
||||
typedef typename iterator_traits<RandIt>::value_type value_type;
|
||||
|
||||
size_type const count = size_type(last - first);
|
||||
if(count <= MergeSortInsertionSortThreshold){
|
||||
insertion_sort(first, last, comp);
|
||||
}
|
||||
else{
|
||||
size_type const half = size_type(count/2u);
|
||||
size_type const rest = size_type(count - half);
|
||||
RandIt const half_it = first + half;
|
||||
RandIt const rest_it = first + rest;
|
||||
|
||||
merge_sort_uninitialized_copy(half_it, last, uninitialized, comp);
|
||||
destruct_n<value_type, RandItRaw> d(uninitialized);
|
||||
d.incr(rest);
|
||||
merge_sort_copy(first, half_it, rest_it, comp);
|
||||
merge_with_right_placed
|
||||
( uninitialized, uninitialized + rest
|
||||
, first, rest_it, last, antistable<Compare>(comp));
|
||||
}
|
||||
}
|
||||
|
||||
///@cond
|
||||
|
||||
template<class RandIt, class RandItRaw, class Compare>
|
||||
void merge_sort_with_constructed_buffer( RandIt first, RandIt last, Compare comp, RandItRaw buffer)
|
||||
{
|
||||
typedef typename iter_size<RandIt>::type size_type;
|
||||
|
||||
size_type const count = size_type(last - first);
|
||||
if(count <= MergeSortInsertionSortThreshold){
|
||||
insertion_sort(first, last, comp);
|
||||
}
|
||||
else{
|
||||
size_type const half = size_type(count/2);
|
||||
size_type const rest = size_type(count - half);
|
||||
RandIt const half_it = first + half;
|
||||
RandIt const rest_it = first + rest;
|
||||
|
||||
merge_sort_copy(half_it, last, buffer, comp);
|
||||
merge_sort_copy(first, half_it, rest_it, comp);
|
||||
merge_with_right_placed
|
||||
(buffer, buffer + rest
|
||||
, first, rest_it, last, antistable<Compare>(comp));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RandIt, typename Pointer,
|
||||
typename Distance, typename Compare>
|
||||
void stable_sort_ONlogN_recursive(RandIt first, RandIt last, Pointer buffer, Distance buffer_size, Compare comp)
|
||||
{
|
||||
typedef typename iter_size<RandIt>::type size_type;
|
||||
if (size_type(last - first) <= size_type(MergeSortInsertionSortThreshold)) {
|
||||
insertion_sort(first, last, comp);
|
||||
}
|
||||
else {
|
||||
const size_type len = size_type(last - first) / 2u;
|
||||
const RandIt middle = first + len;
|
||||
if (len > ((buffer_size+1)/2)){
|
||||
stable_sort_ONlogN_recursive(first, middle, buffer, buffer_size, comp);
|
||||
stable_sort_ONlogN_recursive(middle, last, buffer, buffer_size, comp);
|
||||
}
|
||||
else{
|
||||
merge_sort_with_constructed_buffer(first, middle, comp, buffer);
|
||||
merge_sort_with_constructed_buffer(middle, last, comp, buffer);
|
||||
}
|
||||
merge_adaptive_ONlogN_recursive(first, middle, last,
|
||||
size_type(middle - first),
|
||||
size_type(last - middle),
|
||||
buffer, buffer_size,
|
||||
comp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BidirectionalIterator, typename Compare, typename RandRawIt>
|
||||
void stable_sort_adaptive_ONlogN2(BidirectionalIterator first,
|
||||
BidirectionalIterator last,
|
||||
Compare comp,
|
||||
RandRawIt uninitialized,
|
||||
std::size_t uninitialized_len)
|
||||
{
|
||||
typedef typename iterator_traits<BidirectionalIterator>::value_type value_type;
|
||||
|
||||
::boost::movelib::adaptive_xbuf<value_type, RandRawIt> xbuf(uninitialized, uninitialized_len);
|
||||
xbuf.initialize_until(uninitialized_len, *first);
|
||||
stable_sort_ONlogN_recursive(first, last, uninitialized, uninitialized_len, comp);
|
||||
}
|
||||
|
||||
///@endcond
|
||||
|
||||
}} //namespace boost { namespace movelib{
|
||||
|
||||
#if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <boost/move/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_MOVE_DETAIL_MERGE_SORT_HPP
|
||||
345
include/boost/move/algo/detail/pdqsort.hpp
Normal file
345
include/boost/move/algo/detail/pdqsort.hpp
Normal file
@@ -0,0 +1,345 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Orson Peters 2017.
|
||||
// (C) Copyright Ion Gaztanaga 2017-2018.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/move for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This implementation of Pattern-defeating quicksort (pdqsort) was written
|
||||
// by Orson Peters, and discussed in the Boost mailing list:
|
||||
// http://boost.2283326.n4.nabble.com/sort-pdqsort-td4691031.html
|
||||
//
|
||||
// This implementation is the adaptation by Ion Gaztanaga of code originally in GitHub
|
||||
// with permission from the author to relicense it under the Boost Software License
|
||||
// (see the Boost mailing list for details).
|
||||
//
|
||||
// The original copyright statement is pasted here for completeness:
|
||||
//
|
||||
// pdqsort.h - Pattern-defeating quicksort.
|
||||
// Copyright (c) 2015 Orson Peters
|
||||
// This software is provided 'as-is', without any express or implied warranty. In no event will the
|
||||
// authors be held liable for any damages arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose, including commercial
|
||||
// applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not claim that you wrote the
|
||||
// original software. If you use this software in a product, an acknowledgment in the product
|
||||
// documentation would be appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be misrepresented as
|
||||
// being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_MOVE_ALGO_PDQSORT_HPP
|
||||
#define BOOST_MOVE_ALGO_PDQSORT_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/move/detail/config_begin.hpp>
|
||||
|
||||
#include <boost/move/detail/workaround.hpp>
|
||||
#include <boost/move/utility_core.hpp>
|
||||
#include <boost/move/algo/detail/insertion_sort.hpp>
|
||||
#include <boost/move/algo/detail/heap_sort.hpp>
|
||||
#include <boost/move/detail/iterator_traits.hpp>
|
||||
|
||||
#include <boost/move/adl_move_swap.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
#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 pdqsort_detail {
|
||||
|
||||
//A simple pair implementation to avoid including <utility>
|
||||
template<class T1, class T2>
|
||||
struct pair
|
||||
{
|
||||
pair()
|
||||
{}
|
||||
|
||||
pair(const T1 &t1, const T2 &t2)
|
||||
: first(t1), second(t2)
|
||||
{}
|
||||
|
||||
T1 first;
|
||||
T2 second;
|
||||
};
|
||||
|
||||
enum {
|
||||
// Partitions below this size are sorted using insertion sort.
|
||||
insertion_sort_threshold = 24,
|
||||
|
||||
// Partitions above this size use Tukey's ninther to select the pivot.
|
||||
ninther_threshold = 128,
|
||||
|
||||
// When we detect an already sorted partition, attempt an insertion sort that allows this
|
||||
// amount of element moves before giving up.
|
||||
partial_insertion_sort_limit = 8,
|
||||
|
||||
// Must be multiple of 8 due to loop unrolling, and < 256 to fit in unsigned char.
|
||||
block_size = 64,
|
||||
|
||||
// Cacheline size, assumes power of two.
|
||||
cacheline_size = 64
|
||||
|
||||
};
|
||||
|
||||
// Returns floor(log2(n)), assumes n > 0.
|
||||
template<class Unsigned>
|
||||
Unsigned log2(Unsigned n) {
|
||||
Unsigned log = 0;
|
||||
while (n >>= 1) ++log;
|
||||
return log;
|
||||
}
|
||||
|
||||
// Attempts to use insertion sort on [begin, end). Will return false if more than
|
||||
// partial_insertion_sort_limit elements were moved, and abort sorting. Otherwise it will
|
||||
// successfully sort and return true.
|
||||
template<class Iter, class Compare>
|
||||
inline bool partial_insertion_sort(Iter begin, Iter end, Compare comp) {
|
||||
typedef typename boost::movelib::iterator_traits<Iter>::value_type T;
|
||||
typedef typename boost::movelib:: iter_size<Iter>::type size_type;
|
||||
if (begin == end) return true;
|
||||
|
||||
size_type limit = 0;
|
||||
for (Iter cur = begin + 1; cur != end; ++cur) {
|
||||
if (limit > partial_insertion_sort_limit) return false;
|
||||
|
||||
Iter sift = cur;
|
||||
Iter sift_1 = cur - 1;
|
||||
|
||||
// Compare first so we can avoid 2 moves for an element already positioned correctly.
|
||||
if (comp(*sift, *sift_1)) {
|
||||
T tmp = boost::move(*sift);
|
||||
|
||||
do { *sift-- = boost::move(*sift_1); }
|
||||
while (sift != begin && comp(tmp, *--sift_1));
|
||||
|
||||
*sift = boost::move(tmp);
|
||||
limit += size_type(cur - sift);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Iter, class Compare>
|
||||
inline void sort2(Iter a, Iter b, Compare comp) {
|
||||
if (comp(*b, *a)) boost::adl_move_iter_swap(a, b);
|
||||
}
|
||||
|
||||
// Sorts the elements *a, *b and *c using comparison function comp.
|
||||
template<class Iter, class Compare>
|
||||
inline void sort3(Iter a, Iter b, Iter c, Compare comp) {
|
||||
sort2(a, b, comp);
|
||||
sort2(b, c, comp);
|
||||
sort2(a, b, comp);
|
||||
}
|
||||
|
||||
// Partitions [begin, end) around pivot *begin using comparison function comp. Elements equal
|
||||
// to the pivot are put in the right-hand partition. Returns the position of the pivot after
|
||||
// partitioning and whether the passed sequence already was correctly partitioned. Assumes the
|
||||
// pivot is a median of at least 3 elements and that [begin, end) is at least
|
||||
// insertion_sort_threshold long.
|
||||
template<class Iter, class Compare>
|
||||
pdqsort_detail::pair<Iter, bool> partition_right(Iter begin, Iter end, Compare comp) {
|
||||
typedef typename boost::movelib::iterator_traits<Iter>::value_type T;
|
||||
|
||||
// Move pivot into local for speed.
|
||||
T pivot(boost::move(*begin));
|
||||
|
||||
Iter first = begin;
|
||||
Iter last = end;
|
||||
|
||||
// Find the first element greater than or equal than the pivot (the median of 3 guarantees
|
||||
// this exists).
|
||||
while (comp(*++first, pivot));
|
||||
|
||||
// Find the first element strictly smaller than the pivot. We have to guard this search if
|
||||
// there was no element before *first.
|
||||
if (first - 1 == begin) while (first < last && !comp(*--last, pivot));
|
||||
else while ( !comp(*--last, pivot));
|
||||
|
||||
// If the first pair of elements that should be swapped to partition are the same element,
|
||||
// the passed in sequence already was correctly partitioned.
|
||||
bool already_partitioned = first >= last;
|
||||
|
||||
// Keep swapping pairs of elements that are on the wrong side of the pivot. Previously
|
||||
// swapped pairs guard the searches, which is why the first iteration is special-cased
|
||||
// above.
|
||||
while (first < last) {
|
||||
boost::adl_move_iter_swap(first, last);
|
||||
while (comp(*++first, pivot));
|
||||
while (!comp(*--last, pivot));
|
||||
}
|
||||
|
||||
// Put the pivot in the right place.
|
||||
Iter pivot_pos = first - 1;
|
||||
if(begin != pivot_pos) //Avoid potential self-move
|
||||
*begin = boost::move(*pivot_pos);
|
||||
*pivot_pos = boost::move(pivot);
|
||||
|
||||
return pdqsort_detail::pair<Iter, bool>(pivot_pos, already_partitioned);
|
||||
}
|
||||
|
||||
// Similar function to the one above, except elements equal to the pivot are put to the left of
|
||||
// the pivot and it doesn't check or return if the passed sequence already was partitioned.
|
||||
// Since this is rarely used (the many equal case), and in that case pdqsort already has O(n)
|
||||
// performance, no block quicksort is applied here for simplicity.
|
||||
template<class Iter, class Compare>
|
||||
inline Iter partition_left(Iter begin, Iter end, Compare comp) {
|
||||
typedef typename boost::movelib::iterator_traits<Iter>::value_type T;
|
||||
|
||||
T pivot(boost::move(*begin));
|
||||
Iter first = begin;
|
||||
Iter last = end;
|
||||
|
||||
while (comp(pivot, *--last));
|
||||
|
||||
if (last + 1 == end) while (first < last && !comp(pivot, *++first));
|
||||
else while ( !comp(pivot, *++first));
|
||||
|
||||
while (first < last) {
|
||||
boost::adl_move_iter_swap(first, last);
|
||||
while (comp(pivot, *--last));
|
||||
while (!comp(pivot, *++first));
|
||||
}
|
||||
|
||||
Iter pivot_pos = last;
|
||||
*begin = boost::move(*pivot_pos);
|
||||
*pivot_pos = boost::move(pivot);
|
||||
|
||||
return pivot_pos;
|
||||
}
|
||||
|
||||
|
||||
template<class Iter, class Compare>
|
||||
void pdqsort_loop( Iter begin, Iter end, Compare comp
|
||||
, typename boost::movelib:: iter_size<Iter>::type bad_allowed
|
||||
, bool leftmost = true)
|
||||
{
|
||||
typedef typename boost::movelib:: iter_size<Iter>::type size_type;
|
||||
|
||||
// Use a while loop for tail recursion elimination.
|
||||
while (true) {
|
||||
size_type size = size_type(end - begin);
|
||||
|
||||
// Insertion sort is faster for small arrays.
|
||||
if (size < insertion_sort_threshold) {
|
||||
insertion_sort(begin, end, comp);
|
||||
return;
|
||||
}
|
||||
|
||||
// Choose pivot as median of 3 or pseudomedian of 9.
|
||||
size_type s2 = size / 2;
|
||||
if (size > ninther_threshold) {
|
||||
sort3(begin, begin + s2, end - 1, comp);
|
||||
sort3(begin + 1, begin + (s2 - 1), end - 2, comp);
|
||||
sort3(begin + 2, begin + (s2 + 1), end - 3, comp);
|
||||
sort3(begin + (s2 - 1), begin + s2, begin + (s2 + 1), comp);
|
||||
boost::adl_move_iter_swap(begin, begin + s2);
|
||||
} else sort3(begin + s2, begin, end - 1, comp);
|
||||
|
||||
// If *(begin - 1) is the end of the right partition of a previous partition operation
|
||||
// there is no element in [begin, end) that is smaller than *(begin - 1). Then if our
|
||||
// pivot compares equal to *(begin - 1) we change strategy, putting equal elements in
|
||||
// the left partition, greater elements in the right partition. We do not have to
|
||||
// recurse on the left partition, since it's sorted (all equal).
|
||||
if (!leftmost && !comp(*(begin - 1), *begin)) {
|
||||
begin = partition_left(begin, end, comp) + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Partition and get results.
|
||||
pdqsort_detail::pair<Iter, bool> part_result = partition_right(begin, end, comp);
|
||||
Iter pivot_pos = part_result.first;
|
||||
bool already_partitioned = part_result.second;
|
||||
|
||||
// Check for a highly unbalanced partition.
|
||||
size_type l_size = size_type(pivot_pos - begin);
|
||||
size_type r_size = size_type(end - (pivot_pos + 1));
|
||||
bool highly_unbalanced = l_size < size / 8 || r_size < size / 8;
|
||||
|
||||
// If we got a highly unbalanced partition we shuffle elements to break many patterns.
|
||||
if (highly_unbalanced) {
|
||||
// If we had too many bad partitions, switch to heapsort to guarantee O(n log n).
|
||||
if (--bad_allowed == 0) {
|
||||
boost::movelib::heap_sort(begin, end, comp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (l_size >= insertion_sort_threshold) {
|
||||
boost::adl_move_iter_swap(begin, begin + l_size / 4);
|
||||
boost::adl_move_iter_swap(pivot_pos - 1, pivot_pos - l_size / 4);
|
||||
|
||||
if (l_size > ninther_threshold) {
|
||||
boost::adl_move_iter_swap(begin + 1, begin + (l_size / 4 + 1));
|
||||
boost::adl_move_iter_swap(begin + 2, begin + (l_size / 4 + 2));
|
||||
boost::adl_move_iter_swap(pivot_pos - 2, pivot_pos - (l_size / 4 + 1));
|
||||
boost::adl_move_iter_swap(pivot_pos - 3, pivot_pos - (l_size / 4 + 2));
|
||||
}
|
||||
}
|
||||
|
||||
if (r_size >= insertion_sort_threshold) {
|
||||
boost::adl_move_iter_swap(pivot_pos + 1, pivot_pos + (1 + r_size / 4));
|
||||
boost::adl_move_iter_swap(end - 1, end - r_size / 4);
|
||||
|
||||
if (r_size > ninther_threshold) {
|
||||
boost::adl_move_iter_swap(pivot_pos + 2, pivot_pos + (2 + r_size / 4));
|
||||
boost::adl_move_iter_swap(pivot_pos + 3, pivot_pos + (3 + r_size / 4));
|
||||
boost::adl_move_iter_swap(end - 2, end - (1 + r_size / 4));
|
||||
boost::adl_move_iter_swap(end - 3, end - (2 + r_size / 4));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If we were decently balanced and we tried to sort an already partitioned
|
||||
// sequence try to use insertion sort.
|
||||
if (already_partitioned && partial_insertion_sort(begin, pivot_pos, comp)
|
||||
&& partial_insertion_sort(pivot_pos + 1, end, comp)) return;
|
||||
}
|
||||
|
||||
// Sort the left partition first using recursion and do tail recursion elimination for
|
||||
// the right-hand partition.
|
||||
pdqsort_loop<Iter, Compare>(begin, pivot_pos, comp, bad_allowed, leftmost);
|
||||
begin = pivot_pos + 1;
|
||||
leftmost = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class Iter, class Compare>
|
||||
void pdqsort(Iter begin, Iter end, Compare comp)
|
||||
{
|
||||
if (begin == end) return;
|
||||
typedef typename boost::movelib:: iter_size<Iter>::type size_type;
|
||||
pdqsort_detail::pdqsort_loop<Iter, Compare>(begin, end, comp, pdqsort_detail::log2(size_type(end - begin)));
|
||||
}
|
||||
|
||||
} //namespace movelib {
|
||||
} //namespace boost {
|
||||
|
||||
#if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <boost/move/detail/config_end.hpp>
|
||||
|
||||
#endif //BOOST_MOVE_ALGO_PDQSORT_HPP
|
||||
79
include/boost/move/algo/detail/search.hpp
Normal file
79
include/boost/move/algo/detail/search.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2022-2022.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/move for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef BOOST_MOVE_DETAIL_SEARCH_HPP
|
||||
#define BOOST_MOVE_DETAIL_SEARCH_HPP
|
||||
|
||||
#include <boost/move/detail/iterator_traits.hpp>
|
||||
|
||||
#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 {
|
||||
|
||||
template <class RandIt, class T, class Compare>
|
||||
RandIt lower_bound
|
||||
(RandIt first, const RandIt last, const T& key, Compare comp)
|
||||
{
|
||||
typedef typename iter_size<RandIt>::type size_type;
|
||||
size_type len = size_type(last - first);
|
||||
RandIt middle;
|
||||
|
||||
while (len) {
|
||||
size_type step = size_type(len >> 1);
|
||||
middle = first;
|
||||
middle += step;
|
||||
|
||||
if (comp(*middle, key)) {
|
||||
first = ++middle;
|
||||
len = size_type(len - (step + 1));
|
||||
}
|
||||
else{
|
||||
len = step;
|
||||
}
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
template <class RandIt, class T, class Compare>
|
||||
RandIt upper_bound
|
||||
(RandIt first, const RandIt last, const T& key, Compare comp)
|
||||
{
|
||||
typedef typename iter_size<RandIt>::type size_type;
|
||||
size_type len = size_type(last - first);
|
||||
RandIt middle;
|
||||
|
||||
while (len) {
|
||||
size_type step = size_type(len >> 1);
|
||||
middle = first;
|
||||
middle += step;
|
||||
|
||||
if (!comp(key, *middle)) {
|
||||
first = ++middle;
|
||||
len = size_type(len - (step + 1));
|
||||
}
|
||||
else{
|
||||
len = step;
|
||||
}
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
} //namespace movelib {
|
||||
} //namespace boost {
|
||||
|
||||
#if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif //#define BOOST_MOVE_DETAIL_SEARCH_HPP
|
||||
213
include/boost/move/algo/detail/set_difference.hpp
Normal file
213
include/boost/move/algo/detail/set_difference.hpp
Normal file
@@ -0,0 +1,213 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2017-2017.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/move for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef BOOST_MOVE_SET_DIFFERENCE_HPP
|
||||
#define BOOST_MOVE_SET_DIFFERENCE_HPP
|
||||
|
||||
#include <boost/move/algo/move.hpp>
|
||||
#include <boost/move/iterator.hpp>
|
||||
#include <boost/move/utility_core.hpp>
|
||||
|
||||
#if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace move_detail{
|
||||
|
||||
template<class InputIt, class OutputIt>
|
||||
OutputIt copy(InputIt first, InputIt last, OutputIt result)
|
||||
{
|
||||
while (first != last) {
|
||||
*result++ = *first;
|
||||
++result;
|
||||
++first;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} //namespace move_detail{
|
||||
|
||||
namespace movelib {
|
||||
|
||||
//Moves the elements from the sorted range [first1, last1) which are not found in the sorted
|
||||
//range [first2, last2) to the range beginning at result.
|
||||
//The resulting range is also sorted. Equivalent elements are treated individually,
|
||||
//that is, if some element is found m times in [first1, last1) and n times in [first2, last2),
|
||||
//it will be moved to result exactly max(m-n, 0) times.
|
||||
//The resulting range cannot overlap with either of the input ranges.
|
||||
template<class InputIt1, class InputIt2,
|
||||
class OutputIt, class Compare>
|
||||
OutputIt set_difference
|
||||
(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt result, Compare comp)
|
||||
{
|
||||
while (first1 != last1) {
|
||||
if (first2 == last2)
|
||||
return boost::move_detail::copy(first1, last1, result);
|
||||
|
||||
if (comp(*first1, *first2)) {
|
||||
*result = *first1;
|
||||
++result;
|
||||
++first1;
|
||||
}
|
||||
else {
|
||||
if (!comp(*first2, *first1)) {
|
||||
++first1;
|
||||
}
|
||||
++first2;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//Moves the elements from the sorted range [first1, last1) which are not found in the sorted
|
||||
//range [first2, last2) to the range beginning at first1 (in place operation in range1).
|
||||
//The resulting range is also sorted. Equivalent elements are treated individually,
|
||||
//that is, if some element is found m times in [first1, last1) and n times in [first2, last2),
|
||||
//it will be moved to result exactly max(m-n, 0) times.
|
||||
template<class InputOutputIt1, class InputIt2, class Compare>
|
||||
InputOutputIt1 inplace_set_difference
|
||||
(InputOutputIt1 first1, InputOutputIt1 last1, InputIt2 first2, InputIt2 last2, Compare comp )
|
||||
{
|
||||
while (first1 != last1) {
|
||||
//Skip copying from range 1 if no element has to be skipped
|
||||
if (first2 == last2){
|
||||
return last1;
|
||||
}
|
||||
else if (comp(*first1, *first2)){
|
||||
++first1;
|
||||
}
|
||||
else{
|
||||
if (!comp(*first2, *first1)) {
|
||||
InputOutputIt1 result = first1;
|
||||
//An element from range 1 must be skipped, no longer an inplace operation
|
||||
return boost::movelib::set_difference
|
||||
( boost::make_move_iterator(++first1)
|
||||
, boost::make_move_iterator(last1)
|
||||
, ++first2, last2, result, comp);
|
||||
}
|
||||
++first2;
|
||||
}
|
||||
}
|
||||
return first1;
|
||||
}
|
||||
|
||||
//Moves the elements from the sorted range [first1, last1) which are not found in the sorted
|
||||
//range [first2, last2) to the range beginning at first1.
|
||||
//The resulting range is also sorted. Equivalent elements from range 1 are moved past to end
|
||||
//of the result,
|
||||
//that is, if some element is found m times in [first1, last1) and n times in [first2, last2),
|
||||
//it will be moved to result exactly max(m-n, 0) times.
|
||||
//The resulting range cannot overlap with either of the input ranges.
|
||||
template<class ForwardIt1, class InputIt2,
|
||||
class OutputIt, class Compare>
|
||||
OutputIt set_unique_difference
|
||||
(ForwardIt1 first1, ForwardIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt result, Compare comp)
|
||||
{
|
||||
while (first1 != last1) {
|
||||
if (first2 == last2){
|
||||
//unique_copy-like sequence with forward iterators but don't write i
|
||||
//to result before comparing as moving *i could alter the value in i.
|
||||
ForwardIt1 i = first1;
|
||||
while (++first1 != last1) {
|
||||
if (comp(*i, *first1)) {
|
||||
*result = *i;
|
||||
++result;
|
||||
i = first1;
|
||||
}
|
||||
}
|
||||
*result = *i;
|
||||
++result;
|
||||
break;
|
||||
}
|
||||
|
||||
if (comp(*first1, *first2)) {
|
||||
//Skip equivalent elements in range1 but don't write i
|
||||
//to result before comparing as moving *i could alter the value in i.
|
||||
ForwardIt1 i = first1;
|
||||
while (++first1 != last1) {
|
||||
if (comp(*i, *first1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*result = *i;
|
||||
++result;
|
||||
}
|
||||
else {
|
||||
if (comp(*first2, *first1)) {
|
||||
++first2;
|
||||
}
|
||||
else{
|
||||
++first1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//Moves the elements from the sorted range [first1, last1) which are not found in the sorted
|
||||
//range [first2, last2) to the range beginning at first1 (in place operation in range1).
|
||||
//The resulting range is also sorted. Equivalent elements are treated individually,
|
||||
//that is, if some element is found m times in [first1, last1) and n times in [first2, last2),
|
||||
//it will be moved to result exactly max(m-n, 0) times.
|
||||
template<class ForwardOutputIt1, class ForwardIt2, class Compare>
|
||||
ForwardOutputIt1 inplace_set_unique_difference
|
||||
(ForwardOutputIt1 first1, ForwardOutputIt1 last1, ForwardIt2 first2, ForwardIt2 last2, Compare comp )
|
||||
{
|
||||
while (first1 != last1) {
|
||||
//Skip copying from range 1 if no element has to be skipped
|
||||
if (first2 == last2){
|
||||
//unique-like algorithm for the remaining range 1
|
||||
ForwardOutputIt1 result = first1;
|
||||
while (++first1 != last1) {
|
||||
if (comp(*result, *first1) && ++result != first1) {
|
||||
*result = boost::move(*first1);
|
||||
}
|
||||
}
|
||||
return ++result;
|
||||
}
|
||||
else if (comp(*first2, *first1)) {
|
||||
++first2;
|
||||
}
|
||||
else if (comp(*first1, *first2)){
|
||||
//skip any adjacent equivalent element in range 1
|
||||
ForwardOutputIt1 result = first1;
|
||||
if (++first1 != last1 && !comp(*result, *first1)) {
|
||||
//Some elements from range 1 must be skipped, no longer an inplace operation
|
||||
while (++first1 != last1 && !comp(*result, *first1)){}
|
||||
return boost::movelib::set_unique_difference
|
||||
( boost::make_move_iterator(first1)
|
||||
, boost::make_move_iterator(last1)
|
||||
, first2, last2, ++result, comp);
|
||||
}
|
||||
}
|
||||
else{
|
||||
ForwardOutputIt1 result = first1;
|
||||
//Some elements from range 1 must be skipped, no longer an inplace operation
|
||||
while (++first1 != last1 && !comp(*result, *first1)){}
|
||||
//An element from range 1 must be skipped, no longer an inplace operation
|
||||
return boost::movelib::set_unique_difference
|
||||
( boost::make_move_iterator(first1)
|
||||
, boost::make_move_iterator(last1)
|
||||
, first2, last2, result, comp);
|
||||
}
|
||||
}
|
||||
return first1;
|
||||
}
|
||||
|
||||
#if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
} //namespace movelib {
|
||||
} //namespace boost {
|
||||
|
||||
#endif //#define BOOST_MOVE_SET_DIFFERENCE_HPP
|
||||
Reference in New Issue
Block a user