Add experimental adaptive_merge/sort functions

This commit is contained in:
Ion Gaztañaga
2016-02-23 13:17:12 +01:00
parent 01e40f00b0
commit d5981c52a9
24 changed files with 4573 additions and 127 deletions

View File

@ -14,6 +14,7 @@ import quickbook ;
doxygen autodoc
:
[ glob ../../../boost/move/*.hpp ]
[ glob ../../../boost/move/algo/*.hpp ]
:
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
<doxygen:param>HIDE_UNDOC_MEMBERS=YES

View File

@ -762,6 +762,13 @@ Many thanks to all boosters that have tested, reviewed and improved the library.
[section:release_notes Release Notes]
[section:release_notes_boost_1_61 Boost 1.61 Release]
* Experimental: asymptotically optimal bufferless merge and sort algorithms: [funcref boost::movelib::adaptive_merge adaptive_merge]
and [funcref boost::movelib::adaptive_sort adaptive_sort].
[endsect]
[section:release_notes_boost_1_60 Boost 1.60 Release]
* Fixed bug:
@ -771,11 +778,11 @@ Many thanks to all boosters that have tested, reviewed and improved the library.
[section:release_notes_boost_1_59 Boost 1.59 Release]
* Changed `unique_ptr`'s converting constructor taking the source by value in C++03 compilers to allow simple conversions
from convertible types returned by value.
* Fixed bug:
* [@https://svn.boost.org/trac/boost/ticket/11229 Trac #11229: ['"vector incorrectly copies move-only objects using memcpy"]],
* [@https://svn.boost.org/trac/boost/ticket/11510 Trac #11510: ['"unique_ptr: -Wshadow warning issued"]],
* Changed `unique_ptr`'s converting constructor taking the source by value in C++03 compilers to allow simple conversions
from convertible types returned by value.
* Fixed bug:
* [@https://svn.boost.org/trac/boost/ticket/11229 Trac #11229: ['"vector incorrectly copies move-only objects using memcpy"]],
* [@https://svn.boost.org/trac/boost/ticket/11510 Trac #11510: ['"unique_ptr: -Wshadow warning issued"]],
[endsect]

View File

@ -227,6 +227,40 @@ BOOST_MOVE_FORCEINLINE void adl_move_swap(T& x, T& y)
::boost_move_adl_swap::swap_proxy(x, y);
}
//! Exchanges elements between range [first1, last1) and another range starting at first2
//! using boost::adl_move_swap.
//!
//! Parameters:
//! first1, last1 - the first range of elements to swap
//! first2 - beginning of the second range of elements to swap
//!
//! Type requirements:
//! - ForwardIt1, ForwardIt2 must meet the requirements of ForwardIterator.
//! - The types of dereferenced ForwardIt1 and ForwardIt2 must meet the
//! requirements of Swappable
//!
//! Return value: Iterator to the element past the last element exchanged in the range
//! beginning with first2.
template<class ForwardIt1, class ForwardIt2>
ForwardIt2 adl_move_swap_ranges(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2)
{
while (first1 != last1) {
::boost::adl_move_swap(*first1, *first2);
++first1;
++first2;
}
return first2;
}
template<class BidirIt1, class BidirIt2>
BidirIt2 adl_move_swap_ranges_backward(BidirIt1 first1, BidirIt1 last1, BidirIt2 last2)
{
while (first1 != last1) {
::boost::adl_move_swap(*(--last1), *(--last2));
}
return last2;
}
} //namespace boost{
#endif //#ifndef BOOST_MOVE_ADL_MOVE_SWAP_HPP

View File

@ -0,0 +1,67 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_ADAPTIVE_MERGE_HPP
#define BOOST_MOVE_ADAPTIVE_MERGE_HPP
#include <boost/move/detail/config_begin.hpp>
#include <boost/move/algo/detail/adaptive_sort_merge.hpp>
namespace boost {
namespace movelib {
//! <b>Effects</b>: Merges two consecutive sorted ranges [first, middle) and [middle, last)
//! into one sorted range [first, last) according to the given comparison function comp.
//! The algorithm is stable (if there are equivalent elements in the original two ranges,
//! the elements from the first range (preserving their original order) precede the elements
//! from the second range (preserving their original order).
//!
//! <b>Requires</b>:
//! - RandIt must meet the requirements of ValueSwappable and RandomAccessIterator.
//! - The type of dereferenced RandIt must meet the requirements of MoveAssignable and MoveConstructible.
//!
//! <b>Parameters</b>:
//! - first: the beginning of the first sorted range.
//! - middle: the end of the first sorted range and the beginning of the second
//! - last: the end of the second sorted range
//! - comp: comparison function object which returns true if the first argument is is ordered before the second.
//! - uninitialized, uninitialized_len: raw storage starting on "uninitialized", able to hold "uninitialized_len"
//! elements of type iterator_traits<RandIt>::value_type. Maximum performance is achieved when uninitialized_len
//! is min(std::distance(first, middle), std::distance(middle, last)).
//!
//! <b>Throws</b>: If comp throws or the move constructor, move assignment or swap of the type
//! of dereferenced RandIt throws.
//!
//! <b>Complexity</b>: Always K x O(N) comparisons and move assignments/constructors/swaps.
//! Constant factor for comparisons and data movement is minimized when uninitialized_len
//! is min(std::distance(first, middle), std::distance(middle, last)).
//! Pretty good enough performance is achieved when uninitialized_len is
//! ceil(sqrt(std::distance(first, last)))*2.
//!
//! <b>Caution</b>: Experimental implementation, not production-ready.
template<class RandIt, class Compare>
void adaptive_merge( RandIt first, RandIt middle, RandIt last, Compare comp
, typename iterator_traits<RandIt>::value_type* uninitialized = 0
, std::size_t uninitialized_len = 0)
{
typedef typename iterator_traits<RandIt>::size_type size_type;
typedef typename iterator_traits<RandIt>::value_type value_type;
::boost::movelib::detail_adaptive::adaptive_xbuf<value_type> xbuf(uninitialized, uninitialized_len);
::boost::movelib::detail_adaptive::adaptive_merge_impl(first, size_type(middle - first), size_type(last - middle), comp, xbuf);
}
} //namespace movelib {
} //namespace boost {
#include <boost/move/detail/config_end.hpp>
#endif //#define BOOST_MOVE_ADAPTIVE_MERGE_HPP

View File

@ -0,0 +1,63 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_ADAPTIVE_SORT_HPP
#define BOOST_MOVE_ADAPTIVE_SORT_HPP
#include <boost/move/detail/config_begin.hpp>
#include <boost/move/algo/detail/adaptive_sort_merge.hpp>
namespace boost {
namespace movelib {
//! <b>Effects</b>: Sorts the elements in the range [first, last) in ascending order according
//! to comparison functor "comp". The sort is stable (order of equal elements
//! is guaranteed to be preserved). Performance is improved if additional raw storage is
//! provided.
//!
//! <b>Requires</b>:
//! - RandIt must meet the requirements of ValueSwappable and RandomAccessIterator.
//! - The type of dereferenced RandIt must meet the requirements of MoveAssignable and MoveConstructible.
//!
//! <b>Parameters</b>:
//! - first, last: the range of elements to sort
//! - comp: comparison function object which returns true if the first argument is is ordered before the second.
//! - uninitialized, uninitialized_len: raw storage starting on "uninitialized", able to hold "uninitialized_len"
//! elements of type iterator_traits<RandIt>::value_type. Maximum performance is achieved when uninitialized_len
//! is ceil(std::distance(first, last)/2).
//!
//! <b>Throws</b>: If comp throws or the move constructor, move assignment or swap of the type
//! of dereferenced RandIt throws.
//!
//! <b>Complexity</b>: Always K x O(Nxlog(N)) comparisons and move assignments/constructors/swaps.
//! Comparisons are close to minimum even with no additional memory. Constant factor for data movement is minimized
//! when uninitialized_len is ceil(std::distance(first, last)/2). Pretty good enough performance is achieved when
//! ceil(sqrt(std::distance(first, last)))*2.
//!
//! <b>Caution</b>: Experimental implementation, not production-ready.
template<class RandIt, class Compare>
void adaptive_sort( RandIt first, RandIt last, Compare comp
, typename iterator_traits<RandIt>::value_type* uninitialized = 0
, std::size_t uninitialized_len = 0)
{
typedef typename iterator_traits<RandIt>::size_type size_type;
typedef typename iterator_traits<RandIt>::value_type value_type;
::boost::movelib::detail_adaptive::adaptive_xbuf<value_type> xbuf(uninitialized, uninitialized_len);
::boost::movelib::detail_adaptive::adaptive_sort_impl(first, size_type(last - first), comp, xbuf);
}
} //namespace movelib {
} //namespace boost {
#include <boost/move/detail/config_end.hpp>
#endif //#define BOOST_MOVE_ADAPTIVE_SORT_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,63 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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>
namespace boost {
namespace movelib {
struct forward_t{};
struct backward_t{};
struct move_op
{
template <class SourceIt, class DestinationIt>
void operator()(SourceIt source, DestinationIt dest)
{ *dest = ::boost::move(*source); }
template <class SourceIt, class DestinationIt>
DestinationIt operator()(forward_t, SourceIt first, SourceIt last, DestinationIt dest_begin)
{ return ::boost::move(first, last, dest_begin); }
template <class SourceIt, class DestinationIt>
DestinationIt operator()(backward_t, SourceIt first, SourceIt last, DestinationIt dest_last)
{ return ::boost::move_backward(first, last, dest_last); }
};
struct swap_op
{
template <class SourceIt, class DestinationIt>
void operator()(SourceIt source, DestinationIt dest)
{ boost::adl_move_swap(*dest, *source); }
template <class SourceIt, class DestinationIt>
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>
DestinationIt operator()(backward_t, SourceIt first, SourceIt last, DestinationIt dest_begin)
{ return boost::adl_move_swap_ranges_backward(first, last, dest_begin); }
};
}} //namespace boost::movelib
#endif //BOOST_MOVE_ALGO_BASIC_OP

View File

@ -0,0 +1,120 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_ALGO_BUFFERLESS_MERGE_SORT_HPP
#define BOOST_MOVE_ALGO_BUFFERLESS_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/adl_move_swap.hpp>
#include <boost/move/algo/move.hpp>
#include <boost/move/algo/detail/merge.hpp>
#include <boost/move/detail/iterator_traits.hpp>
#include <boost/move/algo/detail/insertion_sort.hpp>
#include <cassert>
namespace boost {
namespace movelib {
// @cond
namespace detail_bufferless_mergesort {
static const std::size_t UnbufferedMergeSortInsertionSortThreshold = 16;
//A in-placed version based on:
//Jyrki Katajainen, Tomi Pasanen, Jukka Teuhola.
//``Practical in-place mergesort''. Nordic Journal of Computing, 1996.
template<class RandIt, class Compare>
void bufferless_merge_sort(RandIt first, RandIt last, Compare comp);
template<class RandIt, class Compare>
void swap_sort(RandIt const first, RandIt const last, RandIt const buffer_first, RandIt const buffer_last, Compare comp, bool buffer_at_right)
{
typedef typename iterator_traits<RandIt>::size_type size_type;
if (size_type(last - first) > UnbufferedMergeSortInsertionSortThreshold) {
RandIt m = first + (last - first) / 2;
bufferless_merge_sort(first, m, comp);
bufferless_merge_sort(m, last, comp);
if(buffer_at_right){
//Use antistable to minimize movements (if equal, move first half elements
//to maximize the chance last half elements are already in place.
boost::movelib::swap_merge_right(first, m, last, buffer_last, boost::movelib::antistable<Compare>(comp));
}
else{
boost::movelib::swap_merge_left(buffer_first, first, m, last, comp);
}
}
else
boost::movelib::insertion_sort_swap(first, last, buffer_first, comp);
}
template<class RandIt, class Compare>
void bufferless_merge_sort(RandIt const first, RandIt const last, Compare comp)
{
typedef typename iterator_traits<RandIt>::size_type size_type;
size_type len = size_type(last - first);
if (len > size_type(UnbufferedMergeSortInsertionSortThreshold)) {
len /= 2;
RandIt h = last - len; //ceil(half)
RandIt f = h - len; //ceil(first)
swap_sort(f, h, h, last, comp, true); //[h, last) contains sorted elements
//Divide unsorted first half in two
len = size_type(h - first);
while (len > size_type(UnbufferedMergeSortInsertionSortThreshold)) {
len /= 2;
RandIt n = h; //new end
h = n - len; //ceil(half')
f = h - len; //ceil(first')
swap_sort(h, n, f, h, comp, false); // the first half of the previous working area [f, h)
//contains sorted elements: working area in the middle [h, n)
//Now merge small (left) sorted with big (right) sorted (buffer is between them)
swap_merge_with_right_placed(f, h, h, n, last, comp);
}
boost::movelib::insertion_sort(first, h, comp);
boost::movelib::merge_bufferless(first, h, last, comp);
}
else{
boost::movelib::insertion_sort(first, last, comp);
}
}
} //namespace detail_bufferless_mergesort {
// @endcond
//Unstable bufferless merge sort
template<class RandIt, class Compare>
void bufferless_merge_sort(RandIt first, RandIt last, Compare comp)
{
detail_bufferless_mergesort::bufferless_merge_sort(first, last, comp);
}
}} //namespace boost::movelib
#include <boost/move/detail/config_end.hpp>
#endif //#ifndef BOOST_MOVE_ALGO_BUFFERLESS_MERGE_SORT_HPP

View File

@ -0,0 +1,127 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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>
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>
void insertion_sort_uninitialized_copy
(BirdirectionalIterator first1, BirdirectionalIterator const last1
, typename iterator_traits<BirdirectionalIterator>::value_type* const first2
, Compare comp)
{
typedef typename iterator_traits<BirdirectionalIterator>::value_type value_type;
if (first1 != last1){
value_type* last2 = first2;
::new(last2, boost_move_new_t()) value_type(move(*first1));
destruct_n<value_type> d(first2);
d.incr();
for (++last2; ++first1 != last1; ++last2){
value_type* j2 = last2;
value_type* k2 = j2;
if (comp(*first1, *--k2)){
::new(j2, boost_move_new_t()) value_type(move(*k2));
d.incr();
for (--j2; k2 != first2 && comp(*first1, *--k2); --j2)
*j2 = move(*k2);
*j2 = move(*first1);
}
else{
::new(j2, boost_move_new_t()) value_type(move(*first1));
d.incr();
}
}
d.release();
}
}
}} //namespace boost { namespace movelib{
#endif //#ifndef BOOST_MOVE_DETAIL_INSERT_SORT_HPP

View File

@ -0,0 +1,444 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/algo/move.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/assert.hpp>
namespace boost {
namespace movelib {
// @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 <<=1, x>>=1, y>>=1;
}
while(x && y){
if(!(x&1))
x >>=1;
else if(!(y&1))
y >>=1;
else if(x >=y)
x = (x-y) >> 1;
else
y = (y-x) >> 1;
}
return z*(x+y);
}
}
template<typename RandIt>
RandIt rotate_gcd(RandIt first, RandIt middle, RandIt last)
{
typedef typename iterator_traits<RandIt>::size_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 T, class Compare>
RandIt lower_bound
(RandIt first, const RandIt last, const T& key, Compare comp)
{
typedef typename iterator_traits
<RandIt>::size_type size_type;
size_type len = size_type(last - first);
RandIt middle;
while (len) {
size_type step = len >> 1;
middle = first;
middle += step;
if (comp(*middle, key)) {
first = ++middle;
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 iterator_traits
<RandIt>::size_type size_type;
size_type len = size_type(last - first);
RandIt middle;
while (len) {
size_type step = len >> 1;
middle = first;
middle += step;
if (!comp(key, *middle)) {
first = ++middle;
len -= step + 1;
}
else{
len = step;
}
}
return first;
}
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);
}
else{
buf_first = 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());
}
// cost: min(L1,L2)^2+max(L1,L2)
template<class RandIt, class Compare>
void merge_bufferless(RandIt first, RandIt middle, RandIt last, Compare comp)
{
if((middle - first) < (last - middle)){
while(first != middle){
RandIt const old_last1 = middle;
middle = 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 = 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));
}
}
}
template<class Comp>
struct antistable
{
antistable(Comp &comp)
: m_comp(comp)
{}
template<class U, class V>
bool operator()(const U &u, const V & v)
{ return !m_comp(v, u); }
private:
antistable & operator=(const antistable &);
Comp &m_comp;
};
// [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)
{
BOOST_ASSERT((last - first) == (r_first - dest_first));
while ( first != last ) {
if (r_first == r_last) {
InputOutIterator end = op(forward_t(), first, last, dest_first);
BOOST_ASSERT(end == r_last);
(void)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());
}
// [r_first, r_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)
{
BOOST_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);
BOOST_ASSERT(last == res);
(void)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
// [r_first, r_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)
{
BOOST_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> 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(&*dest_first) value_type(::boost::move(*first));
d.incr();
}
d.release();
InputOutIterator end = ::boost::move(first, last, original_r_first);
BOOST_ASSERT(end == r_last);
(void)end;
return;
}
else if (comp(*r_first, *first)) {
::new(&*dest_first) value_type(::boost::move(*r_first));
d.incr();
++r_first;
}
else {
::new(&*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);
}
} //namespace movelib {
} //namespace boost {
#endif //#define BOOST_MOVE_MERGE_HPP

View File

@ -0,0 +1,124 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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>
namespace boost {
namespace movelib {
// @cond
static const unsigned MergeSortInsertionSortThreshold = 16;
// @endcond
template<class RandIt, class RandIt2, class Compare>
void merge_sort_copy( RandIt first, RandIt last
, RandIt2 dest, Compare comp)
{
typedef typename iterator_traits<RandIt>::size_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 = count/2;
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 Compare>
void merge_sort_uninitialized_copy( RandIt first, RandIt last
, typename iterator_traits<RandIt>::value_type* uninitialized
, Compare comp)
{
typedef typename iterator_traits<RandIt>::size_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> d(uninitialized+half);
d.incr(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 Compare>
void merge_sort( RandIt first, RandIt last, Compare comp
, typename iterator_traits<RandIt>::value_type* uninitialized)
{
typedef typename iterator_traits<RandIt>::size_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 = count/2;
size_type const rest = 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> 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));
}
}
}} //namespace boost { namespace movelib{
#include <boost/move/detail/config_end.hpp>
#endif //#ifndef BOOST_MOVE_DETAIL_MERGE_SORT_HPP

View File

@ -0,0 +1,155 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2012-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_ALGO_MOVE_HPP
#define BOOST_MOVE_ALGO_MOVE_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/utility_core.hpp>
#include <boost/move/detail/iterator_traits.hpp>
#include <boost/detail/no_exceptions_support.hpp>
namespace boost {
//////////////////////////////////////////////////////////////////////////////
//
// move
//
//////////////////////////////////////////////////////////////////////////////
#if !defined(BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE)
//! <b>Effects</b>: Moves elements in the range [first,last) into the range [result,result + (last -
//! first)) starting from first and proceeding to last. For each non-negative integer n < (last-first),
//! performs *(result + n) = ::boost::move (*(first + n)).
//!
//! <b>Effects</b>: result + (last - first).
//!
//! <b>Requires</b>: result shall not be in the range [first,last).
//!
//! <b>Complexity</b>: Exactly last - first move assignments.
template <typename I, // I models InputIterator
typename O> // O models OutputIterator
O move(I f, I l, O result)
{
while (f != l) {
*result = ::boost::move(*f);
++f; ++result;
}
return result;
}
//////////////////////////////////////////////////////////////////////////////
//
// move_backward
//
//////////////////////////////////////////////////////////////////////////////
//! <b>Effects</b>: Moves elements in the range [first,last) into the range
//! [result - (last-first),result) starting from last - 1 and proceeding to
//! first. For each positive integer n <= (last - first),
//! performs *(result - n) = ::boost::move(*(last - n)).
//!
//! <b>Requires</b>: result shall not be in the range [first,last).
//!
//! <b>Returns</b>: result - (last - first).
//!
//! <b>Complexity</b>: Exactly last - first assignments.
template <typename I, // I models BidirectionalIterator
typename O> // O models BidirectionalIterator
O move_backward(I f, I l, O result)
{
while (f != l) {
--l; --result;
*result = ::boost::move(*l);
}
return result;
}
#else
using ::std::move_backward;
#endif //!defined(BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE)
//////////////////////////////////////////////////////////////////////////////
//
// uninitialized_move
//
//////////////////////////////////////////////////////////////////////////////
//! <b>Effects</b>:
//! \code
//! for (; first != last; ++result, ++first)
//! new (static_cast<void*>(&*result))
//! typename iterator_traits<ForwardIterator>::value_type(boost::move(*first));
//! \endcode
//!
//! <b>Returns</b>: result
template
<typename I, // I models InputIterator
typename F> // F models ForwardIterator
F uninitialized_move(I f, I l, F r
/// @cond
// ,typename ::boost::move_detail::enable_if<has_move_emulation_enabled<typename boost::movelib::iterator_traits<I>::value_type> >::type* = 0
/// @endcond
)
{
typedef typename boost::movelib::iterator_traits<I>::value_type input_value_type;
F back = r;
BOOST_TRY{
while (f != l) {
void * const addr = static_cast<void*>(::boost::move_detail::addressof(*r));
::new(addr) input_value_type(::boost::move(*f));
++f; ++r;
}
}
BOOST_CATCH(...){
for (; back != r; ++back){
back->~input_value_type();
}
BOOST_RETHROW;
}
BOOST_CATCH_END
return r;
}
/// @cond
/*
template
<typename I, // I models InputIterator
typename F> // F models ForwardIterator
F uninitialized_move(I f, I l, F r,
typename ::boost::move_detail::disable_if<has_move_emulation_enabled<typename boost::movelib::iterator_traits<I>::value_type> >::type* = 0)
{
return std::uninitialized_copy(f, l, r);
}
*/
/// @endcond
} //namespace boost {
#include <boost/move/detail/config_end.hpp>
#endif //#ifndef BOOST_MOVE_ALGO_MOVE_HPP

View File

@ -26,6 +26,7 @@
#include <boost/move/utility_core.hpp>
#include <boost/move/iterator.hpp>
#include <boost/move/algo/move.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <algorithm> //copy, copy_backward
@ -33,122 +34,6 @@
namespace boost {
//////////////////////////////////////////////////////////////////////////////
//
// move
//
//////////////////////////////////////////////////////////////////////////////
#if !defined(BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE)
//! <b>Effects</b>: Moves elements in the range [first,last) into the range [result,result + (last -
//! first)) starting from first and proceeding to last. For each non-negative integer n < (last-first),
//! performs *(result + n) = ::boost::move (*(first + n)).
//!
//! <b>Effects</b>: result + (last - first).
//!
//! <b>Requires</b>: result shall not be in the range [first,last).
//!
//! <b>Complexity</b>: Exactly last - first move assignments.
template <typename I, // I models InputIterator
typename O> // O models OutputIterator
O move(I f, I l, O result)
{
while (f != l) {
*result = ::boost::move(*f);
++f; ++result;
}
return result;
}
//////////////////////////////////////////////////////////////////////////////
//
// move_backward
//
//////////////////////////////////////////////////////////////////////////////
//! <b>Effects</b>: Moves elements in the range [first,last) into the range
//! [result - (last-first),result) starting from last - 1 and proceeding to
//! first. For each positive integer n <= (last - first),
//! performs *(result - n) = ::boost::move(*(last - n)).
//!
//! <b>Requires</b>: result shall not be in the range [first,last).
//!
//! <b>Returns</b>: result - (last - first).
//!
//! <b>Complexity</b>: Exactly last - first assignments.
template <typename I, // I models BidirectionalIterator
typename O> // O models BidirectionalIterator
O move_backward(I f, I l, O result)
{
while (f != l) {
--l; --result;
*result = ::boost::move(*l);
}
return result;
}
#else
using ::std::move_backward;
#endif //!defined(BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE)
//////////////////////////////////////////////////////////////////////////////
//
// uninitialized_move
//
//////////////////////////////////////////////////////////////////////////////
//! <b>Effects</b>:
//! \code
//! for (; first != last; ++result, ++first)
//! new (static_cast<void*>(&*result))
//! typename iterator_traits<ForwardIterator>::value_type(boost::move(*first));
//! \endcode
//!
//! <b>Returns</b>: result
template
<typename I, // I models InputIterator
typename F> // F models ForwardIterator
F uninitialized_move(I f, I l, F r
/// @cond
// ,typename ::boost::move_detail::enable_if<has_move_emulation_enabled<typename std::iterator_traits<I>::value_type> >::type* = 0
/// @endcond
)
{
typedef typename std::iterator_traits<I>::value_type input_value_type;
F back = r;
BOOST_TRY{
while (f != l) {
void * const addr = static_cast<void*>(::boost::move_detail::addressof(*r));
::new(addr) input_value_type(::boost::move(*f));
++f; ++r;
}
}
BOOST_CATCH(...){
for (; back != r; ++back){
back->~input_value_type();
}
BOOST_RETHROW;
}
BOOST_CATCH_END
return r;
}
/// @cond
/*
template
<typename I, // I models InputIterator
typename F> // F models ForwardIterator
F uninitialized_move(I f, I l, F r,
typename ::boost::move_detail::disable_if<has_move_emulation_enabled<typename std::iterator_traits<I>::value_type> >::type* = 0)
{
return std::uninitialized_copy(f, l, r);
}
*/
//////////////////////////////////////////////////////////////////////////////
//
// uninitialized_copy_or_move

View File

@ -17,4 +17,5 @@
# pragma warning (disable : 4675) // "function": resolved overload was found by argument-dependent lookup
# pragma warning (disable : 4996) // "function": was declared deprecated (_CRT_SECURE_NO_DEPRECATE/_SCL_SECURE_NO_WARNINGS)
# pragma warning (disable : 4714) // "function": marked as __forceinline not inlined
# pragma warning (disable : 4127) // conditional expression is constant
#endif

View File

@ -0,0 +1,67 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_DESTRUCT_N_HPP
#define BOOST_MOVE_DETAIL_DESTRUCT_N_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <cstddef>
namespace boost {
namespace movelib{
template<class T>
class destruct_n
{
public:
explicit destruct_n(T *raw)
: m_ptr(raw), m_size()
{}
void incr()
{
++m_size;
}
void incr(std::size_t n)
{
m_size += n;
}
void release()
{
m_size = 0u;
m_ptr = 0;
}
~destruct_n()
{
while(m_size--){
m_ptr[m_size].~T();
}
}
private:
T *m_ptr;
std::size_t m_size;
};
}} //namespace boost { namespace movelib{
#endif //#ifndef BOOST_MOVE_DETAIL_DESTRUCT_N_HPP

View File

@ -23,6 +23,7 @@
#endif
#include <cstddef>
#include <boost/move/detail/type_traits.hpp>
#include <boost/move/detail/std_ns_begin.hpp>
BOOST_MOVE_STD_NS_BEG
@ -46,6 +47,7 @@ struct iterator_traits
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
typedef typename Iterator::iterator_category iterator_category;
typedef typename boost::move_detail::make_unsigned<difference_type>::type size_type;
};
template<class T>
@ -56,6 +58,7 @@ struct iterator_traits<T*>
typedef T* pointer;
typedef T& reference;
typedef std::random_access_iterator_tag iterator_category;
typedef typename boost::move_detail::make_unsigned<difference_type>::type size_type;
};
template<class T>
@ -66,6 +69,7 @@ struct iterator_traits<const T*>
typedef const T* pointer;
typedef const T& reference;
typedef std::random_access_iterator_tag iterator_category;
typedef typename boost::move_detail::make_unsigned<difference_type>::type size_type;
};
}} //namespace boost { namespace movelib{

View File

@ -0,0 +1,30 @@
#ifndef BOOST_MOVE_DETAIL_PLACEMENT_NEW_HPP
#define BOOST_MOVE_DETAIL_PLACEMENT_NEW_HPP
///////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2014-2015. 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
struct boost_move_new_t{};
//avoid including <new>
inline void *operator new(std::size_t, void *p, boost_move_new_t)
{ return p; }
inline void operator delete(void *, void *, boost_move_new_t)
{}
#endif //BOOST_MOVE_DETAIL_PLACEMENT_NEW_HPP

View File

@ -111,6 +111,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "type_traits", "type_traits.
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_sort", "bench_sort.vcproj", "{CD2617A8-6217-9EB7-24CE-6C9AA035376A}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_merge", "bench_merge.vcproj", "{CD2617A8-6217-9EB7-24CE-6C9AA035376A}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
@ -231,25 +239,45 @@ Global
{D7C28A23-8621-FE05-BF87-3C7B6176BD02}.Debug.Build.0 = Debug|Win32
{D7C28A23-8621-FE05-BF87-3C7B6176BD02}.Release.ActiveCfg = Release|Win32
{D7C28A23-8621-FE05-BF87-3C7B6176BD02}.Release.Build.0 = Release|Win32
{CD2617A8-6217-9EB7-24CE-6C9AA035376A}.Debug.ActiveCfg = Debug|Win32
{CD2617A8-6217-9EB7-24CE-6C9AA035376A}.Debug.Build.0 = Debug|Win32
{CD2617A8-6217-9EB7-24CE-6C9AA035376A}.Release.ActiveCfg = Release|Win32
{CD2617A8-6217-9EB7-24CE-6C9AA035376A}.Release.Build.0 = Release|Win32
{CD2617A8-6217-9EB7-24CE-6C9AA035376A}.Debug.ActiveCfg = Debug|Win32
{CD2617A8-6217-9EB7-24CE-6C9AA035376A}.Debug.Build.0 = Debug|Win32
{CD2617A8-6217-9EB7-24CE-6C9AA035376A}.Release.ActiveCfg = Release|Win32
{CD2617A8-6217-9EB7-24CE-6C9AA035376A}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionItems) = postSolution
..\..\..\..\boost\move\algo\adaptive_merge.hpp = ..\..\..\..\boost\move\algo\adaptive_merge.hpp
..\..\..\..\boost\move\algo\adaptive_sort.hpp = ..\..\..\..\boost\move\algo\adaptive_sort.hpp
..\..\..\..\boost\move\algo\detail\adaptive_sort_merge.hpp = ..\..\..\..\boost\move\algo\detail\adaptive_sort_merge.hpp
..\..\..\..\boost\move\adl_move_swap.hpp = ..\..\..\..\boost\move\adl_move_swap.hpp
..\..\..\..\boost\move\algorithm.hpp = ..\..\..\..\boost\move\algorithm.hpp
..\..\..\..\boost\move\algo\basic_op.hpp = ..\..\..\..\boost\move\algo\basic_op.hpp
..\..\..\..\boost\move\algo\bufferless_merge_sort.hpp = ..\..\..\..\boost\move\algo\bufferless_merge_sort.hpp
..\..\..\..\boost\move\detail\config_begin.hpp = ..\..\..\..\boost\move\detail\config_begin.hpp
..\..\..\..\boost\move\detail\config_end.hpp = ..\..\..\..\boost\move\detail\config_end.hpp
..\..\..\..\boost\move\core.hpp = ..\..\..\..\boost\move\core.hpp
..\..\..\..\boost\move\default_delete.hpp = ..\..\..\..\boost\move\default_delete.hpp
..\..\..\..\boost\move\detail\destruct_n.hpp = ..\..\..\..\boost\move\detail\destruct_n.hpp
..\..\..\..\boost\move\detail\fwd_macros.hpp = ..\..\..\..\boost\move\detail\fwd_macros.hpp
..\..\..\..\boost\move\algo\insertion_sort.hpp = ..\..\..\..\boost\move\algo\insertion_sort.hpp
..\..\..\..\boost\move\iterator.hpp = ..\..\..\..\boost\move\iterator.hpp
..\..\..\..\boost\move\detail\iterator_traits.hpp = ..\..\..\..\boost\move\detail\iterator_traits.hpp
..\..\doc\Jamfile.v2 = ..\..\doc\Jamfile.v2
..\..\..\..\boost\move\make_unique.hpp = ..\..\..\..\boost\move\make_unique.hpp
..\..\..\..\boost\move\algo\merge.hpp = ..\..\..\..\boost\move\algo\merge.hpp
..\..\..\..\boost\move\algo\merge_sort.hpp = ..\..\..\..\boost\move\algo\merge_sort.hpp
..\..\..\..\boost\move\detail\meta_utils.hpp = ..\..\..\..\boost\move\detail\meta_utils.hpp
..\..\..\..\boost\move\detail\meta_utils_core.hpp = ..\..\..\..\boost\move\detail\meta_utils_core.hpp
..\..\..\..\boost\move\move.hpp = ..\..\..\..\boost\move\move.hpp
..\..\..\..\boost\move\algo\move.hpp = ..\..\..\..\boost\move\algo\move.hpp
..\..\doc\move.qbk = ..\..\doc\move.qbk
..\..\..\..\boost\move\detail\move_helpers.hpp = ..\..\..\..\boost\move\detail\move_helpers.hpp
..\..\..\..\boost\move\detail\placement_new.hpp = ..\..\..\..\boost\move\detail\placement_new.hpp
..\..\..\..\boost\move\detail\std_ns_begin.hpp = ..\..\..\..\boost\move\detail\std_ns_begin.hpp
..\..\..\..\boost\move\detail\std_ns_end.hpp = ..\..\..\..\boost\move\detail\std_ns_end.hpp
..\..\..\..\boost\move\traits.hpp = ..\..\..\..\boost\move\traits.hpp
..\..\..\..\boost\move\detail\type_traits.hpp = ..\..\..\..\boost\move\detail\type_traits.hpp
..\..\..\..\boost\move\unique_ptr.hpp = ..\..\..\..\boost\move\unique_ptr.hpp

View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="bench_merge"
ProjectGUID="{CD2617A8-6217-9EB7-24CE-6C9AA035376A}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="../../Bin/Win32/Debug"
IntermediateDirectory="Debug/bench_merge"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../../.."
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
DisableLanguageExtensions="FALSE"
TreatWChar_tAsBuiltInType="TRUE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="winmm.lib"
OutputFile="$(OutDir)/bench_merge_d.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../../stage/lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/bench_merge.pdb"
SubSystem="1"
TargetMachine="1"
FixedBaseAddress="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="../../Bin/Win32/Release"
IntermediateDirectory="Release/bench_merge"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../../../.."
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB"
RuntimeLibrary="2"
TreatWChar_tAsBuiltInType="TRUE"
ForceConformanceInForLoopScope="FALSE"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="winmm.lib"
OutputFile="$(OutDir)/bench_merge.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../../stage/lib"
GenerateDebugInformation="TRUE"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{1D875633-A605-0546-5C56-3A5FEAD72B0A}">
<File
RelativePath="..\..\test\bench_merge.cpp">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="bench_sort"
ProjectGUID="{CD2617A8-6217-9EB7-24CE-6C9AA035376A}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="../../Bin/Win32/Debug"
IntermediateDirectory="Debug/bench_sort"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../../.."
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
DisableLanguageExtensions="FALSE"
TreatWChar_tAsBuiltInType="TRUE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="winmm.lib"
OutputFile="$(OutDir)/bench_sort_d.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../../stage/lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/bench_sort.pdb"
SubSystem="1"
TargetMachine="1"
FixedBaseAddress="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="../../Bin/Win32/Release"
IntermediateDirectory="Release/bench_sort"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../../../.."
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB"
RuntimeLibrary="2"
TreatWChar_tAsBuiltInType="TRUE"
ForceConformanceInForLoopScope="FALSE"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="winmm.lib"
OutputFile="$(OutDir)/bench_sort.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../../stage/lib"
GenerateDebugInformation="TRUE"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{1D875633-A605-0546-5C56-3A5FEAD72B0A}">
<File
RelativePath="..\..\test\bench_sort.cpp">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -128,11 +128,6 @@
RelativePath="..\..\test\move.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93A78280-B78D-4B31-7E8B-6255ACE1E5FB}">
</Filter>
</Files>
<Globals>
</Globals>

View File

@ -12,7 +12,7 @@ rule test_all
for local fileb in [ glob *.cpp ]
{
all_rules += [ run $(fileb)
all_rules += [ run $(fileb) /boost/timer//boost_timer
: # additional args
: # test-files
: # requirements

328
test/bench_merge.cpp Normal file
View File

@ -0,0 +1,328 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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.
//
//////////////////////////////////////////////////////////////////////////////
#include <algorithm> //std::inplace_merge
#include <cstdio> //std::printf
#include <iostream> //std::cout
#include <boost/config.hpp>
#include <boost/move/unique_ptr.hpp>
#include <boost/timer/timer.hpp>
using boost::timer::cpu_timer;
using boost::timer::cpu_times;
using boost::timer::nanosecond_type;
boost::ulong_long_type num_copy;
boost::ulong_long_type num_elements;
struct merged_type
{
public:
std::size_t key;
std::size_t val;
merged_type()
{
++num_elements;
}
merged_type(const merged_type& other)
: key(other.key), val(other.val)
{
++num_elements;
++num_copy;
}
merged_type & operator=(const merged_type& other)
{
++num_copy;
key = other.key;
val = other.val;
return *this;
}
~merged_type ()
{
--num_elements;
}
};
boost::ulong_long_type num_compare;
//#define BOOST_MOVE_ADAPTIVE_SORT_STATS
void print_stats(const char *str, boost::ulong_long_type element_count)
{
std::printf("%sCmp:%8.04f Cpy:%9.04f\n", str, double(num_compare)/element_count, double(num_copy)/element_count );
}
template<class T>
struct counted_less
{
bool operator()(const T &a,T const &b) const
{ ++num_compare; return a.key < b.key; }
};
#include <boost/move/algo/adaptive_merge.hpp>
#include <boost/move/algo/detail/merge.hpp>
#include <boost/move/core.hpp>
template<class T, class Compare>
std::size_t generate_elements(T elements[], std::size_t element_count, std::size_t key_reps[], std::size_t key_len, Compare comp)
{
std::srand(0);
for(std::size_t i = 0; i < (key_len ? key_len : element_count); ++i){
key_reps[i]=0;
}
for(std::size_t i=0; i < element_count; ++i){
std::size_t key = key_len ? (i % key_len) : i;
elements[i].key=key;
}
std::random_shuffle(elements, elements + element_count);
std::random_shuffle(elements, elements + element_count);
std::random_shuffle(elements, elements + element_count);
for(std::size_t i = 0; i < element_count; ++i){
elements[i].val = key_reps[elements[i].key]++;
}
std::size_t split_count = element_count/2;
std::stable_sort(elements, elements+split_count, comp);
std::stable_sort(elements+split_count, elements+element_count, comp);
return split_count;
}
template<class T>
bool test_order(T *elements, std::size_t element_count, bool stable = true)
{
for(std::size_t i = 1; i < element_count; ++i){
if(counted_less<T>()(elements[i], elements[i-1])){
std::printf("\n Ord KO !!!!");
return false;
}
if( stable && !(counted_less<T>()(elements[i-1], elements[i])) && (elements[i-1].val > elements[i].val) ){
std::printf("\n Stb KO !!!! ");
return false;
}
}
return true;
}
template<class T, class Compare>
void adaptive_merge_buffered(T *elements, T *mid, T *last, Compare comp, std::size_t BufLen)
{
boost::movelib::unique_ptr<char[]> mem(new char[sizeof(T)*BufLen]);
boost::movelib::adaptive_merge(elements, mid, last, comp, reinterpret_cast<T*>(mem.get()), BufLen);
}
enum AlgoType
{
InplaceMerge,
AdaptiveMerge,
SqrtHAdaptiveMerge,
SqrtAdaptiveMerge,
Sqrt2AdaptiveMerge,
QuartAdaptiveMerge,
BuflessMerge,
MaxMerge
};
const char *AlgoNames [] = { "InplaceMerge "
, "AdaptMerge "
, "SqrtHAdaptMerge "
, "SqrtAdaptMerge "
, "Sqrt2AdaptMerge "
, "QuartAdaptMerge "
, "BuflessMerge "
};
BOOST_STATIC_ASSERT((sizeof(AlgoNames)/sizeof(*AlgoNames)) == MaxMerge);
template<class T>
bool measure_algo(T *elements, std::size_t key_reps[], std::size_t element_count, std::size_t key_len, unsigned alg, nanosecond_type &prev_clock)
{
std::size_t const split_pos = generate_elements(elements, element_count, key_reps, key_len, counted_less<T>());
std::printf("%s ", AlgoNames[alg]);
num_compare=0;
num_copy=0;
num_elements = element_count;
cpu_timer timer;
timer.resume();
switch(alg)
{
case InplaceMerge:
std::inplace_merge(elements, elements+split_pos, elements+element_count, counted_less<T>());
break;
case AdaptiveMerge:
boost::movelib::adaptive_merge(elements, elements+split_pos, elements+element_count, counted_less<T>());
break;
case SqrtHAdaptiveMerge:
adaptive_merge_buffered( elements, elements+split_pos, elements+element_count, counted_less<T>()
, boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count)/2+1);
break;
case SqrtAdaptiveMerge:
adaptive_merge_buffered( elements, elements+split_pos, elements+element_count, counted_less<T>()
, boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count));
break;
case Sqrt2AdaptiveMerge:
adaptive_merge_buffered( elements, elements+split_pos, elements+element_count, counted_less<T>()
, 2*boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count));
break;
case QuartAdaptiveMerge:
adaptive_merge_buffered( elements, elements+split_pos, elements+element_count, counted_less<T>()
, (element_count-1)/4+1);
break;
case BuflessMerge:
boost::movelib::merge_bufferless(elements, elements+split_pos, elements+element_count, counted_less<T>());
break;
}
timer.stop();
if(num_elements == element_count){
std::printf(" Tmp Ok ");
} else{
std::printf(" Tmp KO ");
}
nanosecond_type new_clock = timer.elapsed().wall;
//std::cout << "Cmp:" << num_compare << " Cpy:" << num_copy; //for old compilers without ll size argument
std::printf("Cmp:%8.04f Cpy:%9.04f", double(num_compare)/element_count, double(num_copy)/element_count );
double time = double(new_clock);
const char *units = "ns";
if(time >= 1000000000.0){
time /= 1000000000.0;
units = " s";
}
else if(time >= 1000000.0){
time /= 1000000.0;
units = "ms";
}
else if(time >= 1000.0){
time /= 1000.0;
units = "us";
}
std::printf(" %6.02f%s (%6.02f)\n"
, time
, units
, prev_clock ? double(new_clock)/double(prev_clock): 1.0);
prev_clock = new_clock;
bool res = test_order(elements, element_count, true);
return res;
}
template<class T>
bool measure_all(std::size_t L, std::size_t NK)
{
boost::movelib::unique_ptr<T[]> pdata(new T[L]);
boost::movelib::unique_ptr<std::size_t[]> pkeys(new std::size_t[NK ? NK : L]);
T *A = pdata.get();
std::size_t *Keys = pkeys.get();
std::printf("\n - - N: %u, NK: %u - -\n",L,NK);
nanosecond_type prev_clock = 0;
nanosecond_type back_clock;
bool res = true;
res = res && measure_algo(A,Keys,L,NK,InplaceMerge, prev_clock);
back_clock = prev_clock;/*
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,QuartAdaptiveMerge, prev_clock);*/
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,Sqrt2AdaptiveMerge, prev_clock);
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,SqrtAdaptiveMerge, prev_clock);
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,SqrtHAdaptiveMerge, prev_clock);
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,AdaptiveMerge, prev_clock);
//
//prev_clock = back_clock;
//res = res && measure_algo(A,Keys,L,NK,BuflessMerge, prev_clock);
//
if(!res)
throw int(0);
return res;
}
struct less
{
template<class T, class U>
bool operator()(const T &t, const U &u)
{ return t < u; }
};
//Undef it to run the long test
#define BENCH_MERGE_SHORT
int main()
{
try{
measure_all<merged_type>(101,1);
measure_all<merged_type>(101,7);
measure_all<merged_type>(101,31);
measure_all<merged_type>(101,0);
//
measure_all<merged_type>(1101,1);
measure_all<merged_type>(1001,7);
measure_all<merged_type>(1001,31);
measure_all<merged_type>(1001,127);
measure_all<merged_type>(1001,511);
measure_all<merged_type>(1001,0);
//
#ifndef BENCH_MERGE_SHORT
measure_all<merged_type>(10001,65);
measure_all<merged_type>(10001,255);
measure_all<merged_type>(10001,1023);
measure_all<merged_type>(10001,4095);
measure_all<merged_type>(10001,0);
//
measure_all<merged_type>(100001,511);
measure_all<merged_type>(100001,2047);
measure_all<merged_type>(100001,8191);
measure_all<merged_type>(100001,32767);
measure_all<merged_type>(100001,0);
//
#ifdef NDEBUG
measure_all<merged_type>(1000001,1);
measure_all<merged_type>(1000001,1024);
measure_all<merged_type>(1000001,32768);
measure_all<merged_type>(1000001,524287);
measure_all<merged_type>(1000001,0);
measure_all<merged_type>(1500001,0);
//measure_all<merged_type>(10000001,0);
//measure_all<merged_type>(15000001,0);
//measure_all<merged_type>(100000001,0);
#endif //NDEBUG
#endif //#ifndef BENCH_MERGE_SHORT
//measure_all<merged_type>(100000001,0);
}
catch(...)
{
return 1;
}
return 0;
}

351
test/bench_sort.cpp Normal file
View File

@ -0,0 +1,351 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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.
//
//////////////////////////////////////////////////////////////////////////////
#include <cstdlib> //std::srand
#include <algorithm> //std::stable_sort, std::make|sort_heap, std::random_shuffle
#include <cstdio> //std::printf
#include <iostream> //std::cout
#include <boost/config.hpp>
#include <boost/move/unique_ptr.hpp>
#include <boost/timer/timer.hpp>
using boost::timer::cpu_timer;
using boost::timer::cpu_times;
using boost::timer::nanosecond_type;
boost::ulong_long_type num_copy;
boost::ulong_long_type num_elements;
struct sorted_type
{
public:
std::size_t key;
std::size_t val;
sorted_type()
{
++num_elements;
}
sorted_type(const sorted_type& other)
: key(other.key), val(other.val)
{
++num_elements;
++num_copy;
}
sorted_type & operator=(const sorted_type& other)
{
++num_copy;
key = other.key;
val = other.val;
return *this;
}
~sorted_type ()
{
--num_elements;
}
};
boost::ulong_long_type num_compare;
//#define BOOST_MOVE_ADAPTIVE_SORT_STATS
void print_stats(const char *str, boost::ulong_long_type element_count)
{
std::printf("%sCmp:%7.03f Cpy:%8.03f\n", str, double(num_compare)/element_count, double(num_copy)/element_count );
}
template<class T>
struct counted_less
{
bool operator()(const T &a,T const &b) const
{ ++num_compare; return a.key < b.key; }
};
#include <boost/move/algo/adaptive_sort.hpp>
#include <boost/move/algo/detail/merge_sort.hpp>
#include <boost/move/algo/detail/bufferless_merge_sort.hpp>
#include <boost/move/core.hpp>
template<class T>
void generate_elements(T elements[], std::size_t element_count, std::size_t key_reps[], std::size_t key_len)
{
std::srand(0);
for(std::size_t i = 0; i < (key_len ? key_len : element_count); ++i){
key_reps[i]=0;
}
for(std::size_t i=0; i < element_count; ++i){
std::size_t key = key_len ? (i % key_len) : i;
elements[i].key=key;
}
std::random_shuffle(elements, elements + element_count);
std::random_shuffle(elements, elements + element_count);
std::random_shuffle(elements, elements + element_count);
for(std::size_t i = 0; i < element_count; ++i){
elements[i].val = key_reps[elements[i].key]++;
}
}
template<class T>
bool test_order(T *elements, std::size_t element_count, bool stable = true)
{
for(std::size_t i = 1; i < element_count; ++i){
if(counted_less<T>()(elements[i], elements[i-1])){
std::printf("\n Ord KO !!!!");
return false;
}
if( stable && !(counted_less<T>()(elements[i-1], elements[i])) && (elements[i-1].val > elements[i].val) ){
std::printf("\n Stb KO !!!! ");
return false;
}
}
return true;
}
template<class T, class Compare>
void adaptive_sort_buffered(T *elements, std::size_t element_count, Compare comp, std::size_t BufLen)
{
boost::movelib::unique_ptr<char[]> mem(new char[sizeof(T)*BufLen]);
boost::movelib::adaptive_sort(elements, elements + element_count, comp, reinterpret_cast<T*>(mem.get()), BufLen);
}
template<class T, class Compare>
void merge_sort_buffered(T *elements, std::size_t element_count, Compare comp)
{
boost::movelib::unique_ptr<char[]> mem(new char[sizeof(T)*((element_count+1)/2)]);
boost::movelib::merge_sort(elements, elements + element_count, comp, reinterpret_cast<T*>(mem.get()));
}
enum AlgoType
{
MergeSort,
StableSort,
AdaptiveSort,
SqrtHAdaptiveSort,
SqrtAdaptiveSort,
Sqrt2AdaptiveSort,
QuartAdaptiveSort,
NoBufMergeSort,
SlowStableSort,
HeapSort,
MaxSort
};
const char *AlgoNames [] = { "MergeSort "
, "StableSort "
, "AdaptSort "
, "SqrtHAdaptSort "
, "SqrtAdaptSort "
, "Sqrt2AdaptSort "
, "QuartAdaptSort "
, "NoBufMergeSort "
, "SlowSort "
, "HeapSort "
};
BOOST_STATIC_ASSERT((sizeof(AlgoNames)/sizeof(*AlgoNames)) == MaxSort);
template<class T>
bool measure_algo(T *elements, std::size_t key_reps[], std::size_t element_count, std::size_t key_len, unsigned alg, nanosecond_type &prev_clock)
{
generate_elements(elements, element_count, key_reps, key_len);
std::printf("%s ", AlgoNames[alg]);
num_compare=0;
num_copy=0;
num_elements = element_count;
cpu_timer timer;
timer.resume();
switch(alg)
{
case MergeSort:
merge_sort_buffered(elements, element_count, counted_less<T>());
break;
case StableSort:
std::stable_sort(elements,elements+element_count,counted_less<T>());
break;
case AdaptiveSort:
boost::movelib::adaptive_sort(elements, elements+element_count, counted_less<T>());
break;
case SqrtHAdaptiveSort:
adaptive_sort_buffered( elements, element_count, counted_less<T>()
, boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count)/2+1);
break;
case SqrtAdaptiveSort:
adaptive_sort_buffered( elements, element_count, counted_less<T>()
, boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count));
break;
case Sqrt2AdaptiveSort:
adaptive_sort_buffered( elements, element_count, counted_less<T>()
, 2*boost::movelib::detail_adaptive::ceil_sqrt_multiple(element_count));
break;
case QuartAdaptiveSort:
adaptive_sort_buffered( elements, element_count, counted_less<T>()
, (element_count-1)/4+1);
break;
case NoBufMergeSort:
boost::movelib::bufferless_merge_sort(elements, elements+element_count, counted_less<T>());
break;
case SlowStableSort:
boost::movelib::detail_adaptive::slow_stable_sort(elements, elements+element_count, counted_less<T>());
break;
case HeapSort:
std::make_heap(elements, elements+element_count, counted_less<T>());
std::sort_heap(elements, elements+element_count, counted_less<T>());
break;
}
timer.stop();
if(num_elements == element_count){
std::printf(" Tmp Ok ");
} else{
std::printf(" Tmp KO ");
}
nanosecond_type new_clock = timer.elapsed().wall;
//std::cout << "Cmp:" << num_compare << " Cpy:" << num_copy; //for old compilers without ll size argument
std::printf("Cmp:%7.03f Cpy:%8.03f", double(num_compare)/element_count, double(num_copy)/element_count );
double time = double(new_clock);
const char *units = "ns";
if(time >= 1000000000.0){
time /= 1000000000.0;
units = " s";
}
else if(time >= 1000000.0){
time /= 1000000.0;
units = "ms";
}
else if(time >= 1000.0){
time /= 1000.0;
units = "us";
}
std::printf(" %6.02f%s (%6.02f)\n"
, time
, units
, prev_clock ? double(new_clock)/double(prev_clock): 1.0);
prev_clock = new_clock;
bool res = test_order(elements, element_count, alg != HeapSort && alg != NoBufMergeSort);
return res;
}
template<class T>
bool measure_all(std::size_t L, std::size_t NK)
{
boost::movelib::unique_ptr<T[]> pdata(new T[L]);
boost::movelib::unique_ptr<std::size_t[]> pkeys(new std::size_t[NK ? NK : L]);
T *A = pdata.get();
std::size_t *Keys = pkeys.get();
std::printf("\n - - N: %u, NK: %u - -\n",L,NK);
nanosecond_type prev_clock = 0;
nanosecond_type back_clock;
bool res = true;
res = res && measure_algo(A,Keys,L,NK,MergeSort, prev_clock);
back_clock = prev_clock;
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,StableSort, prev_clock);
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,HeapSort, prev_clock);
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,QuartAdaptiveSort, prev_clock);
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,Sqrt2AdaptiveSort, prev_clock);
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,SqrtAdaptiveSort, prev_clock);
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,SqrtHAdaptiveSort, prev_clock);
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,AdaptiveSort, prev_clock);
//
prev_clock = back_clock;
res = res && measure_algo(A,Keys,L,NK,NoBufMergeSort, prev_clock);
//
//prev_clock = back_clock;
//res = res && measure_algo(A,Keys,L,NK,SlowStableSort, prev_clock);
//
if(!res)
throw int(0);
return res;
}
//Undef it to run the long test
#define BENCH_SORT_SHORT
struct less
{
template<class T, class U>
bool operator()(const T &t, const U &u)
{ return t < u; }
};
int main()
{
measure_all<sorted_type>(101,1);
measure_all<sorted_type>(101,7);
measure_all<sorted_type>(101,31);
measure_all<sorted_type>(101,0);
//
measure_all<sorted_type>(1101,1);
measure_all<sorted_type>(1001,7);
measure_all<sorted_type>(1001,31);
measure_all<sorted_type>(1001,127);
measure_all<sorted_type>(1001,511);
measure_all<sorted_type>(1001,0);
//
#ifndef BENCH_SORT_SHORT
measure_all<sorted_type>(10001,65);
measure_all<sorted_type>(10001,255);
measure_all<sorted_type>(10001,1023);
measure_all<sorted_type>(10001,4095);
measure_all<sorted_type>(10001,0);
//
measure_all<sorted_type>(100001,511);
measure_all<sorted_type>(100001,2047);
measure_all<sorted_type>(100001,8191);
measure_all<sorted_type>(100001,32767);
measure_all<sorted_type>(100001,0);
//
#ifdef NDEBUG
measure_all<sorted_type>(1000001,1);
measure_all<sorted_type>(1000001,1024);
measure_all<sorted_type>(1000001,32768);
measure_all<sorted_type>(1000001,524287);
measure_all<sorted_type>(1000001,0);
measure_all<sorted_type>(1500001,0);
//measure_all<sorted_type>(10000001,0);
#endif //NDEBUG
#endif //#ifndef BENCH_SORT_SHORT
//measure_all<sorted_type>(100000001,0);
return 0;
}