mirror of
https://github.com/boostorg/sort.git
synced 2026-01-19 04:42:11 +00:00
delete namespace parallel
This commit is contained in:
0
benchmark/parallel/runCLANG_benchmark_numbers.sh
Normal file → Executable file
0
benchmark/parallel/runCLANG_benchmark_numbers.sh
Normal file → Executable file
0
benchmark/parallel/runCLANG_benchmark_objects.sh
Normal file → Executable file
0
benchmark/parallel/runCLANG_benchmark_objects.sh
Normal file → Executable file
0
benchmark/parallel/runCLANG_benchmark_strings.sh
Normal file → Executable file
0
benchmark/parallel/runCLANG_benchmark_strings.sh
Normal file → Executable file
0
benchmark/parallel/runGCC_benchmark_numbers.sh
Normal file → Executable file
0
benchmark/parallel/runGCC_benchmark_numbers.sh
Normal file → Executable file
0
benchmark/parallel/runGCC_benchmark_objects.sh
Normal file → Executable file
0
benchmark/parallel/runGCC_benchmark_objects.sh
Normal file → Executable file
0
benchmark/parallel/runGCC_benchmark_strings.sh
Normal file → Executable file
0
benchmark/parallel/runGCC_benchmark_strings.sh
Normal file → Executable file
0
benchmark/single/runCLANG_benchmark_numbers.sh
Normal file → Executable file
0
benchmark/single/runCLANG_benchmark_numbers.sh
Normal file → Executable file
0
benchmark/single/runCLANG_benchmark_objects.sh
Normal file → Executable file
0
benchmark/single/runCLANG_benchmark_objects.sh
Normal file → Executable file
0
benchmark/single/runCLANG_benchmark_strings.sh
Normal file → Executable file
0
benchmark/single/runCLANG_benchmark_strings.sh
Normal file → Executable file
0
benchmark/single/runGCC_benchmark_numbers.sh
Normal file → Executable file
0
benchmark/single/runGCC_benchmark_numbers.sh
Normal file → Executable file
0
benchmark/single/runGCC_benchmark_objects.sh
Normal file → Executable file
0
benchmark/single/runGCC_benchmark_objects.sh
Normal file → Executable file
0
benchmark/single/runGCC_benchmark_strings.sh
Normal file → Executable file
0
benchmark/single/runGCC_benchmark_strings.sh
Normal file → Executable file
@@ -1,504 +0,0 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file block_indirect_sort.hpp
|
||||
/// @brief block indirect sort algorithm
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __BOOST_SORT_PARALLEL_DETAIL_BLOCK_INDIRECT_SORT_HPP
|
||||
#define __BOOST_SORT_PARALLEL_DETAIL_BLOCK_INDIRECT_SORT_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <boost/sort/parallel/detail/merge_blocks.hpp>
|
||||
#include <boost/sort/parallel/detail/move_blocks.hpp>
|
||||
#include <boost/sort/parallel/detail/parallel_sort.hpp>
|
||||
#include <boost/sort/pdqsort/pdqsort.h>
|
||||
#include <boost/sort/common/util/traits.hpp>
|
||||
#include <boost/sort/common/util/algorithm.hpp>
|
||||
#include <future>
|
||||
#include <iterator>
|
||||
|
||||
// This value is the minimal number of threads for to use the
|
||||
// block_indirect_sort algorithm
|
||||
#define BOOST_NTHREAD_BORDER 6
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace sort
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
//---------------------------------------------------------------------------
|
||||
// USING SENTENCES
|
||||
//---------------------------------------------------------------------------
|
||||
namespace bs = boost::sort;
|
||||
namespace bsc = bs::common;
|
||||
namespace bscu = bsc::util;
|
||||
using bscu::compare_iter;
|
||||
using bscu::value_iter;
|
||||
using bsc::range;
|
||||
using bsc::destroy;
|
||||
using bsc::initialize;
|
||||
using bscu::nbits64;
|
||||
using bs::pdqsort;
|
||||
using bscu::enable_if_string;
|
||||
using bscu::enable_if_not_string;
|
||||
using bscu::tmsb;
|
||||
//
|
||||
///---------------------------------------------------------------------------
|
||||
/// @struct block_indirect_sort
|
||||
/// @brief This class is the entry point of the block indirect sort. The code
|
||||
/// of this algorithm is divided in several classes:
|
||||
/// bis/block.hpp : basic structures used in the algorithm
|
||||
/// bis/backbone.hpp : data used by all the classes
|
||||
/// bis/merge_blocks.hpp : merge the internal blocks
|
||||
/// bis/move_blocks.hpp : move the blocks, and obtain all the elements
|
||||
/// phisicaly sorted
|
||||
/// bis/parallel_sort.hpp : make the parallel sort of each part in the
|
||||
/// initial division of the data
|
||||
///
|
||||
//----------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t,
|
||||
class Compare = compare_iter<Iter_t> >
|
||||
struct block_indirect_sort
|
||||
{
|
||||
//------------------------------------------------------------------------
|
||||
// D E F I N I T I O N S
|
||||
//------------------------------------------------------------------------
|
||||
typedef typename std::iterator_traits<Iter_t>::value_type value_t;
|
||||
typedef std::atomic<uint32_t> atomic_t;
|
||||
typedef range<size_t> range_pos;
|
||||
typedef range<Iter_t> range_it;
|
||||
typedef range<value_t *> range_buf;
|
||||
typedef std::function<void(void)> function_t;
|
||||
|
||||
// classes used in the internal operations of the algorithm
|
||||
typedef block_pos block_pos_t;
|
||||
typedef block<Block_size, Iter_t> block_t;
|
||||
typedef backbone<Block_size, Iter_t, Compare> backbone_t;
|
||||
typedef parallel_sort<Block_size, Iter_t, Compare> parallel_sort_t;
|
||||
|
||||
typedef merge_blocks<Block_size, Group_size, Iter_t, Compare> merge_blocks_t;
|
||||
typedef move_blocks<Block_size, Group_size, Iter_t, Compare> move_blocks_t;
|
||||
typedef compare_block_pos<Block_size, Iter_t, Compare> compare_block_pos_t;
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// V A R I A B L E S A N D C O N S T A N T S
|
||||
//------------------------------------------------------------------------
|
||||
// contains the data and the internal data structures of the algorithm for
|
||||
// to be shared between the classes which are part of the algorithm
|
||||
backbone_t bk;
|
||||
// atomic counter for to detect the end of the works created inside
|
||||
// the object
|
||||
atomic_t counter;
|
||||
// pointer to the uninitialized memory used for the thread buffers
|
||||
value_t *ptr;
|
||||
// indicate if the memory pointed by ptr is initialized
|
||||
bool construct;
|
||||
// range from extract the buffers for the threads
|
||||
range_buf rglobal_buf;
|
||||
// number of threads to use
|
||||
uint32_t nthread;
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// F U N C T I O N S
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
block_indirect_sort(Iter_t first, Iter_t last, Compare cmp, uint32_t nthr);
|
||||
|
||||
block_indirect_sort(Iter_t first, Iter_t last) :
|
||||
block_indirect_sort(first, last, Compare(),
|
||||
std::thread::hardware_concurrency()) { }
|
||||
|
||||
|
||||
block_indirect_sort(Iter_t first, Iter_t last, Compare cmp) :
|
||||
block_indirect_sort(first, last, cmp,
|
||||
std::thread::hardware_concurrency()) { }
|
||||
|
||||
|
||||
block_indirect_sort(Iter_t first, Iter_t last, uint32_t nthread) :
|
||||
block_indirect_sort(first, last, Compare(), nthread){}
|
||||
|
||||
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// function :destroy_all
|
||||
/// @brief destructor all the data structures of the class (if the memory
|
||||
/// is constructed, is destroyed) and return the uninitialized
|
||||
/// memory
|
||||
//------------------------------------------------------------------------
|
||||
void destroy_all(void)
|
||||
{
|
||||
if (ptr != nullptr)
|
||||
{
|
||||
if (construct)
|
||||
{
|
||||
destroy(rglobal_buf);
|
||||
construct = false;
|
||||
};
|
||||
std::return_temporary_buffer(ptr);
|
||||
ptr = nullptr;
|
||||
};
|
||||
}
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// function :~block_indirect_sort
|
||||
/// @brief destructor of the class (if the memory is constructed, is
|
||||
/// destroyed) and return the uninitialized memory
|
||||
//------------------------------------------------------------------------
|
||||
~block_indirect_sort(void)
|
||||
{
|
||||
destroy_all();
|
||||
}
|
||||
|
||||
void split_range(size_t pos_index1, size_t pos_index2,
|
||||
uint32_t level_thread);
|
||||
|
||||
void start_function(void);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
}; // End class block_indirect_sort
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
//############################################################################
|
||||
// ##
|
||||
// ##
|
||||
// N O N I N L I N E F U N C T I O N S ##
|
||||
// ##
|
||||
// ##
|
||||
//############################################################################
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : block_indirect_sort
|
||||
/// @brief begin with the execution of the functions stored in works
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
/// @param comp : object for to compare two elements pointed by Iter_t
|
||||
/// iterators
|
||||
/// @param nthr : Number of threads to use in the process.When this value
|
||||
/// is lower than 2, the sorting is done with 1 thread
|
||||
//-------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
block_indirect_sort<Block_size, Group_size, Iter_t, Compare>
|
||||
::block_indirect_sort(Iter_t first, Iter_t last, Compare cmp, uint32_t nthr)
|
||||
: bk(first, last, cmp), counter(0), ptr(nullptr), construct(false),
|
||||
nthread(nthr)
|
||||
{
|
||||
try
|
||||
{
|
||||
assert((last - first) >= 0);
|
||||
size_t nelem = size_t(last - first);
|
||||
if (nelem == 0) return;
|
||||
|
||||
//------------------- check if sort -----------------------------------
|
||||
bool sorted = true;
|
||||
for (Iter_t it1 = first, it2 = first + 1; it2 != last and (sorted =
|
||||
not bk.cmp(*it2, *it1)); it1 = it2++);
|
||||
if (sorted) return;
|
||||
|
||||
//------------------- check if reverse sort ---------------------------
|
||||
sorted = true;
|
||||
for (Iter_t it1 = first, it2 = first + 1; it2 != last and (sorted =
|
||||
not bk.cmp(*it1, *it2)); it1 = it2++);
|
||||
|
||||
if (sorted)
|
||||
{
|
||||
size_t nelem2 = nelem >> 1;
|
||||
Iter_t it1 = first, it2 = last - 1;
|
||||
for (size_t i = 0; i < nelem2; ++i)
|
||||
{
|
||||
std::swap(*(it1++), *(it2--));
|
||||
};
|
||||
return;
|
||||
};
|
||||
|
||||
//---------------- check if only single thread -----------------------
|
||||
size_t nthreadmax = nelem / (Block_size * Group_size) + 1;
|
||||
if (nthread > nthreadmax) nthread = (uint32_t) nthreadmax;
|
||||
|
||||
uint32_t nbits_size = (nbits64(sizeof(value_t)) >> 1);
|
||||
if (nbits_size > 5) nbits_size = 5;
|
||||
size_t max_per_thread = 1 << (18 - nbits_size);
|
||||
|
||||
if (nelem < (max_per_thread) or nthread < 2)
|
||||
{
|
||||
//intro_sort (first, last, bk.cmp);
|
||||
pdqsort(first, last, bk.cmp);
|
||||
return;
|
||||
};
|
||||
|
||||
//----------- creation of the temporary buffer --------------------
|
||||
ptr = std::get_temporary_buffer<value_t>(Block_size * nthread).first;
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
bk.error = true;
|
||||
throw std::bad_alloc();
|
||||
};
|
||||
|
||||
rglobal_buf = range_buf(ptr, ptr + (Block_size * nthread));
|
||||
initialize(rglobal_buf, *first);
|
||||
construct = true;
|
||||
|
||||
// creation of the buffers for the threads
|
||||
std::vector<value_t *> vbuf(nthread);
|
||||
for (uint32_t i = 0; i < nthread; ++i)
|
||||
{
|
||||
vbuf[i] = ptr + (i * Block_size);
|
||||
};
|
||||
|
||||
// Insert the first work in the stack
|
||||
bscu::atomic_write(counter, 1);
|
||||
function_t f1 = [&]( )
|
||||
{
|
||||
start_function ( );
|
||||
bscu::atomic_sub (counter, 1);
|
||||
};
|
||||
bk.works.emplace_back(f1);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// PROCESS
|
||||
//---------------------------------------------------------------------
|
||||
std::vector<std::future<void> > vfuture(nthread);
|
||||
|
||||
// The function launched with the futures is "execute the functions of
|
||||
// the stack until this->counter is zero
|
||||
// vbuf[i] is the memory from the main thread for to configure the
|
||||
// thread local buffer
|
||||
for (uint32_t i = 0; i < nthread; ++i)
|
||||
{
|
||||
auto f1 = [=, &vbuf]( )
|
||||
{ bk.exec (vbuf[i], this->counter);};
|
||||
vfuture[i] = std::async(std::launch::async, f1);
|
||||
};
|
||||
for (uint32_t i = 0; i < nthread; ++i)
|
||||
vfuture[i].get();
|
||||
if (bk.error) throw std::bad_alloc();
|
||||
}
|
||||
catch (std::bad_alloc &)
|
||||
{
|
||||
destroy_all();
|
||||
throw;
|
||||
}
|
||||
};
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : split_rage
|
||||
/// @brief this function splits a range of positions in the index, and
|
||||
/// depending of the size, sort directly or make to a recursive call
|
||||
/// to split_range
|
||||
/// @param pos_index1 : first position in the index
|
||||
/// @param pos_index2 : position after the last in the index
|
||||
/// @param level_thread : depth of the call. When 0 sort the blocks
|
||||
//-----------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
void block_indirect_sort<Block_size, Group_size, Iter_t, Compare>
|
||||
::split_range(size_t pos_index1, size_t pos_index2, uint32_t level_thread)
|
||||
{
|
||||
size_t nblock = pos_index2 - pos_index1;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// In the blocks not sorted, the physical position is the logical position
|
||||
//-------------------------------------------------------------------------
|
||||
Iter_t first = bk.get_block(pos_index1).first;
|
||||
Iter_t last = bk.get_range(pos_index2 - 1).last;
|
||||
|
||||
if (nblock < Group_size)
|
||||
{
|
||||
pdqsort(first, last, bk.cmp);
|
||||
return;
|
||||
};
|
||||
|
||||
size_t pos_index_mid = pos_index1 + (nblock >> 1);
|
||||
atomic_t son_counter(1);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Insert in the stack the work for the second part, and the actual thread,
|
||||
// execute the first part
|
||||
//-------------------------------------------------------------------------
|
||||
if (level_thread != 0)
|
||||
{
|
||||
auto f1 = [=, &son_counter]( )
|
||||
{
|
||||
split_range (pos_index_mid, pos_index2, level_thread - 1);
|
||||
bscu::atomic_sub (son_counter, 1);
|
||||
};
|
||||
bk.works.emplace_back(f1);
|
||||
if (bk.error) return;
|
||||
split_range(pos_index1, pos_index_mid, level_thread - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Iter_t mid = first + ((nblock >> 1) * Block_size);
|
||||
auto f1 = [=, &son_counter]( )
|
||||
{
|
||||
parallel_sort_t (bk, mid, last);
|
||||
bscu::atomic_sub (son_counter, 1);
|
||||
};
|
||||
bk.works.emplace_back(f1);
|
||||
if (bk.error) return;
|
||||
parallel_sort_t(bk, first, mid);
|
||||
};
|
||||
bk.exec(son_counter);
|
||||
if (bk.error) return;
|
||||
merge_blocks_t(bk, pos_index1, pos_index_mid, pos_index2);
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : start_function
|
||||
/// @brief this function init the process. When the number of threads is lower
|
||||
/// than a predefined value, sort the elements with a parallel pdqsort.
|
||||
//-----------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
void block_indirect_sort<Block_size, Group_size, Iter_t, Compare>
|
||||
::start_function(void)
|
||||
{
|
||||
if (nthread < BOOST_NTHREAD_BORDER)
|
||||
{
|
||||
parallel_sort_t(bk, bk.global_range.first, bk.global_range.last);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t level_thread = nbits64(nthread - 1) - 1;
|
||||
split_range(0, bk.nblock, level_thread - 1);
|
||||
if (bk.error) return;
|
||||
move_blocks_t k(bk);
|
||||
};
|
||||
};
|
||||
|
||||
///---------------------------------------------------------------------------
|
||||
// function block_indirect_sort_call
|
||||
/// @brief This class is select the block size in the block_indirect_sort
|
||||
/// algorithm depending of the type and size of the data to sort
|
||||
///
|
||||
//----------------------------------------------------------------------------
|
||||
template <class Iter_t, class Compare,
|
||||
enable_if_string<value_iter<Iter_t>> * = nullptr>
|
||||
inline void block_indirect_sort_call(Iter_t first, Iter_t last, Compare cmp,
|
||||
uint32_t nthr)
|
||||
{
|
||||
block_indirect_sort<128, 128, Iter_t, Compare>(first, last, cmp, nthr);
|
||||
};
|
||||
|
||||
template<size_t Size>
|
||||
struct block_size
|
||||
{
|
||||
static constexpr const uint32_t BitsSize =
|
||||
(Size == 0) ? 0 : (Size > 256) ? 9 : tmsb[Size - 1];
|
||||
static constexpr const uint32_t sz[10] =
|
||||
{ 4096, 4096, 4096, 4096, 2048, 1024, 768, 512, 256, 128 };
|
||||
static constexpr const uint32_t data = sz[BitsSize];
|
||||
};
|
||||
//
|
||||
///---------------------------------------------------------------------------
|
||||
/// @struct block_indirect_sort_call
|
||||
/// @brief This class is select the block size in the block_indirect_sort
|
||||
/// algorithm depending of the type and size of the data to sort
|
||||
///
|
||||
//----------------------------------------------------------------------------
|
||||
template <class Iter_t, class Compare,
|
||||
enable_if_not_string<value_iter<Iter_t>> * = nullptr>
|
||||
inline void block_indirect_sort_call (Iter_t first, Iter_t last, Compare cmp,
|
||||
uint32_t nthr)
|
||||
{
|
||||
block_indirect_sort<block_size<sizeof (value_iter<Iter_t> )>::data, 64,
|
||||
Iter_t, Compare> (first, last, cmp, nthr);
|
||||
};
|
||||
|
||||
//
|
||||
//****************************************************************************
|
||||
}; // End namespace block_detail
|
||||
//****************************************************************************
|
||||
//
|
||||
namespace bscu = boost::sort::common::util;
|
||||
//
|
||||
//############################################################################
|
||||
// ##
|
||||
// ##
|
||||
// B L O C K _ I N D I R E C T _ S O R T ##
|
||||
// ##
|
||||
// ##
|
||||
//############################################################################
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : block_indirect_sort
|
||||
/// @brief parallel sample sort algorithm (stable sort)
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Iter_t>
|
||||
void block_indirect_sort(Iter_t first, Iter_t last)
|
||||
{
|
||||
typedef bscu::compare_iter<Iter_t> Compare;
|
||||
detail::block_indirect_sort_call (first, last, Compare(),
|
||||
std::thread::hardware_concurrency());
|
||||
}
|
||||
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : block_indirect_sort
|
||||
/// @brief parallel sample sort algorithm (stable sort)
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
/// @param nthread : Number of threads to use in the process. When this value
|
||||
/// is lower than 2, the sorting is done with 1 thread
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Iter_t>
|
||||
void block_indirect_sort(Iter_t first, Iter_t last, uint32_t nthread)
|
||||
{
|
||||
typedef bscu::compare_iter<Iter_t> Compare;
|
||||
detail::block_indirect_sort_call(first, last, Compare(), nthread);
|
||||
}
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : block_indirect_sort
|
||||
/// @brief parallel sample sort algorithm (stable sort)
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
/// @param comp : object for to compare two elements pointed by Iter_t
|
||||
/// iterators
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Iter_t, class Compare,
|
||||
bscu::enable_if_not_integral<Compare> * = nullptr>
|
||||
void block_indirect_sort(Iter_t first, Iter_t last, Compare comp)
|
||||
{
|
||||
detail::block_indirect_sort_call (first, last, comp,
|
||||
std::thread::hardware_concurrency());
|
||||
}
|
||||
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : block_indirect_sort
|
||||
/// @brief parallel sample sort algorithm (stable sort)
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
/// @param comp : object for to compare two elements pointed by Iter_t
|
||||
/// iterators
|
||||
/// @param nthread : Number of threads to use in the process. When this value
|
||||
/// is lower than 2, the sorting is done with 1 thread
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Iter_t, class Compare>
|
||||
void block_indirect_sort (Iter_t first, Iter_t last, Compare comp,
|
||||
uint32_t nthread)
|
||||
{
|
||||
detail::block_indirect_sort_call(first, last, comp, nthread);
|
||||
}
|
||||
//
|
||||
//****************************************************************************
|
||||
}; // End namespace parallel
|
||||
}; // End namespace sort
|
||||
}; // End namespace boost
|
||||
//****************************************************************************
|
||||
//
|
||||
#endif
|
||||
@@ -1,222 +0,0 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file backbone.hpp
|
||||
/// @brief This file constains the class backbone, which is part of the
|
||||
/// block_indirect_sort algorithm
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __BOOST_SORT_PARALLEL_DETAIL_BACKBONE_HPP
|
||||
#define __BOOST_SORT_PARALLEL_DETAIL_BACKBONE_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <boost/sort/pdqsort/pdqsort.h>
|
||||
#include <boost/sort/common/util/atomic.hpp>
|
||||
#include <boost/sort/common/util/algorithm.hpp>
|
||||
#include <boost/sort/common/stack_cnc.hpp>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
#include <boost/sort/parallel/detail/block.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace sort
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// USING SENTENCES
|
||||
//---------------------------------------------------------------------------
|
||||
namespace bsc = boost::sort::common;
|
||||
namespace bscu = bsc::util;
|
||||
using bsc::stack_cnc;
|
||||
using bsc::range;
|
||||
|
||||
///---------------------------------------------------------------------------
|
||||
/// @struct backbone
|
||||
/// @brief This contains all the information shared betwen the classes of the
|
||||
/// block indirect sort algorithm
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
template < uint32_t Block_size, class Iter_t, class Compare >
|
||||
struct backbone
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
// D E F I N I T I O N S
|
||||
//-------------------------------------------------------------------------
|
||||
typedef typename std::iterator_traits< Iter_t >::value_type value_t;
|
||||
typedef std::atomic< uint32_t > atomic_t;
|
||||
typedef range< size_t > range_pos;
|
||||
typedef range< Iter_t > range_it;
|
||||
typedef range< value_t * > range_buf;
|
||||
typedef std::function< void(void) > function_t;
|
||||
typedef block< Block_size, Iter_t > block_t;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// V A R I A B L E S
|
||||
//------------------------------------------------------------------------
|
||||
// range with all the element to sort
|
||||
range< Iter_t > global_range;
|
||||
|
||||
// index vector of block_pos elements
|
||||
std::vector< block_pos > index;
|
||||
|
||||
// Number of elements to sort
|
||||
size_t nelem;
|
||||
|
||||
// Number of blocks to sort
|
||||
size_t nblock;
|
||||
|
||||
// Number of elements in the last block (tail)
|
||||
size_t ntail;
|
||||
|
||||
// object for to compare two elements
|
||||
Compare cmp;
|
||||
|
||||
// range of elements of the last block (tail)
|
||||
range_it range_tail;
|
||||
|
||||
// thread local varible. It is a pointer to the buffer
|
||||
static thread_local value_t *buf;
|
||||
|
||||
// concurrent stack where store the function_t elements
|
||||
stack_cnc< function_t > works;
|
||||
|
||||
// global indicator of error
|
||||
bool error;
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// F U N C T I O N S
|
||||
//------------------------------------------------------------------------
|
||||
backbone (Iter_t first, Iter_t last, Compare comp);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// function : get_block
|
||||
/// @brief obtain the block in the position pos
|
||||
/// @param pos : position of the range
|
||||
/// @return block required
|
||||
//------------------------------------------------------------------------
|
||||
block_t get_block (size_t pos) const
|
||||
{
|
||||
return block_t (global_range.first + (pos * Block_size));
|
||||
};
|
||||
//-------------------------------------------------------------------------
|
||||
// function : get_range
|
||||
/// @brief obtain the range in the position pos
|
||||
/// @param pos : position of the range
|
||||
/// @return range required
|
||||
//-------------------------------------------------------------------------
|
||||
range_it get_range (size_t pos) const
|
||||
{
|
||||
Iter_t it1 = global_range.first + (pos * Block_size);
|
||||
Iter_t it2 =
|
||||
(pos == (nblock - 1)) ? global_range.last : it1 + Block_size;
|
||||
return range_it (it1, it2);
|
||||
};
|
||||
//-------------------------------------------------------------------------
|
||||
// function : get_range_buf
|
||||
/// @brief obtain the auxiliary buffer of the thread
|
||||
//-------------------------------------------------------------------------
|
||||
range_buf get_range_buf ( ) const
|
||||
{
|
||||
return range_buf (buf, buf + Block_size);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// function : exec
|
||||
/// @brief Initialize the thread local buffer with the ptr_buf pointer,
|
||||
/// and begin with the execution of the functions stored in works
|
||||
//
|
||||
/// @param ptr_buf : Pointer to the memory assigned to the thread_local
|
||||
/// buffer
|
||||
/// @param counter : atomic counter for to invoke to the exec function
|
||||
/// with only 1 parameter
|
||||
//-------------------------------------------------------------------------
|
||||
void exec (value_t *ptr_buf, atomic_t &counter)
|
||||
{
|
||||
buf = ptr_buf;
|
||||
exec (counter);
|
||||
};
|
||||
|
||||
void exec (atomic_t &counter);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
}; // end struct backbone
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//############################################################################
|
||||
// ##
|
||||
// ##
|
||||
// N O N I N L I N E F U N C T I O N S ##
|
||||
// ##
|
||||
// ##
|
||||
//############################################################################
|
||||
//
|
||||
// initialization of the thread_local pointer to the auxiliary buffer
|
||||
template < uint32_t Block_size, class Iter_t, class Compare >
|
||||
thread_local typename std::iterator_traits< Iter_t >
|
||||
::value_type *backbone< Block_size, Iter_t, Compare >::buf = nullptr;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// function : backbone
|
||||
/// @brief constructor of the class
|
||||
//
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
/// @param comp : object for to compare two elements pointed by Iter_t
|
||||
/// iterators
|
||||
//------------------------------------------------------------------------
|
||||
template < uint32_t Block_size, class Iter_t, class Compare >
|
||||
backbone< Block_size, Iter_t, Compare >
|
||||
::backbone (Iter_t first, Iter_t last, Compare comp)
|
||||
: global_range (first, last), cmp (comp), error (false)
|
||||
{
|
||||
assert ((last - first) >= 0);
|
||||
if (first == last) return; // nothing to do
|
||||
|
||||
nelem = size_t (last - first);
|
||||
nblock = (nelem + Block_size - 1) / Block_size;
|
||||
ntail = (nelem % Block_size);
|
||||
index.reserve (nblock + 1);
|
||||
|
||||
for (size_t i = 0; i < nblock; ++i) index.emplace_back (block_pos (i));
|
||||
|
||||
range_tail.first =
|
||||
(ntail == 0) ? last : (first + ((nblock - 1) * Block_size));
|
||||
range_tail.last = last;
|
||||
};
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : exec
|
||||
/// @brief execute the function_t stored in works, until counter is zero
|
||||
//
|
||||
/// @param counter : atomic counter. When 0 exits the function
|
||||
//-------------------------------------------------------------------------
|
||||
template < uint32_t Block_size, class Iter_t, class Compare >
|
||||
void backbone< Block_size, Iter_t, Compare >::exec (atomic_t &counter)
|
||||
{
|
||||
function_t func_exec;
|
||||
while (bscu::atomic_read (counter) != 0)
|
||||
{
|
||||
if (works.pop_move_back (func_exec)) func_exec ( );
|
||||
else std::this_thread::yield ( );
|
||||
};
|
||||
};
|
||||
//
|
||||
//****************************************************************************
|
||||
}; // End namespace block_detail
|
||||
}; // End namespace parallel
|
||||
}; // End namespace sort
|
||||
}; // End namespace boost
|
||||
//****************************************************************************
|
||||
#endif
|
||||
@@ -1,183 +0,0 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file block.hpp
|
||||
/// @brief This file contains the internal data structures used in the
|
||||
/// block_indirect_sort algorithm
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __BOOST_SORT_PARALLEL_DETAIL_BLOCK_HPP
|
||||
#define __BOOST_SORT_PARALLEL_DETAIL_BLOCK_HPP
|
||||
|
||||
#include <boost/sort/common/range.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace sort
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
//---------------------------------------------------------------------------
|
||||
// USING SENTENCES
|
||||
//---------------------------------------------------------------------------
|
||||
using namespace boost::sort::common;
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
/// @struct block_pos
|
||||
/// @brief represent a pair of values, a position represented as an unsigned
|
||||
/// variable ( position ), and a bool variable ( side ). They are packed
|
||||
/// in a size_t variable. The Least Significant Bit is the bool variable,
|
||||
/// and the others bits are the position
|
||||
//----------------------------------------------------------------------------
|
||||
class block_pos
|
||||
{
|
||||
//------------------------------------------------------------------------
|
||||
// VARIABLES
|
||||
//-----------------------------------------------------------------------
|
||||
size_t num; // number which store a position and a bool side
|
||||
|
||||
public:
|
||||
//----------------------------- FUNCTIONS ------------------------------
|
||||
block_pos (void) : num (0){};
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : block_pos
|
||||
/// @brief constructor from a position and a side
|
||||
/// @param position : position to sotre
|
||||
/// @param side : side to store
|
||||
//-------------------------------------------------------------------------
|
||||
block_pos (size_t position, bool side = false)
|
||||
{
|
||||
num = (position << 1) + ((side) ? 1 : 0);
|
||||
};
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : pos
|
||||
/// @brief obtain the position stored inside the block_pos
|
||||
/// @return position
|
||||
//-------------------------------------------------------------------------
|
||||
size_t pos (void) const { return (num >> 1); };
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : pos
|
||||
/// @brief store a position inside the block_pos
|
||||
/// @param position : value to store
|
||||
//-------------------------------------------------------------------------
|
||||
void set_pos (size_t position) { num = (position << 1) + (num & 1); };
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : side
|
||||
/// @brief obtain the side stored inside the block_pos
|
||||
/// @return bool value
|
||||
//-------------------------------------------------------------------------
|
||||
bool side (void) const { return ((num & 1) != 0); };
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : side
|
||||
/// @brief store a bool value the block_pos
|
||||
/// @param sd : bool value to store
|
||||
//-------------------------------------------------------------------------
|
||||
void set_side (bool sd) { num = (num & ~1) + ((sd) ? 1 : 0); };
|
||||
}; // end struct block_pos
|
||||
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
/// @struct block
|
||||
/// @brief represent a group of Block_size contiguous elements, beginning
|
||||
/// with the pointed by first
|
||||
//----------------------------------------------------------------------------
|
||||
template < uint32_t Block_size, class Iter_t >
|
||||
struct block
|
||||
{
|
||||
//----------------------------------------------------------------------
|
||||
// VARIABLES
|
||||
//----------------------------------------------------------------------
|
||||
Iter_t first; // iterator to the first element of the block
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// function : block
|
||||
/// @brief constructor from an iterator to the first element of the block
|
||||
/// @param it : iterator to the first element of the block
|
||||
//-------------------------------------------------------------------------
|
||||
block (Iter_t it) : first (it){};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// function : get_range
|
||||
/// @brief convert a block in a range
|
||||
/// @return range
|
||||
//-------------------------------------------------------------------------
|
||||
range< Iter_t > get_range (void)
|
||||
{
|
||||
return range_it (first, first + Block_size);
|
||||
};
|
||||
|
||||
}; // end struct block
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : compare_block
|
||||
/// @brief compare two blocks using the content of the pointed by first
|
||||
/// @param block1 : first block to compare
|
||||
/// @param block2 : second block to compare
|
||||
/// @param cmp : comparison operator
|
||||
//-------------------------------------------------------------------------
|
||||
template < uint32_t Block_size, class Iter_t, class Compare >
|
||||
bool compare_block (block< Block_size, Iter_t > block1,
|
||||
block< Block_size, Iter_t > block2,
|
||||
Compare cmp = Compare ( ))
|
||||
{
|
||||
return cmp (*block1.first, *block2.first);
|
||||
};
|
||||
//
|
||||
///---------------------------------------------------------------------------
|
||||
/// @struct compare_block_pos
|
||||
/// @brief This is a object for to compare two block_pos objects
|
||||
//----------------------------------------------------------------------------
|
||||
template < uint32_t Block_size, class Iter_t, class Compare >
|
||||
struct compare_block_pos
|
||||
{
|
||||
//-----------------------------------------------------------------------
|
||||
// VARIABLES
|
||||
//-----------------------------------------------------------------------
|
||||
Iter_t global_first; // iterator to the first element to sort
|
||||
Compare comp; // comparison object for to compare two elements
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// function : compare_block_pos
|
||||
/// @brief constructor
|
||||
/// @param g_first : itertor to the first element to sort
|
||||
/// @param cmp : comparison operator
|
||||
//-------------------------------------------------------------------------
|
||||
compare_block_pos (Iter_t g_first, Compare cmp)
|
||||
: global_first (g_first), comp (cmp){};
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : operator ()
|
||||
/// @brief compare two blocks using the content of the pointed by
|
||||
/// global_first
|
||||
/// @param block_pos1 : first block to compare
|
||||
/// @param block_pos2 : second block to compare
|
||||
//-------------------------------------------------------------------------
|
||||
bool operator( ) (block_pos block_pos1, block_pos block_pos2) const
|
||||
{
|
||||
return comp (*(global_first + (block_pos1.pos ( ) * Block_size)),
|
||||
*(global_first + (block_pos2.pos ( ) * Block_size)));
|
||||
};
|
||||
|
||||
}; // end struct compare_block_pos
|
||||
|
||||
//****************************************************************************
|
||||
}; // End namespace block_detail
|
||||
}; // End namespace parallel
|
||||
}; // End namespace sort
|
||||
}; // End namespace boost
|
||||
//****************************************************************************
|
||||
//
|
||||
#endif
|
||||
@@ -1,26 +0,0 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file constants.hpp
|
||||
/// @brief This file contains the constants values used in the algorithms
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco José Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __BOOST_SORT_PARALLEL_DETAIL_CONSTANTS_HPP
|
||||
#define __BOOST_SORT_PARALLEL_DETAIL_CONSTANTS_HPP
|
||||
|
||||
// This value is the block size in the block_indirect_sort algorithm
|
||||
#define BOOST_BLOCK_SIZE 1024
|
||||
|
||||
// This value represent the group size in the block_indirect_sort algorithm
|
||||
#define BOOST_GROUP_SIZE 64
|
||||
|
||||
// This value is the minimal number of threads for to use the
|
||||
// block_indirect_sort algorithm
|
||||
#define BOOST_NTHREAD_BORDER 6
|
||||
|
||||
#endif
|
||||
@@ -1,429 +0,0 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file merge_blocks.hpp
|
||||
/// @brief contains the class merge_blocks, which is part of the
|
||||
/// block_indirect_sort algorithm
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __BOOST_SORT_PARALLEL_DETAIL_MERGE_BLOCKS_HPP
|
||||
#define __BOOST_SORT_PARALLEL_DETAIL_MERGE_BLOCKS_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <boost/sort/parallel/detail/backbone.hpp>
|
||||
#include <boost/sort/common/range.hpp>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace sort
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
//----------------------------------------------------------------------------
|
||||
// USING SENTENCES
|
||||
//----------------------------------------------------------------------------
|
||||
namespace bsc = boost::sort::common;
|
||||
namespace bscu = bsc::util;
|
||||
using bsc::range;
|
||||
using bsc::is_mergeable;
|
||||
using bsc::merge_uncontiguous;
|
||||
//
|
||||
///---------------------------------------------------------------------------
|
||||
/// @struct merge_blocks
|
||||
/// @brief This class merge the blocks. The blocks to merge are defined by two
|
||||
/// ranges of positions in the index of the backbone
|
||||
//----------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
struct merge_blocks
|
||||
{
|
||||
//-----------------------------------------------------------------------
|
||||
// D E F I N I T I O N S
|
||||
//-----------------------------------------------------------------------
|
||||
typedef typename std::iterator_traits<Iter_t>::value_type value_t;
|
||||
typedef std::atomic<uint32_t> atomic_t;
|
||||
typedef range<size_t> range_pos;
|
||||
typedef range<Iter_t> range_it;
|
||||
typedef range<value_t *> range_buf;
|
||||
typedef std::function<void(void)> function_t;
|
||||
typedef backbone<Block_size, Iter_t, Compare> backbone_t;
|
||||
typedef compare_block_pos<Block_size, Iter_t, Compare> compare_block_pos_t;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// V A R I A B L E S
|
||||
//------------------------------------------------------------------------
|
||||
// Object with the elements to sort and all internal data structures of the
|
||||
// algorithm
|
||||
backbone_t &bk;
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// F U N C T I O N S
|
||||
//------------------------------------------------------------------------
|
||||
merge_blocks(backbone_t &bkb, size_t pos_index1, size_t pos_index2,
|
||||
size_t pos_index3);
|
||||
|
||||
void tail_process(std::vector<block_pos> &vblkpos1,
|
||||
std::vector<block_pos> &vblkpos2);
|
||||
|
||||
void cut_range(range_pos rng);
|
||||
|
||||
void merge_range_pos(range_pos rng);
|
||||
|
||||
void extract_ranges(range_pos range_input);
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// function : function_merge_range_pos
|
||||
/// @brief create a function_t with a call to merge_range_pos, and insert
|
||||
/// in the stack of the backbone
|
||||
//
|
||||
/// @param rng_input : range of positions of blocks in the index to merge
|
||||
/// @param son_counter : atomic variable which is decremented when finish
|
||||
/// the function. This variable is used for to know
|
||||
/// when are finished all the function_t created
|
||||
/// inside an object
|
||||
/// @param error : global indicator of error.
|
||||
///
|
||||
//------------------------------------------------------------------------
|
||||
void function_merge_range_pos(const range_pos &rng_input, atomic_t &counter,
|
||||
bool &error)
|
||||
{
|
||||
bscu::atomic_add(counter, 1);
|
||||
function_t f1 = [this, rng_input, &counter, &error]( ) -> void
|
||||
{
|
||||
if (not error)
|
||||
{
|
||||
try
|
||||
{
|
||||
this->merge_range_pos (rng_input);
|
||||
}
|
||||
catch (std::bad_alloc &ba)
|
||||
{
|
||||
error = true;
|
||||
};
|
||||
}
|
||||
bscu::atomic_sub (counter, 1);
|
||||
};
|
||||
bk.works.emplace_back(f1);
|
||||
}
|
||||
;
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// function : function_cut_range
|
||||
/// @brief create a function_t with a call to cut_range, and inser in
|
||||
/// the stack of the backbone
|
||||
//
|
||||
/// @param rng_input : range of positions in the index to cut
|
||||
/// @param counter : atomic variable which is decremented when finish
|
||||
/// the function. This variable is used for to know
|
||||
/// when are finished all the function_t created
|
||||
/// inside an object
|
||||
/// @param error : global indicator of error.
|
||||
//------------------------------------------------------------------------
|
||||
void function_cut_range(const range_pos &rng_input, atomic_t &counter,
|
||||
bool &error)
|
||||
{
|
||||
bscu::atomic_add(counter, 1);
|
||||
function_t f1 = [this, rng_input, &counter, &error]( ) -> void
|
||||
{
|
||||
if (not error)
|
||||
{
|
||||
try
|
||||
{
|
||||
this->cut_range (rng_input);
|
||||
}
|
||||
catch (std::bad_alloc &)
|
||||
{
|
||||
error = true;
|
||||
};
|
||||
}
|
||||
bscu::atomic_sub (counter, 1);
|
||||
};
|
||||
bk.works.emplace_back(f1);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
};
|
||||
// end struct merge_blocks
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
//############################################################################
|
||||
// ##
|
||||
// ##
|
||||
// N O N I N L I N E F U N C T I O N S ##
|
||||
// ##
|
||||
// ##
|
||||
//############################################################################
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : merge_blocks
|
||||
/// @brief make the indirect merge of the two range_pos defined by their index
|
||||
/// position [pos_index1, pos_index2 ) and [ pos_index2, pos_index3 )
|
||||
//
|
||||
/// @param bkb : backbone with all the data to sort , and the internal data
|
||||
/// structures of the algorithm
|
||||
/// @param pos_index1 : first position of the first range in the index
|
||||
/// @param pos_index2 : last position of the first range and first position
|
||||
/// of the second range in the index
|
||||
/// @param pos_index3 : last position of the second range in the index
|
||||
//-------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
merge_blocks<Block_size, Group_size, Iter_t, Compare>
|
||||
::merge_blocks( backbone_t &bkb, size_t pos_index1, size_t pos_index2,
|
||||
size_t pos_index3) : bk(bkb)
|
||||
{
|
||||
size_t nblock1 = pos_index2 - pos_index1;
|
||||
size_t nblock2 = pos_index3 - pos_index2;
|
||||
if (nblock1 == 0 or nblock2 == 0) return;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Merging of the two intervals
|
||||
//-----------------------------------------------------------------------
|
||||
std::vector<block_pos> vpos1, vpos2;
|
||||
vpos1.reserve(nblock1 + 1);
|
||||
vpos2.reserve(nblock2 + 1);
|
||||
|
||||
for (size_t i = pos_index1; i < pos_index2; ++i)
|
||||
{
|
||||
vpos1.emplace_back(bk.index[i].pos(), true);
|
||||
};
|
||||
|
||||
for (size_t i = pos_index2; i < pos_index3; ++i)
|
||||
{
|
||||
vpos2.emplace_back(bk.index[i].pos(), false);
|
||||
};
|
||||
//-------------------------------------------------------------------
|
||||
// tail process
|
||||
//-------------------------------------------------------------------
|
||||
if (vpos2.back().pos() == (bk.nblock - 1)
|
||||
and bk.range_tail.first != bk.range_tail.last)
|
||||
{
|
||||
tail_process(vpos1, vpos2);
|
||||
nblock1 = vpos1.size();
|
||||
nblock2 = vpos2.size();
|
||||
};
|
||||
|
||||
compare_block_pos_t cmp_blk(bk.global_range.first, bk.cmp);
|
||||
if (bk.error) return;
|
||||
bscu::merge(vpos1.begin(), vpos1.end(), vpos2.begin(), vpos2.end(),
|
||||
bk.index.begin() + pos_index1, cmp_blk);
|
||||
if (bk.error) return;
|
||||
// Extracting the ranges for to merge the elements
|
||||
extract_ranges(range_pos(pos_index1, pos_index1 + nblock1 + nblock2));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : tail_process
|
||||
/// @brief make the process when the second vector of block_pos to merge is
|
||||
/// the last, and have an incomplete block ( tail)
|
||||
//
|
||||
/// @param vblkpos1 : first vector of block_pos elements to merge
|
||||
/// @param vblkpos2 : second vector of block_pos elements to merge
|
||||
//-------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
void merge_blocks<Block_size, Group_size, Iter_t, Compare>
|
||||
::tail_process( std::vector<block_pos> &vblkpos1,
|
||||
std::vector<block_pos> &vblkpos2 )
|
||||
{
|
||||
if (vblkpos1.size() == 0 or vblkpos2.size() == 0) return;
|
||||
|
||||
vblkpos2.pop_back();
|
||||
|
||||
size_t posback1 = vblkpos1.back().pos();
|
||||
range_it range_back1 = bk.get_range(posback1);
|
||||
|
||||
if (bsc::is_mergeable(range_back1, bk.range_tail, bk.cmp))
|
||||
{
|
||||
bsc::merge_uncontiguous(range_back1, bk.range_tail, bk.get_range_buf(),
|
||||
bk.cmp);
|
||||
if (vblkpos1.size() > 1)
|
||||
{
|
||||
size_t pos_aux = vblkpos1[vblkpos1.size() - 2].pos();
|
||||
range_it range_aux = bk.get_range(pos_aux);
|
||||
|
||||
if (bsc::is_mergeable(range_aux, range_back1, bk.cmp))
|
||||
{
|
||||
vblkpos2.emplace_back(posback1, false);
|
||||
vblkpos1.pop_back();
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : cut_range
|
||||
/// @brief when the rng_input is greather than Group_size, this function divide
|
||||
/// it in several parts creating function_t elements, which are inserted
|
||||
/// in the concurrent stack of the backbone
|
||||
//
|
||||
/// @param rng_input : range to divide
|
||||
//-------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
void merge_blocks<Block_size, Group_size, Iter_t, Compare>
|
||||
::cut_range(range_pos rng_input)
|
||||
{
|
||||
if (rng_input.size() < Group_size)
|
||||
{
|
||||
merge_range_pos(rng_input);
|
||||
return;
|
||||
};
|
||||
|
||||
atomic_t counter(0);
|
||||
size_t npart = (rng_input.size() + Group_size - 1) / Group_size;
|
||||
size_t size_part = rng_input.size() / npart;
|
||||
|
||||
size_t pos_ini = rng_input.first;
|
||||
size_t pos_last = rng_input.last;
|
||||
|
||||
while (pos_ini < pos_last)
|
||||
{
|
||||
size_t pos = pos_ini + size_part;
|
||||
while (pos < pos_last
|
||||
and bk.index[pos - 1].side() == bk.index[pos].side())
|
||||
{
|
||||
++pos;
|
||||
};
|
||||
if (pos < pos_last)
|
||||
{
|
||||
merge_uncontiguous(bk.get_range(bk.index[pos - 1].pos()),
|
||||
bk.get_range(bk.index[pos].pos()),
|
||||
bk.get_range_buf(), bk.cmp);
|
||||
}
|
||||
else pos = pos_last;
|
||||
if ((pos - pos_ini) > 1)
|
||||
{
|
||||
range_pos rng_aux(pos_ini, pos);
|
||||
function_merge_range_pos(rng_aux, counter, bk.error);
|
||||
};
|
||||
pos_ini = pos;
|
||||
};
|
||||
bk.exec(counter); // wait until finish all the ranges
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : merge_range_pos
|
||||
/// @brief make the indirect merge of the blocks inside the rng_input
|
||||
//
|
||||
/// @param rng_input : range of positions of the blocks to merge
|
||||
//-------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
void merge_blocks<Block_size, Group_size, Iter_t, Compare>
|
||||
::merge_range_pos(range_pos rng_input)
|
||||
{
|
||||
if (rng_input.size() < 2) return;
|
||||
range_buf rbuf = bk.get_range_buf();
|
||||
|
||||
range_it rng_prev = bk.get_range(bk.index[rng_input.first].pos());
|
||||
move_forward(rbuf, rng_prev);
|
||||
range_it rng_posx(rng_prev);
|
||||
|
||||
for (size_t posx = rng_input.first + 1; posx != rng_input.last; ++posx)
|
||||
{
|
||||
rng_posx = bk.get_range(bk.index[posx].pos());
|
||||
bsc::merge_flow(rng_prev, rbuf, rng_posx, bk.cmp);
|
||||
rng_prev = rng_posx;
|
||||
|
||||
};
|
||||
move_forward(rng_posx, rbuf);
|
||||
}
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : extract_ranges
|
||||
/// @brief from a big range of positions of blocks in the index. Examine which
|
||||
/// are mergeable, and generate a couple of ranges for to be merged.
|
||||
/// With the ranges obtained generate function_t elements and are
|
||||
/// inserted in the concurrent stack.
|
||||
/// When the range obtained is smaller than Group_size, generate a
|
||||
/// function_t calling to merge_range_pos, when is greater, generate a
|
||||
/// function_t calling to cut_range
|
||||
//
|
||||
/// @param rpos range_input : range of the position in the index, where must
|
||||
/// extract the ranges to merge
|
||||
//-------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
void merge_blocks<Block_size, Group_size, Iter_t, Compare>
|
||||
::extract_ranges(range_pos range_input)
|
||||
{
|
||||
if (range_input.size() < 2) return;
|
||||
atomic_t counter(0);
|
||||
|
||||
// The names with x are positions of the index
|
||||
size_t posx_ini = range_input.first;
|
||||
block_pos bp_posx_ini = bk.index[posx_ini];
|
||||
|
||||
range_it rng_max = bk.get_range(bp_posx_ini.pos());
|
||||
bool side_max = bp_posx_ini.side();
|
||||
|
||||
block_pos bp_posx;
|
||||
range_it rng_posx = rng_max;
|
||||
bool side_posx = side_max;
|
||||
|
||||
for (size_t posx = posx_ini + 1; posx <= range_input.last; ++posx)
|
||||
{
|
||||
bool final = (posx == range_input.last);
|
||||
bool mergeable = false;
|
||||
|
||||
if (not final)
|
||||
{
|
||||
bp_posx = bk.index[posx];
|
||||
rng_posx = bk.get_range(bp_posx.pos());
|
||||
side_posx = bp_posx.side();
|
||||
mergeable = (side_max != side_posx
|
||||
and is_mergeable(rng_max, rng_posx, bk.cmp));
|
||||
};
|
||||
if (bk.error) return;
|
||||
if (final or not mergeable)
|
||||
{
|
||||
range_pos rp_final(posx_ini, posx);
|
||||
if (rp_final.size() > 1)
|
||||
{
|
||||
if (rp_final.size() > Group_size)
|
||||
{
|
||||
function_cut_range(rp_final, counter, bk.error);
|
||||
}
|
||||
else
|
||||
{
|
||||
function_merge_range_pos(rp_final, counter, bk.error);
|
||||
};
|
||||
};
|
||||
posx_ini = posx;
|
||||
if (not final)
|
||||
{
|
||||
rng_max = rng_posx;
|
||||
side_max = side_posx;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bk.cmp(*(rng_max.back()), *(rng_posx.back())))
|
||||
{
|
||||
rng_max = rng_posx;
|
||||
side_max = side_posx;
|
||||
};
|
||||
};
|
||||
};
|
||||
bk.exec(counter);
|
||||
}
|
||||
//
|
||||
//****************************************************************************
|
||||
}; // End namespace block_detail
|
||||
}; // End namespace parallel
|
||||
}; // End namespace sort
|
||||
}; // End namespace boost
|
||||
//****************************************************************************
|
||||
//
|
||||
#endif
|
||||
@@ -1,287 +0,0 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file move_blocks.hpp
|
||||
/// @brief contains the class move_blocks, which is part of the
|
||||
/// block_indirect_sort algorithm
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __BOOST_SORT_PARALLEL_DETAIL_MOVE_BLOCKS_HPP
|
||||
#define __BOOST_SORT_PARALLEL_DETAIL_MOVE_BLOCKS_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <boost/sort/parallel/detail/backbone.hpp>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace sort
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
//----------------------------------------------------------------------------
|
||||
// USING SENTENCES
|
||||
//----------------------------------------------------------------------------
|
||||
namespace bsc = boost::sort::common;
|
||||
//
|
||||
///---------------------------------------------------------------------------
|
||||
/// @struct move_blocks
|
||||
/// @brief This class move the blocks, trnasforming a logical sort by an index,
|
||||
/// in physical sort
|
||||
//----------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
struct move_blocks
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
// D E F I N I T I O N S
|
||||
//-------------------------------------------------------------------------
|
||||
typedef move_blocks<Block_size, Group_size, Iter_t, Compare> this_type;
|
||||
typedef typename std::iterator_traits<Iter_t>::value_type value_t;
|
||||
typedef std::atomic<uint32_t> atomic_t;
|
||||
typedef bsc::range<size_t> range_pos;
|
||||
typedef bsc::range<Iter_t> range_it;
|
||||
typedef bsc::range<value_t *> range_buf;
|
||||
typedef std::function<void(void)> function_t;
|
||||
typedef backbone<Block_size, Iter_t, Compare> backbone_t;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// V A R I A B L E S
|
||||
//------------------------------------------------------------------------
|
||||
// Object with the elements to sort and all internal data structures of the
|
||||
// algorithm
|
||||
backbone_t &bk;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// F U N C T I O N S
|
||||
//------------------------------------------------------------------------
|
||||
move_blocks(backbone_t &bkb);
|
||||
|
||||
void move_sequence(const std::vector<size_t> &init_sequence);
|
||||
|
||||
void move_long_sequence(const std::vector<size_t> &init_sequence);
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// function : function_move_sequence
|
||||
/// @brief create a function_t with a call to move_sequence, and insert
|
||||
/// in the stack of the backbone
|
||||
///
|
||||
/// @param sequence :sequence of positions for to move the blocks
|
||||
/// @param counter : atomic variable which is decremented when finish
|
||||
/// the function. This variable is used for to know
|
||||
/// when are finished all the function_t created
|
||||
/// inside an object
|
||||
/// @param error : global indicator of error.
|
||||
//------------------------------------------------------------------------
|
||||
void function_move_sequence(std::vector<size_t> &sequence,
|
||||
atomic_t &counter, bool &error)
|
||||
{
|
||||
bscu::atomic_add(counter, 1);
|
||||
function_t f1 = [this, sequence, &counter, &error]( ) -> void
|
||||
{
|
||||
if (not error)
|
||||
{
|
||||
try
|
||||
{
|
||||
this->move_sequence (sequence);
|
||||
}
|
||||
catch (std::bad_alloc &)
|
||||
{
|
||||
error = true;
|
||||
};
|
||||
}
|
||||
bscu::atomic_sub (counter, 1);
|
||||
};
|
||||
bk.works.emplace_back(f1);
|
||||
}
|
||||
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// function : function_move_long_sequence
|
||||
/// @brief create a function_t with a call to move_long_sequence, and
|
||||
/// insert in the stack of the backbone
|
||||
//
|
||||
/// @param sequence :sequence of positions for to move the blocks
|
||||
/// @param counter : atomic variable which is decremented when finish
|
||||
/// the function. This variable is used for to know
|
||||
/// when are finished all the function_t created
|
||||
/// inside an object
|
||||
/// @param error : global indicator of error.
|
||||
//------------------------------------------------------------------------
|
||||
void function_move_long_sequence(std::vector<size_t> &sequence,
|
||||
atomic_t &counter, bool &error)
|
||||
{
|
||||
bscu::atomic_add(counter, 1);
|
||||
function_t f1 = [this, sequence, &counter, &error]( ) -> void
|
||||
{
|
||||
if (not error)
|
||||
{
|
||||
try
|
||||
{
|
||||
this->move_long_sequence (sequence);
|
||||
}
|
||||
catch (std::bad_alloc &)
|
||||
{
|
||||
error = true;
|
||||
};
|
||||
}
|
||||
bscu::atomic_sub (counter, 1);
|
||||
};
|
||||
bk.works.emplace_back(f1);
|
||||
}
|
||||
;
|
||||
//---------------------------------------------------------------------------
|
||||
}; // end of struct move_blocks
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//############################################################################
|
||||
// ##
|
||||
// ##
|
||||
// N O N I N L I N E F U N C T I O N S ##
|
||||
// ##
|
||||
// ##
|
||||
//############################################################################
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : move_blocks
|
||||
/// @brief constructor of the class for to move the blocks to their true
|
||||
/// position obtained from the index
|
||||
//
|
||||
/// @param bkb : backbone with the index and the blocks
|
||||
//-------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
move_blocks<Block_size, Group_size, Iter_t, Compare>
|
||||
::move_blocks(backbone_t &bkb) : bk(bkb)
|
||||
{
|
||||
std::vector<std::vector<size_t> > vsequence;
|
||||
vsequence.reserve(bk.index.size() >> 1);
|
||||
std::vector<size_t> sequence;
|
||||
atomic_t counter(0);
|
||||
|
||||
size_t pos_index_ini = 0, pos_index_src = 0, pos_index_dest = 0;
|
||||
while (pos_index_ini < bk.index.size())
|
||||
{
|
||||
while (pos_index_ini < bk.index.size()
|
||||
and bk.index[pos_index_ini].pos() == pos_index_ini)
|
||||
{
|
||||
++pos_index_ini;
|
||||
};
|
||||
|
||||
if (pos_index_ini == bk.index.size()) break;
|
||||
|
||||
sequence.clear();
|
||||
pos_index_src = pos_index_dest = pos_index_ini;
|
||||
sequence.push_back(pos_index_ini);
|
||||
|
||||
while (bk.index[pos_index_dest].pos() != pos_index_ini)
|
||||
{
|
||||
pos_index_src = bk.index[pos_index_dest].pos();
|
||||
sequence.push_back(pos_index_src);
|
||||
|
||||
bk.index[pos_index_dest].set_pos(pos_index_dest);
|
||||
pos_index_dest = pos_index_src;
|
||||
};
|
||||
|
||||
bk.index[pos_index_dest].set_pos(pos_index_dest);
|
||||
vsequence.push_back(sequence);
|
||||
|
||||
if (sequence.size() < Group_size)
|
||||
{
|
||||
function_move_sequence(vsequence.back(), counter, bk.error);
|
||||
}
|
||||
else
|
||||
{
|
||||
function_move_long_sequence(vsequence.back(), counter, bk.error);
|
||||
};
|
||||
};
|
||||
bk.exec(counter);
|
||||
}
|
||||
;
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : move_sequence
|
||||
/// @brief move the blocks, following the positions of the init_sequence
|
||||
//
|
||||
/// @param init_sequence : vector with the positions from and where move the
|
||||
/// blocks
|
||||
//-------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
void move_blocks<Block_size, Group_size, Iter_t, Compare>
|
||||
::move_sequence(const std::vector<size_t> &init_sequence)
|
||||
{
|
||||
range_buf rbuf = bk.get_range_buf();
|
||||
size_t pos_range2 = init_sequence[0];
|
||||
|
||||
range_it range2 = bk.get_range(pos_range2);
|
||||
move_forward(rbuf, range2);
|
||||
|
||||
for (size_t i = 1; i < init_sequence.size(); ++i)
|
||||
{
|
||||
pos_range2 = init_sequence[i];
|
||||
range_it range1(range2);
|
||||
range2 = bk.get_range(pos_range2);
|
||||
move_forward(range1, range2);
|
||||
};
|
||||
move_forward(range2, rbuf);
|
||||
};
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// function : move_long_sequence
|
||||
/// @brief move the blocks, following the positions of the init_sequence.
|
||||
/// if the sequence is greater than Group_size, it is divided in small
|
||||
/// sequences, creating function_t elements, for to be inserted in the
|
||||
/// concurrent stack
|
||||
//
|
||||
/// @param init_sequence : vector with the positions from and where move the
|
||||
/// blocks
|
||||
//-------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, uint32_t Group_size, class Iter_t, class Compare>
|
||||
void move_blocks<Block_size, Group_size, Iter_t, Compare>
|
||||
::move_long_sequence(const std::vector<size_t> &init_sequence)
|
||||
{
|
||||
if (init_sequence.size() < Group_size) return move_sequence(init_sequence);
|
||||
|
||||
size_t npart = (init_sequence.size() + Group_size - 1) / Group_size;
|
||||
size_t size_part = init_sequence.size() / npart;
|
||||
atomic_t son_counter(0);
|
||||
|
||||
std::vector<size_t> sequence;
|
||||
sequence.reserve(size_part);
|
||||
|
||||
std::vector<size_t> index_seq;
|
||||
index_seq.reserve(npart);
|
||||
|
||||
auto it_pos = init_sequence.begin();
|
||||
for (size_t i = 0; i < (npart - 1); ++i, it_pos += size_part)
|
||||
{
|
||||
sequence.assign(it_pos, it_pos + size_part);
|
||||
index_seq.emplace_back(*(it_pos + size_part - 1));
|
||||
function_move_sequence(sequence, son_counter, bk.error);
|
||||
};
|
||||
|
||||
sequence.assign(it_pos, init_sequence.end());
|
||||
index_seq.emplace_back(init_sequence.back());
|
||||
function_move_sequence(sequence, son_counter, bk.error);
|
||||
|
||||
bk.exec(son_counter);
|
||||
if (bk.error) return;
|
||||
move_long_sequence(index_seq);
|
||||
}
|
||||
|
||||
//
|
||||
//****************************************************************************
|
||||
}; // End namespace block_detail
|
||||
}; // End namespace parallel
|
||||
}; // End namespace sort
|
||||
}; // End namespace boost
|
||||
//****************************************************************************
|
||||
//
|
||||
#endif
|
||||
@@ -1,239 +0,0 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file parallel_sort.hpp
|
||||
/// @brief Contains the parallel_sort class, which is part of the
|
||||
/// block_indirect_sort algorithm
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __BOOST_SORT_PARALLEL_DETAIL_PARALLEL_SORT_HPP
|
||||
#define __BOOST_SORT_PARALLEL_DETAIL_PARALLEL_SORT_HPP
|
||||
|
||||
#include <boost/sort/parallel/detail/backbone.hpp>
|
||||
#include <boost/sort/pdqsort/pdqsort.h>
|
||||
#include <boost/sort/common/pivot.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace sort
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// USING SENTENCES
|
||||
//----------------------------------------------------------------------------
|
||||
namespace bsc = boost::sort::common;
|
||||
namespace bscu = bsc::util;
|
||||
using bscu::nbits64;
|
||||
using bsc::pivot9;
|
||||
using boost::sort::pdqsort;
|
||||
//
|
||||
///---------------------------------------------------------------------------
|
||||
/// @struct parallel_sort
|
||||
/// @brief This class do a parallel sort, using the quicksort filtering,
|
||||
/// splitting the data until the number of elements is smaller than a
|
||||
/// predefined value (max_per_thread)
|
||||
//----------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, class Iter_t, class Compare>
|
||||
struct parallel_sort
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
// D E F I N I T I O N S
|
||||
//-------------------------------------------------------------------------
|
||||
typedef typename std::iterator_traits<Iter_t>::value_type value_t;
|
||||
typedef std::atomic<uint32_t> atomic_t;
|
||||
typedef std::function<void(void)> function_t;
|
||||
typedef backbone<Block_size, Iter_t, Compare> backbone_t;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// V A R I A B L E S
|
||||
//------------------------------------------------------------------------
|
||||
// reference to a object with all the data to sort
|
||||
backbone_t &bk;
|
||||
|
||||
// maximun number of element to sort woth 1 thread
|
||||
size_t max_per_thread;
|
||||
|
||||
// atomic counter for to detect the end of the works created inside
|
||||
// the object
|
||||
atomic_t counter;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// F U N C T I O N S
|
||||
//------------------------------------------------------------------------
|
||||
parallel_sort(backbone_t &bkbn, Iter_t first, Iter_t last);
|
||||
|
||||
void divide_sort(Iter_t first, Iter_t last, uint32_t level);
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// function : function_divide_sort
|
||||
/// @brief create a function_t with a call to divide_sort, and inser in
|
||||
/// the stack of the backbone
|
||||
//
|
||||
/// @param first : iterator to the first element of the range to divide
|
||||
/// @param last : iterator to the next element after the last element of
|
||||
/// the range to divide
|
||||
/// @param level : level of depth in the division.When zero call to
|
||||
/// pdqsort
|
||||
/// @param counter : atomic variable which is decremented when finish
|
||||
/// the function. This variable is used for to know
|
||||
/// when are finished all the function_t created
|
||||
/// inside an object
|
||||
/// @param error : global indicator of error.
|
||||
//------------------------------------------------------------------------
|
||||
void function_divide_sort(Iter_t first, Iter_t last, uint32_t level,
|
||||
atomic_t &counter, bool &error)
|
||||
{
|
||||
bscu::atomic_add(counter, 1);
|
||||
function_t f1 = [this, first, last, level, &counter, &error]( )
|
||||
{
|
||||
if (not error)
|
||||
{
|
||||
try
|
||||
{
|
||||
this->divide_sort (first, last, level);
|
||||
}
|
||||
catch (std::bad_alloc &)
|
||||
{
|
||||
error = true;
|
||||
};
|
||||
};
|
||||
bscu::atomic_sub (counter, 1);
|
||||
};
|
||||
bk.works.emplace_back(f1);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
};// end struct parallel_sort
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
//############################################################################
|
||||
// ##
|
||||
// ##
|
||||
// N O N I N L I N E F U N C T I O N S ##
|
||||
// ##
|
||||
// ##
|
||||
//############################################################################
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// function : parallel_sort
|
||||
/// @brief constructor of the class
|
||||
/// @param [in] bkbn : backbone struct with all the information to sort
|
||||
/// @param [in] first : iterator to the first element to sort
|
||||
/// @param [in] last : iterator to the next element after the last
|
||||
//------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, class Iter_t, class Compare>
|
||||
parallel_sort<Block_size, Iter_t, Compare>
|
||||
::parallel_sort(backbone_t &bkbn, Iter_t first, Iter_t last)
|
||||
: bk(bkbn), counter(0)
|
||||
{
|
||||
assert((last - first) >= 0);
|
||||
size_t nelem = size_t(last - first);
|
||||
|
||||
//------------------- check if sort --------------------------------------
|
||||
bool sorted = true;
|
||||
for (Iter_t it1 = first, it2 = first + 1;
|
||||
it2 != last and (sorted = not bk.cmp(*it2, *it1)); it1 = it2++);
|
||||
if (sorted) return;
|
||||
|
||||
//------------------- check if reverse sort ---------------------------
|
||||
sorted = true;
|
||||
for (Iter_t it1 = first, it2 = first + 1;
|
||||
it2 != last and (sorted = not bk.cmp(*it1, *it2)); it1 = it2++);
|
||||
|
||||
if (sorted)
|
||||
{
|
||||
size_t nelem2 = nelem >> 1;
|
||||
Iter_t it1 = first, it2 = last - 1;
|
||||
for (size_t i = 0; i < nelem2; ++i)
|
||||
std::swap(*(it1++), *(it2--));
|
||||
return;
|
||||
};
|
||||
|
||||
//-------------------max_per_thread ---------------------------
|
||||
uint32_t nbits_size = (nbits64(sizeof(value_t))) >> 1;
|
||||
if (nbits_size > 5) nbits_size = 5;
|
||||
max_per_thread = 1 << (18 - nbits_size);
|
||||
|
||||
uint32_t level = ((nbits64(nelem / max_per_thread)) * 3) / 2;
|
||||
|
||||
//---------------- check if only single thread -----------------------
|
||||
if (nelem < (max_per_thread))
|
||||
{
|
||||
pdqsort(first, last, bk.cmp);
|
||||
return;
|
||||
};
|
||||
if (not bk.error) divide_sort(first, last, level);
|
||||
|
||||
// wait until all the parts are finished
|
||||
bk.exec(counter);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// function : divide_sort
|
||||
/// @brief this function divide the data in two part, for to be sorted in
|
||||
/// a parallel mode
|
||||
/// @param first : iterator to the first element to sort
|
||||
/// @param last : iterator to the next element after the last
|
||||
/// @param level : level of depth before call to pdqsort
|
||||
//------------------------------------------------------------------------
|
||||
template<uint32_t Block_size, class Iter_t, class Compare>
|
||||
void parallel_sort<Block_size, Iter_t, Compare>
|
||||
::divide_sort(Iter_t first, Iter_t last, uint32_t level)
|
||||
{
|
||||
//------------------- check if sort -----------------------------------
|
||||
bool sorted = true;
|
||||
for (Iter_t it1 = first, it2 = first + 1;
|
||||
it2 != last and (sorted = not bk.cmp(*it2, *it1)); it1 = it2++);
|
||||
if (sorted) return;
|
||||
|
||||
//---------------- check if finish the subdivision -------------------
|
||||
size_t nelem = last - first;
|
||||
if (level == 0 or nelem < (max_per_thread))
|
||||
{
|
||||
return pdqsort(first, last, bk.cmp);
|
||||
};
|
||||
|
||||
//-------------------- pivoting ----------------------------------
|
||||
pivot9(first, last, bk.cmp);
|
||||
const value_t &val = const_cast<value_t &>(*first);
|
||||
Iter_t c_first = first + 1, c_last = last - 1;
|
||||
|
||||
while (bk.cmp(*c_first, val)) ++c_first;
|
||||
while (bk.cmp(val, *c_last)) --c_last;
|
||||
|
||||
while (not (c_first > c_last))
|
||||
{
|
||||
std::swap(*(c_first++), *(c_last--));
|
||||
while (bk.cmp(*c_first, val))
|
||||
++c_first;
|
||||
while (bk.cmp(val, *c_last))
|
||||
--c_last;
|
||||
};
|
||||
|
||||
std::swap(*first, *c_last);
|
||||
|
||||
// insert the work of the second half in the stack of works
|
||||
function_divide_sort(c_first, last, level - 1, counter, bk.error);
|
||||
if (bk.error) return;
|
||||
|
||||
// The first half is done by the same thread
|
||||
function_divide_sort(first, c_last, level - 1, counter, bk.error);
|
||||
};
|
||||
//
|
||||
//****************************************************************************
|
||||
};// End namespace block_detail
|
||||
};// End namespace parallel
|
||||
};// End namespace sort
|
||||
};// End namespace boost
|
||||
//****************************************************************************
|
||||
//
|
||||
#endif
|
||||
@@ -1,273 +0,0 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file parallel_stable_sort.hpp
|
||||
/// @brief This file contains the class parallel_stable_sort
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __BOOST_SORT_PARALLEL_DETAIL_PARALLEL_STABLE_SORT_HPP
|
||||
#define __BOOST_SORT_PARALLEL_DETAIL_PARALLEL_STABLE_SORT_HPP
|
||||
|
||||
#include <boost/sort/parallel/sample_sort.hpp>
|
||||
#include <boost/sort/common/util/traits.hpp>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace sort
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
namespace stable_detail
|
||||
{
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// USING SENTENCES
|
||||
//---------------------------------------------------------------------------
|
||||
namespace bsc = boost::sort::common;
|
||||
namespace bss = boost::sort::spin_detail;
|
||||
using bsc::range;
|
||||
using bsc::merge_half;
|
||||
using boost::sort::parallel::sample_detail::sample_sort;
|
||||
//
|
||||
///---------------------------------------------------------------------------
|
||||
/// @struct parallel_stable_sort
|
||||
/// @brief This a structure for to implement a parallel stable sort, exception
|
||||
/// safe
|
||||
//----------------------------------------------------------------------------
|
||||
template <class Iter_t, class Compare = compare_iter <Iter_t> >
|
||||
struct parallel_stable_sort
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
// DEFINITIONS
|
||||
//-------------------------------------------------------------------------
|
||||
typedef value_iter<Iter_t> value_t;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// VARIABLES
|
||||
//-------------------------------------------------------------------------
|
||||
// Number of elements to sort
|
||||
size_t nelem;
|
||||
// Pointer to the auxiliary memory needed for the algorithm
|
||||
value_t *ptr;
|
||||
// Minimal number of elements for to be sorted in parallel mode
|
||||
const size_t nelem_min = 1 << 16;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// F U N C T I O N S
|
||||
//------------------------------------------------------------------------
|
||||
parallel_stable_sort (Iter_t first, Iter_t last)
|
||||
: parallel_stable_sort (first, last, Compare(),
|
||||
std::thread::hardware_concurrency()) { };
|
||||
|
||||
parallel_stable_sort (Iter_t first, Iter_t last, Compare cmp)
|
||||
: parallel_stable_sort (first, last, cmp,
|
||||
std::thread::hardware_concurrency()) { };
|
||||
|
||||
parallel_stable_sort (Iter_t first, Iter_t last, uint32_t num_thread)
|
||||
: parallel_stable_sort (first, last, Compare(), num_thread) { };
|
||||
|
||||
parallel_stable_sort (Iter_t first, Iter_t last, Compare cmp,
|
||||
uint32_t num_thread);
|
||||
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : destroy_all
|
||||
/// @brief The utility is to destroy the temporary buffer used in the
|
||||
/// sorting process
|
||||
//-----------------------------------------------------------------------------
|
||||
void destroy_all()
|
||||
{
|
||||
if (ptr != nullptr) std::return_temporary_buffer(ptr);
|
||||
};
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function :~parallel_stable_sort
|
||||
/// @brief destructor of the class. The utility is to destroy the temporary
|
||||
/// buffer used in the sorting process
|
||||
//-----------------------------------------------------------------------------
|
||||
~parallel_stable_sort() {destroy_all(); } ;
|
||||
};
|
||||
// end struct parallel_stable_sort
|
||||
|
||||
//
|
||||
//############################################################################
|
||||
// ##
|
||||
// ##
|
||||
// N O N I N L I N E F U N C T I O N S ##
|
||||
// ##
|
||||
// ##
|
||||
//############################################################################
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : parallel_stable_sort
|
||||
/// @brief constructor of the class
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
/// @param comp : object for to compare two elements pointed by Iter_t
|
||||
/// iterators
|
||||
/// @param nthread : Number of threads to use in the process. When this value
|
||||
/// is lower than 2, the sorting is done with 1 thread
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Iter_t, class Compare>
|
||||
parallel_stable_sort <Iter_t, Compare>
|
||||
::parallel_stable_sort (Iter_t first, Iter_t last, Compare comp,
|
||||
uint32_t nthread) : nelem(0), ptr(nullptr)
|
||||
{
|
||||
range<Iter_t> range_initial(first, last);
|
||||
assert(range_initial.valid());
|
||||
|
||||
nelem = range_initial.size();
|
||||
size_t nptr = (nelem + 1) >> 1;
|
||||
|
||||
if (nelem < nelem_min or nthread < 2)
|
||||
{
|
||||
bss::spinsort<Iter_t, Compare>
|
||||
(range_initial.first, range_initial.last, comp);
|
||||
return;
|
||||
};
|
||||
|
||||
//------------------- check if sort --------------------------------------
|
||||
bool sw = true;
|
||||
for (Iter_t it1 = first, it2 = first + 1;
|
||||
it2 != last and (sw = not comp(*it2, *it1)); it1 = it2++);
|
||||
if (sw) return;
|
||||
|
||||
//------------------- check if reverse sort ---------------------------
|
||||
sw = true;
|
||||
for (Iter_t it1 = first, it2 = first + 1;
|
||||
it2 != last and (sw = comp(*it2, *it1)); it1 = it2++);
|
||||
if (sw)
|
||||
{
|
||||
size_t nelem2 = nelem >> 1;
|
||||
Iter_t it1 = first, it2 = last - 1;
|
||||
for (size_t i = 0; i < nelem2; ++i)
|
||||
std::swap(*(it1++), *(it2--));
|
||||
return;
|
||||
};
|
||||
|
||||
ptr = std::get_temporary_buffer<value_t>(nptr).first;
|
||||
if (ptr == nullptr) throw std::bad_alloc();
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Parallel Process
|
||||
//---------------------------------------------------------------------
|
||||
range<Iter_t> range_first(range_initial.first, range_initial.first + nptr);
|
||||
|
||||
range<Iter_t> range_second(range_initial.first + nptr, range_initial.last);
|
||||
|
||||
range<value_t *> range_buffer(ptr, ptr + nptr);
|
||||
|
||||
try
|
||||
{
|
||||
sample_sort<Iter_t, Compare>
|
||||
(range_initial.first, range_initial.first + nptr,
|
||||
comp, nthread, range_buffer);
|
||||
} catch (std::bad_alloc &)
|
||||
{
|
||||
destroy_all();
|
||||
throw std::bad_alloc();
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
sample_sort<Iter_t, Compare>
|
||||
(range_initial.first + nptr,
|
||||
range_initial.last, comp, nthread, range_buffer);
|
||||
} catch (std::bad_alloc &)
|
||||
{
|
||||
destroy_all();
|
||||
throw std::bad_alloc();
|
||||
};
|
||||
|
||||
range_buffer = move_forward(range_buffer, range_first);
|
||||
range_initial = merge_half(range_initial, range_buffer, range_second, comp);
|
||||
}; // end of constructor
|
||||
|
||||
//
|
||||
//****************************************************************************
|
||||
};// End namespace stable_detail
|
||||
//****************************************************************************
|
||||
//
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// USING SENTENCES
|
||||
//---------------------------------------------------------------------------
|
||||
namespace bsc = boost::sort::common;
|
||||
namespace bscu = bsc::util;
|
||||
namespace bss = boost::sort::spin_detail;
|
||||
using bsc::range;
|
||||
using bsc::merge_half;
|
||||
//
|
||||
//############################################################################
|
||||
// ##
|
||||
// ##
|
||||
// P A R A L L E L _ S T A B L E _ S O R T ##
|
||||
// ##
|
||||
// ##
|
||||
//############################################################################
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : parallel_stable_sort
|
||||
/// @brief : parallel stable sort algorithm.
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Iter_t>
|
||||
void parallel_stable_sort(Iter_t first, Iter_t last)
|
||||
{
|
||||
typedef bscu::compare_iter<Iter_t> Compare;
|
||||
stable_detail::parallel_stable_sort<Iter_t, Compare>(first, last);
|
||||
};
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : parallel_stable_sort
|
||||
/// @brief parallel stable sort.
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
/// @param nthread : Number of threads to use in the process. When this value
|
||||
/// is lower than 2, the sorting is done with 1 thread
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Iter_t>
|
||||
void parallel_stable_sort(Iter_t first, Iter_t last, uint32_t nthread)
|
||||
{
|
||||
typedef bscu::compare_iter<Iter_t> Compare;
|
||||
stable_detail::parallel_stable_sort<Iter_t, Compare>(first, last, nthread);
|
||||
};
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : parallel_stable_sort
|
||||
/// @brief : parallel stable sort.
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
/// @param comp : object for to compare two elements pointed by Iter_t
|
||||
/// iterators
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class Iter_t, class Compare,
|
||||
bscu::enable_if_not_integral<Compare> * = nullptr>
|
||||
void parallel_stable_sort(Iter_t first, Iter_t last, Compare comp)
|
||||
{
|
||||
stable_detail::parallel_stable_sort<Iter_t, Compare>(first, last, comp);
|
||||
};
|
||||
//
|
||||
//****************************************************************************
|
||||
};// End namespace parallel
|
||||
};// End namespace sort
|
||||
};// End namespace boost
|
||||
//****************************************************************************
|
||||
//
|
||||
#endif
|
||||
@@ -1,563 +0,0 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file sample_sort.hpp
|
||||
/// @brief contains the class sample_sort
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __BOOST_SORT_PARALLEL_DETAIL_SAMPLE_SORT_HPP
|
||||
#define __BOOST_SORT_PARALLEL_DETAIL_SAMPLE_SORT_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/sort/spinsort/spinsort.hpp>
|
||||
#include <boost/sort/common/indirect.hpp>
|
||||
#include <boost/sort/common/util/atomic.hpp>
|
||||
#include <boost/sort/common/merge_four.hpp>
|
||||
#include <boost/sort/common/merge_vector.hpp>
|
||||
#include <boost/sort/common/range.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace sort
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
namespace sample_detail
|
||||
{
|
||||
//---------------------------------------------------------------------------
|
||||
// USING SENTENCES
|
||||
//---------------------------------------------------------------------------
|
||||
namespace bsc = boost::sort::common;
|
||||
namespace bss = boost::sort::spin_detail;
|
||||
namespace bscu = boost::sort::common::util;
|
||||
using bsc::range;
|
||||
using bscu::atomic_add;
|
||||
using bsc::merge_vector4;
|
||||
using bsc::uninit_merge_level4;
|
||||
using bsc::less_ptr_no_null;
|
||||
|
||||
//
|
||||
///---------------------------------------------------------------------------
|
||||
/// @struct sample_sort
|
||||
/// @brief This a structure for to implement a sample sort, exception
|
||||
/// safe
|
||||
/// @tparam
|
||||
/// @remarks
|
||||
//----------------------------------------------------------------------------
|
||||
template<class Iter_t, class Compare>
|
||||
struct sample_sort
|
||||
{
|
||||
//------------------------------------------------------------------------
|
||||
// DEFINITIONS
|
||||
//------------------------------------------------------------------------
|
||||
typedef value_iter<Iter_t> value_t;
|
||||
typedef range<Iter_t> range_it;
|
||||
typedef range<value_t *> range_buf;
|
||||
typedef sample_sort<Iter_t, Compare> this_t;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// VARIABLES AND CONSTANTS
|
||||
//------------------------------------------------------------------------
|
||||
// minimun numbers of elements for to be sortd in parallel mode
|
||||
static const uint32_t thread_min = (1 << 16);
|
||||
|
||||
// Number of threads to use in the algorithm
|
||||
// Number of intervals for to do the internal division of the data
|
||||
uint32_t nthread, ninterval;
|
||||
|
||||
// Bool variables indicating if the auxiliary memory is constructed
|
||||
// and indicating in the auxiliary memory had been obtained inside the
|
||||
/// algorithm or had been received as a parameter
|
||||
bool construct = false, owner = false;
|
||||
|
||||
// Comparison object for to compare two elements
|
||||
Compare comp;
|
||||
|
||||
// Range with all the elements to sort
|
||||
range_it global_range;
|
||||
|
||||
// range with the auxiliary memory
|
||||
range_buf global_buf;
|
||||
|
||||
// vector of futures
|
||||
std::vector<std::future<void>> vfuture;
|
||||
|
||||
// vector of vectors which contains the ranges to merge obtained in the
|
||||
// subdivision
|
||||
std::vector<std::vector<range_it>> vv_range_it;
|
||||
|
||||
// each vector of ranges of the vv_range_it, need their corresponding buffer
|
||||
// for to do the merge
|
||||
std::vector<std::vector<range_buf>> vv_range_buf;
|
||||
|
||||
// Initial vector of ranges
|
||||
std::vector<range_it> vrange_it_ini;
|
||||
|
||||
// Initial vector of buffers
|
||||
std::vector<range_buf> vrange_buf_ini;
|
||||
|
||||
// atomic counter for to know when are finished the function_t created
|
||||
// inside a function
|
||||
std::atomic<uint32_t> njob;
|
||||
|
||||
// Indicate if an error in the algorithm for to undo all
|
||||
bool error;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// FUNCTIONS OF THE STRUCT
|
||||
//------------------------------------------------------------------------
|
||||
void initial_configuration(void);
|
||||
|
||||
sample_sort (Iter_t first, Iter_t last, Compare cmp, uint32_t num_thread,
|
||||
value_t *paux, size_t naux);
|
||||
|
||||
sample_sort(Iter_t first, Iter_t last)
|
||||
: sample_sort (first, last, Compare(), std::thread::hardware_concurrency(),
|
||||
nullptr, 0) { };
|
||||
|
||||
sample_sort(Iter_t first, Iter_t last, Compare cmp)
|
||||
: sample_sort(first, last, cmp, std::thread::hardware_concurrency(),
|
||||
nullptr, 0) { };
|
||||
|
||||
sample_sort(Iter_t first, Iter_t last, uint32_t num_thread)
|
||||
: sample_sort(first, last, Compare(), num_thread, nullptr, 0) { };
|
||||
|
||||
sample_sort(Iter_t first, Iter_t last, Compare cmp, uint32_t num_thread)
|
||||
: sample_sort(first, last, cmp, num_thread, nullptr, 0) { };
|
||||
|
||||
sample_sort(Iter_t first, Iter_t last, Compare cmp, uint32_t num_thread,
|
||||
range_buf range_buf_initial)
|
||||
: sample_sort(first, last, cmp, num_thread,
|
||||
range_buf_initial.first, range_buf_initial.size()) { };
|
||||
|
||||
void destroy_all(void);
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function :~sample_sort
|
||||
/// @brief destructor of the class. The utility is to destroy the temporary
|
||||
/// buffer used in the sorting process
|
||||
//-----------------------------------------------------------------------------
|
||||
~sample_sort(void) { destroy_all(); };
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
// function : execute first
|
||||
/// @brief this a function to assign to each thread in the first merge
|
||||
//-----------------------------------------------------------------------
|
||||
void execute_first(void)
|
||||
{
|
||||
uint32_t job = 0;
|
||||
while ((job = atomic_add(njob, 1)) < ninterval)
|
||||
{
|
||||
uninit_merge_level4(vrange_buf_ini[job], vv_range_it[job],
|
||||
vv_range_buf[job], comp);
|
||||
};
|
||||
};
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
// function : execute
|
||||
/// @brief this is a function to assignt each thread the final merge
|
||||
//-----------------------------------------------------------------------
|
||||
void execute(void)
|
||||
{
|
||||
uint32_t job = 0;
|
||||
while ((job = atomic_add(njob, 1)) < ninterval)
|
||||
{
|
||||
merge_vector4(vrange_buf_ini[job], vrange_it_ini[job],
|
||||
vv_range_buf[job], vv_range_it[job], comp);
|
||||
};
|
||||
};
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
// function : first merge
|
||||
/// @brief Implement the merge of the initially sparse ranges
|
||||
//-----------------------------------------------------------------------
|
||||
void first_merge(void)
|
||||
{ //---------------------------------- begin --------------------------
|
||||
njob = 0;
|
||||
|
||||
for (uint32_t i = 0; i < nthread; ++i)
|
||||
{
|
||||
vfuture[i] = std::async(std::launch::async, &this_t::execute_first,
|
||||
this);
|
||||
};
|
||||
for (uint32_t i = 0; i < nthread; ++i)
|
||||
vfuture[i].get();
|
||||
};
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
// function : final merge
|
||||
/// @brief Implement the final merge of the ranges
|
||||
//-----------------------------------------------------------------------
|
||||
void final_merge(void)
|
||||
{ //---------------------------------- begin --------------------------
|
||||
njob = 0;
|
||||
|
||||
for (uint32_t i = 0; i < nthread; ++i)
|
||||
{
|
||||
vfuture[i] = std::async(std::launch::async, &this_t::execute, this);
|
||||
};
|
||||
for (uint32_t i = 0; i < nthread; ++i)
|
||||
vfuture[i].get();
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
};
|
||||
// End class sample_sort
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
//############################################################################
|
||||
// ##
|
||||
// N O N I N L I N E F U N C T I O N S ##
|
||||
// ##
|
||||
// ##
|
||||
//############################################################################
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : sample_sort
|
||||
/// @brief constructor of the class
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
/// @param cmp : object for to compare two elements pointed by Iter_t iterators
|
||||
/// @param num_thread : Number of threads to use in the process. When this value
|
||||
/// is lower than 2, the sorting is done with 1 thread
|
||||
/// @param paux : pointer to the auxiliary memory. If nullptr, the memory is
|
||||
/// created inside the class
|
||||
/// @param naux : number of elements of the memory pointed by paux
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Iter_t, typename Compare>
|
||||
sample_sort<Iter_t, Compare>
|
||||
::sample_sort (Iter_t first, Iter_t last, Compare cmp, uint32_t num_thread,
|
||||
value_t *paux, size_t naux)
|
||||
: nthread(num_thread), owner(false), comp(cmp), global_range(first, last),
|
||||
global_buf(nullptr, nullptr), error(false)
|
||||
{
|
||||
assert((last - first) >= 0);
|
||||
size_t nelem = size_t(last - first);
|
||||
construct = false;
|
||||
njob = 0;
|
||||
vfuture.resize(nthread);
|
||||
|
||||
// Adjust when have many threads and only a few elements
|
||||
while (nelem > thread_min and (nthread * nthread) > (nelem >> 3))
|
||||
{
|
||||
nthread /= 2;
|
||||
};
|
||||
ninterval = (nthread << 3);
|
||||
|
||||
if (nthread < 2 or nelem <= (thread_min))
|
||||
{
|
||||
bss::spinsort<Iter_t, Compare>(first, last, comp);
|
||||
return;
|
||||
};
|
||||
|
||||
//------------------- check if sort --------------------------------------
|
||||
bool sw = true;
|
||||
for (Iter_t it1 = first, it2 = first + 1;
|
||||
it2 != last and (sw = not comp(*it2, *it1)); it1 = it2++);
|
||||
if (sw) return;
|
||||
|
||||
//------------------- check if reverse sort ---------------------------
|
||||
sw = true;
|
||||
for (Iter_t it1 = first, it2 = first + 1;
|
||||
it2 != last and (sw = comp(*it2, *it1)); it1 = it2++);
|
||||
if (sw)
|
||||
{
|
||||
size_t nelem2 = nelem >> 1;
|
||||
Iter_t it1 = first, it2 = last - 1;
|
||||
for (size_t i = 0; i < nelem2; ++i)
|
||||
std::swap(*(it1++), *(it2--));
|
||||
return;
|
||||
};
|
||||
|
||||
if (paux != nullptr)
|
||||
{
|
||||
assert(naux != 0);
|
||||
global_buf.first = paux;
|
||||
global_buf.last = paux + naux;
|
||||
owner = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
value_t *ptr = std::get_temporary_buffer<value_t>(nelem).first;
|
||||
if (ptr == nullptr) throw std::bad_alloc();
|
||||
owner = true;
|
||||
global_buf = range_buf(ptr, ptr + nelem);
|
||||
};
|
||||
//------------------------------------------------------------------------
|
||||
// PROCESS
|
||||
//------------------------------------------------------------------------
|
||||
try
|
||||
{
|
||||
initial_configuration();
|
||||
} catch (std::bad_alloc &)
|
||||
{
|
||||
error = true;
|
||||
};
|
||||
if (not error)
|
||||
{
|
||||
first_merge();
|
||||
construct = true;
|
||||
final_merge();
|
||||
};
|
||||
if (error)
|
||||
{
|
||||
destroy_all();
|
||||
throw std::bad_alloc();
|
||||
};
|
||||
}
|
||||
;
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : destroy_all
|
||||
/// @brief destructor of the class. The utility is to destroy the temporary
|
||||
/// buffer used in the sorting process
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Iter_t, typename Compare>
|
||||
void sample_sort<Iter_t, Compare>::destroy_all(void)
|
||||
{
|
||||
if (construct)
|
||||
{
|
||||
destroy(global_buf);
|
||||
construct = false;
|
||||
}
|
||||
if (global_buf.first != nullptr and owner)
|
||||
std::return_temporary_buffer(global_buf.first);
|
||||
}
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : initial_configuration
|
||||
/// @brief Create the internal data structures, and obtain the inital set of
|
||||
/// ranges to merge
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Iter_t, typename Compare>
|
||||
void sample_sort<Iter_t, Compare>::initial_configuration(void)
|
||||
{
|
||||
std::vector<range_it> vmem_thread;
|
||||
std::vector<range_buf> vbuf_thread;
|
||||
size_t nelem = global_range.size();
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
size_t cupo = nelem / nthread;
|
||||
Iter_t it_first = global_range.first;
|
||||
value_t *buf_first = global_buf.first;
|
||||
vmem_thread.reserve(nthread + 1);
|
||||
vbuf_thread.reserve(nthread + 1);
|
||||
|
||||
for (uint32_t i = 0; i < (nthread - 1); ++i, it_first += cupo, buf_first +=
|
||||
cupo)
|
||||
{
|
||||
vmem_thread.emplace_back(it_first, it_first + cupo);
|
||||
vbuf_thread.emplace_back(buf_first, buf_first + cupo);
|
||||
};
|
||||
|
||||
vmem_thread.emplace_back(it_first, global_range.last);
|
||||
vbuf_thread.emplace_back(buf_first, global_buf.last);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Sorting of the ranges
|
||||
//------------------------------------------------------------------------
|
||||
std::vector<std::future<void>> vfuture(nthread);
|
||||
|
||||
for (uint32_t i = 0; i < nthread; ++i)
|
||||
{
|
||||
auto func = [=]()
|
||||
{
|
||||
bss::spinsort<Iter_t, Compare> (vmem_thread[i].first,
|
||||
vmem_thread[i].last, comp,
|
||||
vbuf_thread[i]);
|
||||
};
|
||||
vfuture[i] = std::async(std::launch::async, func);
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < nthread; ++i)
|
||||
vfuture[i].get();
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Obtain the vector of milestones
|
||||
//------------------------------------------------------------------------
|
||||
std::vector<Iter_t> vsample;
|
||||
vsample.reserve(nthread * (ninterval - 1));
|
||||
|
||||
for (uint32_t i = 0; i < nthread; ++i)
|
||||
{
|
||||
size_t distance = vmem_thread[i].size() / ninterval;
|
||||
for (size_t j = 1, pos = distance; j < ninterval; ++j, pos += distance)
|
||||
{
|
||||
vsample.push_back(vmem_thread[i].first + pos);
|
||||
};
|
||||
};
|
||||
typedef less_ptr_no_null<Iter_t, Compare> compare_ptr;
|
||||
typedef typename std::vector<Iter_t>::iterator it_to_it;
|
||||
|
||||
bss::spinsort<it_to_it, compare_ptr>(vsample.begin(), vsample.end(),
|
||||
compare_ptr(comp));
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Create the final milestone vector
|
||||
//------------------------------------------------------------------------
|
||||
std::vector<Iter_t> vmilestone;
|
||||
vmilestone.reserve(ninterval);
|
||||
|
||||
for (uint32_t pos = nthread >> 1; pos < vsample.size(); pos += nthread)
|
||||
{
|
||||
vmilestone.push_back(vsample[pos]);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Creation of the first vector of ranges
|
||||
//------------------------------------------------------------------------
|
||||
std::vector<std::vector<range<Iter_t>>>vv_range_first (nthread);
|
||||
|
||||
for (uint32_t i = 0; i < nthread; ++i)
|
||||
{
|
||||
Iter_t itaux = vmem_thread[i].first;
|
||||
|
||||
for (uint32_t k = 0; k < (ninterval - 1); ++k)
|
||||
{
|
||||
Iter_t it2 = std::upper_bound(itaux, vmem_thread[i].last,
|
||||
*vmilestone[k], comp);
|
||||
|
||||
vv_range_first[i].emplace_back(itaux, it2);
|
||||
itaux = it2;
|
||||
};
|
||||
vv_range_first[i].emplace_back(itaux, vmem_thread[i].last);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Copy in buffer and creation of the final matrix of ranges
|
||||
//------------------------------------------------------------------------
|
||||
vv_range_it.resize(ninterval);
|
||||
vv_range_buf.resize(ninterval);
|
||||
vrange_it_ini.reserve(ninterval);
|
||||
vrange_buf_ini.reserve(ninterval);
|
||||
|
||||
for (uint32_t i = 0; i < ninterval; ++i)
|
||||
{
|
||||
vv_range_it[i].reserve(nthread);
|
||||
vv_range_buf[i].reserve(nthread);
|
||||
};
|
||||
|
||||
Iter_t it = global_range.first;
|
||||
value_t *it_buf = global_buf.first;
|
||||
|
||||
for (uint32_t k = 0; k < ninterval; ++k)
|
||||
{
|
||||
size_t nelem_interval = 0;
|
||||
|
||||
for (uint32_t i = 0; i < nthread; ++i)
|
||||
{
|
||||
size_t nelem_range = vv_range_first[i][k].size();
|
||||
if (nelem_range != 0)
|
||||
{
|
||||
vv_range_it[k].push_back(vv_range_first[i][k]);
|
||||
};
|
||||
nelem_interval += nelem_range;
|
||||
};
|
||||
|
||||
vrange_it_ini.emplace_back(it, it + nelem_interval);
|
||||
vrange_buf_ini.emplace_back(it_buf, it_buf + nelem_interval);
|
||||
|
||||
it += nelem_interval;
|
||||
it_buf += nelem_interval;
|
||||
};
|
||||
}
|
||||
;
|
||||
//
|
||||
//****************************************************************************
|
||||
}
|
||||
;
|
||||
// End namespace sample_detail
|
||||
//****************************************************************************
|
||||
//
|
||||
namespace bscu = boost::sort::common::util;
|
||||
//
|
||||
//############################################################################
|
||||
// ##
|
||||
// ##
|
||||
// S A M P L E _ S O R T ##
|
||||
// ##
|
||||
// ##
|
||||
//############################################################################
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : sample_sort
|
||||
/// @brief parallel sample sort algorithm (stable sort)
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Iter_t>
|
||||
void sample_sort(Iter_t first, Iter_t last)
|
||||
{
|
||||
typedef compare_iter<Iter_t> Compare;
|
||||
sample_detail::sample_sort<Iter_t, Compare>(first, last);
|
||||
};
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : sample_sort
|
||||
/// @brief parallel sample sort algorithm (stable sort)
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
/// @param nthread : Number of threads to use in the process. When this value
|
||||
/// is lower than 2, the sorting is done with 1 thread
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Iter_t>
|
||||
void sample_sort(Iter_t first, Iter_t last, uint32_t nthread)
|
||||
{
|
||||
typedef compare_iter<Iter_t> Compare;
|
||||
sample_detail::sample_sort<Iter_t, Compare>(first, last, nthread);
|
||||
};
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : sample_sort
|
||||
/// @brief parallel sample sort algorithm (stable sort)
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
/// @param comp : object for to compare two elements pointed by Iter_t
|
||||
/// iterators
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Iter_t, class Compare, bscu::enable_if_not_integral<Compare> * =
|
||||
nullptr>
|
||||
void sample_sort(Iter_t first, Iter_t last, Compare comp)
|
||||
{
|
||||
sample_detail::sample_sort<Iter_t, Compare>(first, last, comp);
|
||||
};
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// function : sample_sort
|
||||
/// @brief parallel sample sort algorithm (stable sort)
|
||||
///
|
||||
/// @param first : iterator to the first element of the range to sort
|
||||
/// @param last : iterator after the last element to the range to sort
|
||||
/// @param comp : object for to compare two elements pointed by Iter_t
|
||||
/// iterators
|
||||
/// @param nthread : Number of threads to use in the process. When this value
|
||||
/// is lower than 2, the sorting is done with 1 thread
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Iter_t, class Compare>
|
||||
void sample_sort(Iter_t first, Iter_t last, Compare comp, uint32_t nthread)
|
||||
{
|
||||
sample_detail::sample_sort<Iter_t, Compare>(first, last, comp, nthread);
|
||||
};
|
||||
//
|
||||
//****************************************************************************
|
||||
};// End namespace parallel
|
||||
};// End namespace sort
|
||||
};// End namespace boost
|
||||
//****************************************************************************
|
||||
//
|
||||
#endif
|
||||
@@ -1,20 +0,0 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file sort.hpp
|
||||
/// @brief This file contains the sort functions of the sort library
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __BOOST_SORT_PARALLEL_SORT_HPP
|
||||
#define __BOOST_SORT_PARALLEL_SORT_HPP
|
||||
|
||||
#include <boost/sort/parallel/block_indirect_sort.hpp>
|
||||
#include <boost/sort/parallel/parallel_stable_sort.hpp>
|
||||
#include <boost/sort/parallel/sample_sort.hpp>
|
||||
//
|
||||
#endif
|
||||
@@ -19,7 +19,20 @@ import testing ;
|
||||
: : : : string_sort ]
|
||||
[ run sort_detail_test.cpp
|
||||
: : : : sort_detail ]
|
||||
|
||||
|
||||
|
||||
[ run test_flat_stable_sort.cpp
|
||||
: : : <optimization>speed : test_flat_stable_sort ]
|
||||
[ run test_spinsort.cpp
|
||||
: : : <optimization>speed : test_spinsort ]
|
||||
[ run test_insert_sort.cpp
|
||||
: : : <optimization>speed : test_insert_sort ]
|
||||
|
||||
|
||||
[ run test_block_indirect_sort.cpp
|
||||
: : : <optimization>speed <threading>multi : test_block_indirect_sort ]
|
||||
[ run test_sample_sort.cpp
|
||||
: : : <optimization>speed <threading>multi : test_sample_sort ]
|
||||
[ run test_parallel_stable_sort.cpp
|
||||
: : : <optimization>speed <threading>multi : test_parallel_stable_sort ]
|
||||
;
|
||||
}
|
||||
|
||||
384
test/test_block_indirect_sort.cpp
Normal file
384
test/test_block_indirect_sort.cpp
Normal file
@@ -0,0 +1,384 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file test_block_indirect_sort.cpp
|
||||
/// @brief Test program of the block_indirect_sort algorithm
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <vector>
|
||||
#include <ciso646>
|
||||
#include <boost/test/included/test_exec_monitor.hpp>
|
||||
#include <boost/test/test_tools.hpp>
|
||||
#include <boost/sort/sort.hpp>
|
||||
|
||||
|
||||
namespace bsc = boost::sort::common;
|
||||
namespace bsp = boost::sort;
|
||||
using boost::sort::block_indirect_sort;
|
||||
using bsc::range;
|
||||
|
||||
|
||||
void test1 (void)
|
||||
{
|
||||
typedef std::less< uint64_t > compare;
|
||||
|
||||
const uint32_t NElem = 500000;
|
||||
std::vector< uint64_t > V1;
|
||||
std::mt19937_64 my_rand (0);
|
||||
compare comp;
|
||||
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (my_rand ( ) % NElem);
|
||||
block_indirect_sort (V1.begin ( ), V1.end ( ), comp, 2);
|
||||
|
||||
for (unsigned i = 1; i < NElem; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
V1.clear ( );
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (i);
|
||||
|
||||
block_indirect_sort ( V1.begin ( ), V1.end ( ), comp, 2);
|
||||
for (unsigned i = 1; i < NElem; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
V1.clear ( );
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (NElem - i);
|
||||
|
||||
block_indirect_sort ( V1.begin ( ), V1.end ( ), comp, 2);
|
||||
for (unsigned i = 1; i < NElem; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
V1.clear ( );
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (1000);
|
||||
|
||||
block_indirect_sort (V1.begin ( ), V1.end ( ), comp, 2);
|
||||
for (unsigned i = 1; i < NElem; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] == V1[ i ]);
|
||||
};
|
||||
};
|
||||
|
||||
void test2 (void)
|
||||
{
|
||||
std::less< uint64_t > comp;
|
||||
std::vector< uint64_t > V;
|
||||
|
||||
for (uint32_t i = 0; i < 2083333; ++i) V.push_back (i);
|
||||
|
||||
block_indirect_sort ( V.begin ( ), V.end ( ),comp, 8);
|
||||
for (uint32_t i = 0; i < V.size ( ); ++i) {
|
||||
BOOST_CHECK (V[ i ] == i);
|
||||
};
|
||||
};
|
||||
|
||||
void test3 (void)
|
||||
{
|
||||
typedef typename std::vector< uint64_t >::iterator iter_t;
|
||||
typedef range< iter_t > range_it;
|
||||
|
||||
const uint32_t NELEM = 416667;
|
||||
std::vector< uint64_t > A;
|
||||
std::less< uint64_t > comp;
|
||||
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (0);
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back (NELEM - i);
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (0);
|
||||
|
||||
range_it R1 (A.begin ( ) + 1000, A.begin ( ) + (1000 + NELEM));
|
||||
block_indirect_sort ( A.begin () + 1000,
|
||||
A.begin () + (1000 + NELEM), comp, 8);
|
||||
for (iter_t it = A.begin ( ) + 1000; it != A.begin ( ) + (1000 + NELEM);
|
||||
++it)
|
||||
{
|
||||
BOOST_CHECK ((*(it - 1)) <= (*it));
|
||||
};
|
||||
BOOST_CHECK (A[ 998 ] == 0 and A[ 999 ] == 0 and A[ 1000 + NELEM ] == 0 and
|
||||
A[ 1001 + NELEM ] == 0);
|
||||
|
||||
|
||||
A.clear ( );
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (999999999);
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back (NELEM - i);
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (999999999);
|
||||
|
||||
R1 = range_it (A.begin ( ) + 1000, A.begin ( ) + (1000 + NELEM));
|
||||
block_indirect_sort ( A.begin ( ) + 1000,
|
||||
A.begin ( ) + (1000 + NELEM), comp, 4);
|
||||
|
||||
for (iter_t it = A.begin ( ) + 1001; it != A.begin ( ) + (1000 + NELEM);
|
||||
++it)
|
||||
{
|
||||
BOOST_CHECK ((*(it - 1)) <= (*it));
|
||||
};
|
||||
BOOST_CHECK (A[ 998 ] == 999999999 and A[ 999 ] == 999999999 and
|
||||
A[ 1000 + NELEM ] == 999999999 and
|
||||
A[ 1001 + NELEM ] == 999999999);
|
||||
};
|
||||
|
||||
void test4 (void)
|
||||
{
|
||||
typedef std::less< uint32_t > compare;
|
||||
|
||||
const uint32_t NElem = 1000000;
|
||||
std::vector< uint32_t > V1, V2, V3;
|
||||
V1.reserve ( NElem ) ;
|
||||
std::mt19937 my_rand (0);
|
||||
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (my_rand ( ));
|
||||
|
||||
V2 = V1;
|
||||
V3 = V1;
|
||||
std::sort (V2.begin ( ), V2.end ( ));
|
||||
|
||||
V1 = V3;
|
||||
block_indirect_sort ( V1.begin ( ), V1.end ( ), compare(), 2);
|
||||
for (unsigned i = 0; i < V1.size(); i++)
|
||||
{
|
||||
BOOST_CHECK (V1[ i ] == V2[ i ]);
|
||||
};
|
||||
|
||||
V1 = V3;
|
||||
block_indirect_sort (V1.begin ( ), V1.end ( ), compare(), 4);
|
||||
for (unsigned i = 0; i < V1.size(); i++)
|
||||
{ BOOST_CHECK (V1[ i ] == V2[ i ]);
|
||||
};
|
||||
|
||||
V1 = V3;
|
||||
|
||||
block_indirect_sort (V1.begin ( ), V1.end ( ), compare(), 8);
|
||||
|
||||
for (unsigned i = 0; i < V1.size(); i++)
|
||||
{ BOOST_CHECK (V1[ i ] == V2[ i ]);
|
||||
};
|
||||
|
||||
V1 = V3;
|
||||
block_indirect_sort ( V1.begin ( ), V1.end ( ), compare(), 16);
|
||||
for (unsigned i = 0; i < V1.size(); i++)
|
||||
{ BOOST_CHECK (V1[ i ] == V2[ i ]);
|
||||
};
|
||||
|
||||
V1 = V3;
|
||||
block_indirect_sort ( V1.begin ( ), V1.end ( ), compare(), 100);
|
||||
for (unsigned i = 1; i < V1.size(); i++)
|
||||
{ BOOST_CHECK (V1[ i ] == V2[ i ]);
|
||||
};
|
||||
};
|
||||
|
||||
template<uint32_t NN>
|
||||
struct int_array
|
||||
{
|
||||
uint64_t M[NN];
|
||||
|
||||
int_array(uint64_t number = 0)
|
||||
{
|
||||
for (uint32_t i = 0; i < NN; ++i)
|
||||
M[i] = number;
|
||||
}
|
||||
|
||||
bool operator<(const int_array<NN> &A) const
|
||||
{
|
||||
return M[0] < A.M[0];
|
||||
}
|
||||
};
|
||||
|
||||
void test5(void)
|
||||
{
|
||||
namespace bspd = boost::sort::blk_detail;
|
||||
BOOST_CHECK(bspd::block_size<0>::data == 4096);
|
||||
|
||||
BOOST_CHECK(bspd::block_size<1>::data == 4096);
|
||||
|
||||
BOOST_CHECK(bspd::block_size<2>::data == 4096);
|
||||
|
||||
BOOST_CHECK(bspd::block_size<3>::data == 4096);
|
||||
BOOST_CHECK(bspd::block_size<4>::data == 4096);
|
||||
|
||||
BOOST_CHECK(bspd::block_size<5>::data == 4096);
|
||||
BOOST_CHECK(bspd::block_size<6>::data == 4096);
|
||||
BOOST_CHECK(bspd::block_size<7>::data == 4096);
|
||||
BOOST_CHECK(bspd::block_size<8>::data == 4096);
|
||||
|
||||
BOOST_CHECK(bspd::block_size<9>::data == 2048);
|
||||
BOOST_CHECK(bspd::block_size<12>::data == 2048);
|
||||
BOOST_CHECK(bspd::block_size<15>::data == 2048);
|
||||
BOOST_CHECK(bspd::block_size<16>::data == 2048);
|
||||
|
||||
BOOST_CHECK(bspd::block_size<17>::data == 1024);
|
||||
BOOST_CHECK(bspd::block_size<24>::data == 1024);
|
||||
BOOST_CHECK(bspd::block_size<31>::data == 1024);
|
||||
BOOST_CHECK(bspd::block_size<32>::data == 1024);
|
||||
|
||||
BOOST_CHECK(bspd::block_size<33>::data == 768);
|
||||
BOOST_CHECK(bspd::block_size<50>::data == 768);
|
||||
BOOST_CHECK(bspd::block_size<63>::data == 768);
|
||||
BOOST_CHECK(bspd::block_size<64>::data == 768);
|
||||
|
||||
BOOST_CHECK(bspd::block_size<65>::data == 512);
|
||||
BOOST_CHECK(bspd::block_size<100>::data == 512);
|
||||
BOOST_CHECK(bspd::block_size<127>::data == 512);
|
||||
BOOST_CHECK(bspd::block_size<128>::data == 512);
|
||||
|
||||
BOOST_CHECK(bspd::block_size<129>::data == 256);
|
||||
BOOST_CHECK(bspd::block_size<200>::data == 256);
|
||||
BOOST_CHECK(bspd::block_size<255>::data == 256);
|
||||
BOOST_CHECK(bspd::block_size<256>::data == 256);
|
||||
|
||||
BOOST_CHECK(bspd::block_size<257>::data == 128);
|
||||
BOOST_CHECK(bspd::block_size<400>::data == 128);
|
||||
BOOST_CHECK(bspd::block_size<511>::data == 128);
|
||||
BOOST_CHECK(bspd::block_size<512>::data == 128);
|
||||
BOOST_CHECK(bspd::block_size<513>::data == 128);
|
||||
BOOST_CHECK(bspd::block_size<600>::data == 128);
|
||||
};
|
||||
|
||||
void test6()
|
||||
{
|
||||
std::less<uint64_t> cmp64;
|
||||
std::less<uint32_t> cmp32;
|
||||
std::less<uint16_t> cmp16;
|
||||
std::less<uint8_t> cmp8;
|
||||
|
||||
std::mt19937_64 my_rand(0);
|
||||
|
||||
const uint32_t NELEM = (1 << 20);
|
||||
std::vector<uint64_t> V1, V2;
|
||||
V1.reserve(NELEM);
|
||||
V2.reserve(NELEM);
|
||||
|
||||
for (uint32_t i = 0; i < NELEM; ++i)
|
||||
V1.push_back(my_rand());
|
||||
V2 = V1;
|
||||
|
||||
uint64_t *p64 = &V1[0];
|
||||
uint32_t *p32 = reinterpret_cast<uint32_t *>(p64);
|
||||
uint16_t *p16 = reinterpret_cast<uint16_t *>(p64);
|
||||
uint8_t *p8 = reinterpret_cast<uint8_t *>(p64);
|
||||
|
||||
V1 = V2;
|
||||
bsp::block_indirect_sort(p64, p64 + NELEM, cmp64, 8);
|
||||
for (unsigned i = 1; i < NELEM; i++)
|
||||
{
|
||||
BOOST_CHECK(p64[i - 1] <= p64[i]);
|
||||
};
|
||||
|
||||
V1 = V2;
|
||||
bsp::block_indirect_sort(p32, p32 + (NELEM << 1), cmp32, 8);
|
||||
for (unsigned i = 1; i < (NELEM << 1); i++)
|
||||
{
|
||||
BOOST_CHECK(p32[i - 1] <= p32[i]);
|
||||
};
|
||||
|
||||
V1 = V2;
|
||||
bsp::block_indirect_sort(p16, p16 + (NELEM << 2), cmp16, 8);
|
||||
for (unsigned i = 1; i < (NELEM << 2); i++)
|
||||
{
|
||||
BOOST_CHECK(p16[i - 1] <= p16[i]);
|
||||
};
|
||||
|
||||
V1 = V2;
|
||||
bsp::block_indirect_sort(p8, p8 + (NELEM << 3), cmp8, 8);
|
||||
for (unsigned i = 1; i < (NELEM << 3); i++)
|
||||
{
|
||||
BOOST_CHECK(p8[i - 1] <= p8[i]);
|
||||
};
|
||||
};
|
||||
|
||||
template<class IA>
|
||||
void test_int_array(uint32_t NELEM)
|
||||
{
|
||||
typedef std::less<IA> compare;
|
||||
std::mt19937_64 my_rand(0);
|
||||
|
||||
std::vector<IA> V1;
|
||||
V1.reserve(NELEM);
|
||||
for (uint32_t i = 0; i < NELEM; ++i)
|
||||
V1.emplace_back(my_rand());
|
||||
|
||||
bsp::block_indirect_sort(V1.begin(), V1.end(), compare());
|
||||
for (unsigned i = 1; i < NELEM; i++)
|
||||
{
|
||||
BOOST_CHECK(not (V1[i] < V1[i - 1]));
|
||||
};
|
||||
}
|
||||
|
||||
void test7()
|
||||
{
|
||||
test_int_array<int_array<1> >(1u << 20);
|
||||
test_int_array<int_array<2> >(1u << 19);
|
||||
test_int_array<int_array<4> >(1u << 18);
|
||||
test_int_array<int_array<8> >(1u << 17);
|
||||
test_int_array<int_array<16> >(1u << 17);
|
||||
test_int_array<int_array<32> >(1u << 17);
|
||||
test_int_array<int_array<64> >(1u << 17);
|
||||
test_int_array<int_array<128> >(1u << 17);
|
||||
}
|
||||
void test8()
|
||||
{
|
||||
std::mt19937_64 my_rand(0);
|
||||
const uint32_t NELEM = 1 << 20;
|
||||
const uint32_t NString = 100000;
|
||||
std::vector<uint64_t> V1;
|
||||
V1.reserve(NELEM);
|
||||
for (uint32_t i = 0; i < NELEM; ++i)
|
||||
V1.push_back(my_rand());
|
||||
|
||||
uint64_t *p64 = &V1[0];
|
||||
char *pchar = reinterpret_cast<char *>(p64);
|
||||
|
||||
std::string sinput(pchar, (NELEM << 3));
|
||||
|
||||
std::istringstream strm_input(sinput);
|
||||
std::string inval;
|
||||
std::vector<std::string> V;
|
||||
V.reserve(NString);
|
||||
strm_input.seekg(0, std::ios_base::beg);
|
||||
|
||||
strm_input.seekg(0, std::ios_base::beg);
|
||||
|
||||
for (size_t i = 0; i < NString; ++i)
|
||||
{
|
||||
if (!strm_input.eof())
|
||||
{
|
||||
strm_input >> inval;
|
||||
V.push_back(inval);
|
||||
inval.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::ios_base::failure("Insuficient lenght of the file\n");
|
||||
};
|
||||
};
|
||||
|
||||
typedef std::less<std::string> compare;
|
||||
bsp::block_indirect_sort(V.begin(), V.end(), compare());
|
||||
for (unsigned i = 1; i < NString; i++)
|
||||
{
|
||||
BOOST_CHECK(not (V[i] < V[i - 1]));
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
int test_main (int, char *[])
|
||||
{
|
||||
test1 ( );
|
||||
test2 ( );
|
||||
test3 ( );
|
||||
test4 ( );
|
||||
test5 ( );
|
||||
test6 ( );
|
||||
test7 ( );
|
||||
test8 ( );
|
||||
|
||||
return 0;
|
||||
};
|
||||
269
test/test_flat_stable_sort.cpp
Normal file
269
test/test_flat_stable_sort.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file test_flat_stable_sort.cpp
|
||||
/// @brief test program of the flat_stable_sort algorithm
|
||||
///
|
||||
/// @author Copyright (c) 2017 Francisco José Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
#include <ciso646>
|
||||
#include <boost/sort/flat_stable_sort/flat_stable_sort.hpp>
|
||||
#include <boost/test/included/test_exec_monitor.hpp>
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
using namespace boost::sort;
|
||||
|
||||
void test2 ( );
|
||||
void test3 ( );
|
||||
void test4 ( );
|
||||
void test5 ( );
|
||||
void test6 ( );
|
||||
void test7 ( );
|
||||
|
||||
struct xk
|
||||
{
|
||||
unsigned tail : 4;
|
||||
unsigned num : 28;
|
||||
xk ( uint32_t n =0 , uint32_t t =0): tail (t), num(n){};
|
||||
bool operator< (xk A) const { return (num < A.num); };
|
||||
};
|
||||
|
||||
void test2 ( )
|
||||
{
|
||||
uint64_t V1[ 300 ];
|
||||
typedef std::less< uint64_t > compare_t;
|
||||
compare_t comp;
|
||||
|
||||
for (uint32_t i = 0; i < 200; ++i) V1[ i ] = i;
|
||||
|
||||
indirect_flat_stable_sort (&V1[ 0 ], &V1[ 200 ], comp);
|
||||
for (unsigned i = 1; i < 200; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < 200; ++i) V1[ i ] = 199 - i;
|
||||
flat_stable_sort (&V1[ 0 ], &V1[ 200 ], comp);
|
||||
for (unsigned i = 1; i < 200; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < 300; ++i) V1[ i ] = 299 - i;
|
||||
|
||||
flat_stable_sort (&V1[ 0 ], &V1[ 300 ], comp);
|
||||
for (unsigned i = 1; i < 300; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < 300; ++i) V1[ i ] = 88;
|
||||
|
||||
flat_stable_sort (&V1[ 0 ], &V1[ 300 ], comp);
|
||||
for (unsigned i = 1; i < 300; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
};
|
||||
|
||||
void test3 ( )
|
||||
{
|
||||
typedef std::less< xk > compare_t;
|
||||
std::mt19937_64 my_rand (0);
|
||||
|
||||
const uint32_t NMAX = 500000;
|
||||
|
||||
|
||||
std::vector< xk > V1, V2, V3;
|
||||
V1.reserve (NMAX);
|
||||
for (uint32_t i = 0; i < 8; ++i) {
|
||||
for (uint32_t k = 0; k < NMAX; ++k) {
|
||||
uint32_t NM = my_rand ( );
|
||||
xk G;
|
||||
G.num = NM >> 3;
|
||||
G.tail = i;
|
||||
V1.push_back (G);
|
||||
};
|
||||
};
|
||||
V3 = V2 = V1;
|
||||
flat_stable_sort (V1.begin ( ), V1.end ( ), compare_t ( ));
|
||||
std::stable_sort (V2.begin ( ), V2.end ( ));
|
||||
|
||||
BOOST_CHECK (V1.size ( ) == V2.size ( ));
|
||||
for (uint32_t i = 0; i < V1.size ( ); ++i) {
|
||||
BOOST_CHECK (V1[ i ].num == V2[ i ].num and
|
||||
V1[ i ].tail == V2[ i ].tail);
|
||||
};
|
||||
};
|
||||
|
||||
void test4 (void)
|
||||
{
|
||||
typedef std::less< uint64_t > compare_t;
|
||||
const uint32_t NElem = 500000;
|
||||
std::vector< uint64_t > V1;
|
||||
std::mt19937_64 my_rand (0);
|
||||
compare_t comp;
|
||||
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (my_rand ( ) % NElem);
|
||||
|
||||
flat_stable_sort (V1.begin ( ), V1.end ( ), comp);
|
||||
for (unsigned i = 1; i < NElem; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
V1.clear ( );
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (i);
|
||||
flat_stable_sort (V1.begin ( ), V1.end ( ), comp);
|
||||
for (unsigned i = 1; i < NElem; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
V1.clear ( );
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (NElem - i);
|
||||
flat_stable_sort (V1.begin ( ), V1.end ( ), comp);
|
||||
for (unsigned i = 1; i < NElem; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
V1.clear ( );
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (1000);
|
||||
flat_stable_sort (V1.begin ( ), V1.end ( ), comp);
|
||||
for (unsigned i = 1; i < NElem; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] == V1[ i ]);
|
||||
};
|
||||
};
|
||||
|
||||
void test5 (void)
|
||||
{
|
||||
typedef std::less< uint64_t > compare;
|
||||
|
||||
const uint32_t KMax = 500000;
|
||||
|
||||
std::vector< uint64_t > K, M;
|
||||
std::mt19937_64 my_rand (0);
|
||||
compare comp;
|
||||
|
||||
for (uint32_t i = 0; i < KMax; ++i) K.push_back (my_rand ( ));
|
||||
M = K;
|
||||
|
||||
flat_stable_sort (K.begin ( ), K.end ( ), comp);
|
||||
std::stable_sort (M.begin ( ), M.end ( ), comp);
|
||||
for (unsigned i = 0; i < KMax; i++) BOOST_CHECK (M[ i ] == K[ i ]);
|
||||
};
|
||||
|
||||
void test6 (void)
|
||||
{
|
||||
typedef std::less< uint64_t > compare_t;
|
||||
std::vector< uint64_t > V;
|
||||
|
||||
for (uint32_t i = 0; i < 2083333; ++i) V.push_back (i);
|
||||
flat_stable_sort(V.begin ( ), V.end ( ), compare_t ( ));
|
||||
for (uint32_t i = 0; i < V.size ( ); ++i) {
|
||||
BOOST_CHECK (V[ i ] == i);
|
||||
};
|
||||
};
|
||||
|
||||
void test7 (void)
|
||||
{
|
||||
typedef typename std::vector< uint64_t >::iterator iter_t;
|
||||
typedef std::less< uint64_t > compare_t;
|
||||
|
||||
compare_t comp;
|
||||
const uint32_t NELEM = 416667;
|
||||
const uint32_t N1 = (NELEM + 1) / 2;
|
||||
std::vector< uint64_t > A;
|
||||
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (0);
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back (NELEM - i);
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (0);
|
||||
|
||||
flat_stable_sort (A.begin ( ) + 1000,
|
||||
A.begin ( ) + (1000 + NELEM), comp);
|
||||
|
||||
for (iter_t it = A.begin ( ) + 1000; it != A.begin ( ) + (1000 + NELEM);
|
||||
++it)
|
||||
{
|
||||
BOOST_CHECK ((*(it - 1)) <= (*it));
|
||||
};
|
||||
BOOST_CHECK (A[ 998 ] == 0 and A[ 999 ] == 0 and A[ 1000 + NELEM ] == 0 and
|
||||
A[ 1001 + NELEM ] == 0);
|
||||
|
||||
|
||||
A.clear ( );
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (999999999);
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back (NELEM - i);
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (999999999);
|
||||
|
||||
flat_stable_sort (A.begin ( ) + 1000,
|
||||
A.begin ( ) + (1000 + NELEM), comp);
|
||||
|
||||
for (iter_t it = A.begin ( ) + 1001; it != A.begin ( ) + (1000 + NELEM);
|
||||
++it)
|
||||
{
|
||||
BOOST_CHECK ((*(it - 1)) <= (*it));
|
||||
};
|
||||
BOOST_CHECK (A[ 998 ] == 999999999 and A[ 999 ] == 999999999 and
|
||||
A[ 1000 + NELEM ] == 999999999 and
|
||||
A[ 1001 + NELEM ] == 999999999);
|
||||
|
||||
std::vector< uint64_t > B (N1 + 2000, 0);
|
||||
|
||||
A.clear ( );
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back (NELEM - i);
|
||||
|
||||
flat_stable_sort (A.begin ( ), A.end ( ), comp);
|
||||
for (iter_t it = A.begin ( ) + 1; it != A.end ( ); ++it) {
|
||||
if ((*(it - 1)) > (*it)) std::cout << "error 1\n";
|
||||
};
|
||||
BOOST_CHECK (B[ 998 ] == 0 and B[ 999 ] == 0 and B[ 1000 + N1 ] == 0 and
|
||||
B[ 1001 + N1 ] == 0);
|
||||
|
||||
for (uint32_t i = 0; i < B.size ( ); ++i) B[ i ] = 999999999;
|
||||
A.clear ( );
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back (NELEM - i);
|
||||
flat_stable_sort (A.begin ( ), A.end ( ), comp);
|
||||
|
||||
for (iter_t it = A.begin ( ) + 1; it != A.end ( ); ++it) {
|
||||
BOOST_CHECK ((*(it - 1)) <= (*it));
|
||||
};
|
||||
BOOST_CHECK (B[ 998 ] == 999999999 and B[ 999 ] == 999999999 and
|
||||
B[ 1000 + N1 ] == 999999999 and B[ 1001 + N1 ] == 999999999);
|
||||
};
|
||||
void test8 (void)
|
||||
{
|
||||
typedef typename std::vector<xk>::iterator iter_t;
|
||||
typedef std::less<xk> compare_t;
|
||||
std::mt19937 my_rand (0);
|
||||
std::vector<xk> V ;
|
||||
const uint32_t NELEM = 1000000;
|
||||
V.reserve(NELEM * 10);
|
||||
|
||||
|
||||
for (uint32_t k =0 ; k < 10 ; ++k)
|
||||
{ for ( uint32_t i =0 ; i < NELEM ; ++i)
|
||||
{ V.emplace_back(i , k);
|
||||
};
|
||||
iter_t first = V.begin() + (k * NELEM);
|
||||
iter_t last = first + NELEM ;
|
||||
std::shuffle( first, last, my_rand);
|
||||
};
|
||||
flat_stable_sort( V.begin() , V.end(), compare_t());
|
||||
for ( uint32_t i =0 ; i < ( NELEM * 10); ++i)
|
||||
{ BOOST_CHECK ( V[i].num == (i / 10) and V[i].tail == (i %10) );
|
||||
};
|
||||
}
|
||||
int test_main (int, char *[])
|
||||
{
|
||||
test2 ( );
|
||||
test3 ( );
|
||||
test4 ( );
|
||||
test5 ( );
|
||||
test6 ( );
|
||||
test7 ( );
|
||||
test8 ( );
|
||||
return 0;
|
||||
};
|
||||
163
test/test_insert_sort.cpp
Normal file
163
test/test_insert_sort.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file test_insert_sort.cpp
|
||||
/// @brief Test program of the insert_sort algorithm
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <ciso646>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <vector>
|
||||
#include <boost/sort/insert_sort/insert_sort.hpp>
|
||||
#include <boost/test/included/test_exec_monitor.hpp>
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
|
||||
using namespace boost::sort;
|
||||
using namespace std;
|
||||
using boost::sort::common::util::insert_sorted;
|
||||
|
||||
void test01 (void)
|
||||
{
|
||||
unsigned A[] = {7, 4, 23, 15, 17, 2, 24, 13, 8, 3, 11,
|
||||
16, 6, 14, 21, 5, 1, 12, 19, 22, 25, 8};
|
||||
|
||||
std::less< unsigned > comp;
|
||||
// Insertion Sort Unordered, not repeated
|
||||
insert_sort (&A[ 0 ], &A[ 22 ], comp);
|
||||
for (unsigned i = 0; i < 21; i++) {
|
||||
BOOST_CHECK (A[ i ] <= A[ i + 1 ]);
|
||||
};
|
||||
|
||||
unsigned B[] = {1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12,
|
||||
13, 14, 15, 17, 18, 19, 20, 21, 23, 24, 25};
|
||||
// Insertion Sort Ordered, not repeated
|
||||
insert_sort (&B[ 0 ], &B[ 22 ], comp);
|
||||
for (unsigned i = 0; i < 21; i++) {
|
||||
BOOST_CHECK (B[ i ] <= B[ i + 1 ]);
|
||||
};
|
||||
|
||||
unsigned C[] = {27, 26, 25, 23, 22, 21, 19, 18, 17, 16, 15,
|
||||
14, 13, 11, 10, 9, 8, 7, 6, 5, 3, 2};
|
||||
// Insertion Sort reverse sorted, not repeated
|
||||
insert_sort (&C[ 0 ], &C[ 22 ], comp);
|
||||
for (unsigned i = 0; i < 21; i++) {
|
||||
BOOST_CHECK (C[ i ] <= C[ i + 1 ]);
|
||||
};
|
||||
|
||||
unsigned D[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4};
|
||||
// Insertion Sort equal elements
|
||||
insert_sort (&D[ 0 ], &D[ 22 ], comp);
|
||||
for (unsigned i = 0; i < 21; i++) {
|
||||
BOOST_CHECK (D[ i ] <= D[ i + 1 ]);
|
||||
};
|
||||
|
||||
// Insertion Sort 100 random elements
|
||||
unsigned F[ 100 ];
|
||||
for (unsigned i = 0; i < 100; i++) F[ i ] = rand ( ) % 1000;
|
||||
insert_sort (&F[ 0 ], &F[ 100 ], comp);
|
||||
for (unsigned i = 0; i < 99; i++) {
|
||||
BOOST_CHECK (F[ i ] <= F[ i + 1 ]);
|
||||
};
|
||||
|
||||
const unsigned NG = 10000;
|
||||
// Insertion Sort "<<NG<<" random elements
|
||||
unsigned G[ NG ];
|
||||
for (unsigned i = 0; i < NG; i++) G[ i ] = rand ( ) % 1000;
|
||||
insert_sort (&G[ 0 ], &G[ NG ], comp);
|
||||
for (unsigned i = 0; i < NG - 1; i++) {
|
||||
BOOST_CHECK (G[ i ] <= G[ i + 1 ]);
|
||||
};
|
||||
};
|
||||
void test02 (void)
|
||||
{
|
||||
typedef typename std::vector< uint64_t >::iterator iter_t;
|
||||
const uint32_t NELEM = 6667;
|
||||
std::vector< uint64_t > A;
|
||||
std::less< uint64_t > comp;
|
||||
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (0);
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back (NELEM - i);
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (0);
|
||||
|
||||
insert_sort (A.begin ( ) + 1000, A.begin ( ) + (1000 + NELEM), comp);
|
||||
|
||||
for (iter_t it = A.begin ( ) + 1000; it != A.begin ( ) + (1000 + NELEM);
|
||||
++it)
|
||||
{
|
||||
BOOST_CHECK ((*(it - 1)) <= (*it));
|
||||
};
|
||||
BOOST_CHECK (A[ 998 ] == 0 and A[ 999 ] == 0 and A[ 1000 + NELEM ] == 0 and
|
||||
A[ 1001 + NELEM ] == 0);
|
||||
|
||||
|
||||
A.clear ( );
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (999999999);
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back (NELEM - i);
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (999999999);
|
||||
|
||||
insert_sort (A.begin ( ) + 1000, A.begin ( ) + (1000 + NELEM), comp);
|
||||
|
||||
for (iter_t it = A.begin ( ) + 1001; it != A.begin ( ) + (1000 + NELEM);
|
||||
++it)
|
||||
{
|
||||
BOOST_CHECK ((*(it - 1)) <= (*it));
|
||||
};
|
||||
BOOST_CHECK (A[ 998 ] == 999999999 and A[ 999 ] == 999999999 and
|
||||
A[ 1000 + NELEM ] == 999999999 and
|
||||
A[ 1001 + NELEM ] == 999999999);
|
||||
};
|
||||
|
||||
|
||||
void test03 ( void)
|
||||
{
|
||||
std::vector<uint32_t> V {1,3,5,2,4};
|
||||
std::less<uint32_t> comp ;
|
||||
uint32_t aux[10] ;
|
||||
|
||||
insert_sorted ( V.begin() , V.begin()+3, V.end(), comp, aux);
|
||||
//insert_partial_sort ( V.begin() , V.begin()+3, V.end() , comp);
|
||||
for ( uint32_t i =0 ; i < V.size() ; ++i)
|
||||
std::cout<<V[i]<<", ";
|
||||
std::cout<<std::endl;
|
||||
|
||||
V ={3,5,7,9,11,13,15,17,19,8,6,10,4,2};
|
||||
insert_sorted ( V.begin() , V.begin()+9, V.end() , comp, aux);
|
||||
//insert_partial_sort ( V.begin() , V.begin()+9, V.end() , comp);
|
||||
for ( uint32_t i =0 ; i < V.size() ; ++i)
|
||||
std::cout<<V[i]<<", ";
|
||||
std::cout<<std::endl;
|
||||
|
||||
V ={13,15,17,19,21,23,35,27,29,8,6,10,4,2};
|
||||
insert_sorted ( V.begin() , V.begin()+9, V.end() , comp, aux);
|
||||
//insert_partial_sort ( V.begin() , V.begin()+9, V.end() , comp);
|
||||
for ( uint32_t i =0 ; i < V.size() ; ++i)
|
||||
std::cout<<V[i]<<", ";
|
||||
std::cout<<std::endl;
|
||||
|
||||
V ={3,5,7,9,11,13,15,17,19,28,26,30,24,22};
|
||||
insert_sorted ( V.begin() , V.begin()+9, V.end() , comp, aux);
|
||||
//insert_partial_sort ( V.begin() , V.begin()+9, V.end() , comp);
|
||||
for ( uint32_t i =0 ; i < V.size() ; ++i)
|
||||
std::cout<<V[i]<<", ";
|
||||
std::cout<<std::endl;
|
||||
|
||||
|
||||
|
||||
}
|
||||
int test_main (int, char *[])
|
||||
{
|
||||
test01 ( );
|
||||
test02 ( );
|
||||
test03 ( );
|
||||
return 0;
|
||||
}
|
||||
230
test/test_parallel_stable_sort.cpp
Normal file
230
test/test_parallel_stable_sort.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file test_parallel_stable_sort.cpp
|
||||
/// @brief test program of the parallel_stable_sort algorithm
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <ciso646>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <boost/sort/parallel_stable_sort/parallel_stable_sort.hpp>
|
||||
#include <boost/test/included/test_exec_monitor.hpp>
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
using namespace std;
|
||||
namespace bsort = boost::sort::stable_detail;
|
||||
|
||||
typedef typename std::vector<uint64_t>::iterator iter_t;
|
||||
|
||||
std::mt19937_64 my_rand(0);
|
||||
|
||||
struct xk
|
||||
{
|
||||
unsigned tail : 4;
|
||||
unsigned num : 28;
|
||||
xk ( uint32_t n =0 , uint32_t t =0): tail (t), num(n){};
|
||||
bool operator< (xk A) const { return (num < A.num); };
|
||||
};
|
||||
|
||||
void test3()
|
||||
{
|
||||
typedef typename std::vector<xk>::iterator iter_t;
|
||||
typedef std::less<xk> compare;
|
||||
|
||||
const uint32_t NMAX = 500000;
|
||||
std::vector<xk> V1, V2, V3;
|
||||
V1.reserve(NMAX);
|
||||
|
||||
for (uint32_t i = 0; i < 8; ++i)
|
||||
{
|
||||
for (uint32_t k = 0; k < NMAX; ++k)
|
||||
{
|
||||
uint32_t NM = my_rand();
|
||||
xk G;
|
||||
G.num = NM >> 3;
|
||||
G.tail = i;
|
||||
V1.push_back(G);
|
||||
};
|
||||
};
|
||||
V3 = V2 = V1;
|
||||
|
||||
bsort::parallel_stable_sort<iter_t, compare>(V1.begin(), V1.end());
|
||||
std::stable_sort(V2.begin(), V2.end());
|
||||
bsort::parallel_stable_sort<iter_t, compare>(V3.begin(), V3.end(), 0);
|
||||
|
||||
BOOST_CHECK(V1.size() == V2.size());
|
||||
for (uint32_t i = 0; i < V1.size(); ++i)
|
||||
{
|
||||
BOOST_CHECK(V1[i].num == V2[i].num and V1[i].tail == V2[i].tail);
|
||||
};
|
||||
|
||||
BOOST_CHECK(V3.size() == V2.size());
|
||||
for (uint32_t i = 0; i < V3.size(); ++i)
|
||||
{
|
||||
BOOST_CHECK(V3[i].num == V2[i].num and V3[i].tail == V2[i].tail);
|
||||
};
|
||||
};
|
||||
|
||||
void test4(void)
|
||||
{
|
||||
typedef typename std::vector<uint64_t>::iterator iter_t;
|
||||
typedef std::less<uint64_t> compare;
|
||||
|
||||
const uint32_t NElem = 500000;
|
||||
std::vector<uint64_t> V1;
|
||||
std::mt19937_64 my_rand(0);
|
||||
|
||||
for (uint32_t i = 0; i < NElem; ++i)
|
||||
V1.push_back(my_rand() % NElem);
|
||||
|
||||
// parallel_stable_sort unsorted
|
||||
bsort::parallel_stable_sort<iter_t, compare>(V1.begin(), V1.end());
|
||||
for (unsigned i = 1; i < NElem; i++)
|
||||
{
|
||||
BOOST_CHECK(V1[i - 1] <= V1[i]);
|
||||
};
|
||||
|
||||
V1.clear();
|
||||
for (uint32_t i = 0; i < NElem; ++i)
|
||||
V1.push_back(i);
|
||||
|
||||
// parallel_stable_sort sorted
|
||||
bsort::parallel_stable_sort<iter_t, compare>(V1.begin(), V1.end());
|
||||
for (unsigned i = 1; i < NElem; i++)
|
||||
{
|
||||
BOOST_CHECK(V1[i - 1] <= V1[i]);
|
||||
};
|
||||
|
||||
V1.clear();
|
||||
for (uint32_t i = 0; i < NElem; ++i)
|
||||
V1.push_back(NElem - i);
|
||||
|
||||
// parallel_stable_sort reverse sorted
|
||||
bsort::parallel_stable_sort<iter_t, compare>(V1.begin(), V1.end());
|
||||
for (unsigned i = 1; i < NElem; i++)
|
||||
{
|
||||
BOOST_CHECK(V1[i - 1] <= V1[i]);
|
||||
};
|
||||
|
||||
V1.clear();
|
||||
for (uint32_t i = 0; i < NElem; ++i)
|
||||
V1.push_back(1000);
|
||||
// parallel_stable_sort equals
|
||||
bsort::parallel_stable_sort<iter_t, compare>(V1.begin(), V1.end());
|
||||
for (unsigned i = 1; i < NElem; i++)
|
||||
{
|
||||
BOOST_CHECK(V1[i - 1] == V1[i]);
|
||||
};
|
||||
};
|
||||
|
||||
void test5(void)
|
||||
{
|
||||
typedef typename std::vector<uint64_t>::iterator iter_t;
|
||||
typedef std::less<uint64_t> compare;
|
||||
|
||||
const uint32_t NELEM = 500000;
|
||||
std::vector<uint64_t> A, B;
|
||||
A.reserve(NELEM);
|
||||
|
||||
for (unsigned i = 0; i < NELEM; i++)
|
||||
A.push_back(my_rand());
|
||||
B = A;
|
||||
|
||||
bsort::parallel_stable_sort<iter_t, compare>(A.begin(), A.end());
|
||||
for (unsigned i = 0; i < (NELEM - 1); i++)
|
||||
{
|
||||
BOOST_CHECK(A[i] <= A[i + 1]);
|
||||
};
|
||||
std::stable_sort(B.begin(), B.end());
|
||||
BOOST_CHECK(A.size() == B.size());
|
||||
|
||||
for (uint32_t i = 0; i < A.size(); ++i)
|
||||
BOOST_CHECK(A[i] == B[i]);
|
||||
};
|
||||
|
||||
void test6(void)
|
||||
{
|
||||
typedef typename std::vector<uint64_t>::iterator iter_t;
|
||||
typedef std::less<uint64_t> compare;
|
||||
|
||||
const uint32_t NELEM = 500000;
|
||||
std::vector<uint64_t> A;
|
||||
A.reserve(NELEM);
|
||||
|
||||
for (unsigned i = 0; i < NELEM; i++)
|
||||
A.push_back(NELEM - i);
|
||||
|
||||
bsort::parallel_stable_sort<iter_t, compare>(A.begin(), A.end());
|
||||
for (unsigned i = 1; i < NELEM; i++)
|
||||
{
|
||||
BOOST_CHECK(A[i - 1] <= A[i]);
|
||||
};
|
||||
};
|
||||
void test7(void)
|
||||
{
|
||||
typedef typename std::vector<uint64_t>::iterator iter_t;
|
||||
typedef std::less<uint64_t> compare;
|
||||
|
||||
const uint32_t NELEM = 132000;
|
||||
std::vector<uint64_t> A, B;
|
||||
A.reserve(NELEM);
|
||||
|
||||
for (unsigned i = 0; i < NELEM; i++)
|
||||
A.push_back(my_rand());
|
||||
B = A;
|
||||
|
||||
bsort::parallel_stable_sort<iter_t, compare>(A.begin(), A.end(), 200);
|
||||
for (unsigned i = 0; i < (NELEM - 1); i++)
|
||||
{
|
||||
BOOST_CHECK(A[i] <= A[i + 1]);
|
||||
};
|
||||
std::stable_sort(B.begin(), B.end());
|
||||
BOOST_CHECK(A.size() == B.size());
|
||||
|
||||
for (uint32_t i = 0; i < A.size(); ++i)
|
||||
BOOST_CHECK(A[i] == B[i]);
|
||||
};
|
||||
void test8 (void)
|
||||
{
|
||||
typedef typename std::vector<xk>::iterator iter_t;
|
||||
typedef std::less<xk> compare_t;
|
||||
std::mt19937 my_rand (0);
|
||||
std::vector<xk> V ;
|
||||
const uint32_t NELEM = 500000;
|
||||
V.reserve(NELEM * 10);
|
||||
|
||||
|
||||
for (uint32_t k =0 ; k < 10 ; ++k)
|
||||
{ for ( uint32_t i =0 ; i < NELEM ; ++i)
|
||||
{ V.emplace_back(i , k);
|
||||
};
|
||||
iter_t first = V.begin() + (k * NELEM);
|
||||
iter_t last = first + NELEM ;
|
||||
std::shuffle( first, last, my_rand);
|
||||
};
|
||||
bsort::parallel_stable_sort<iter_t, compare_t>
|
||||
( V.begin() , V.end(), compare_t());
|
||||
for ( uint32_t i =0 ; i < ( NELEM * 10); ++i)
|
||||
{ BOOST_CHECK ( V[i].num == (i / 10) and V[i].tail == (i %10) );
|
||||
};
|
||||
}
|
||||
int test_main(int, char *[])
|
||||
{
|
||||
test3();
|
||||
test4();
|
||||
test5();
|
||||
test6();
|
||||
test7();
|
||||
test8();
|
||||
return 0;
|
||||
}
|
||||
320
test/test_sample_sort.cpp
Normal file
320
test/test_sample_sort.cpp
Normal file
@@ -0,0 +1,320 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file test_sample_sort.cpp
|
||||
/// @brief test sample_sort algorithm
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <ciso646>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <boost/sort/sample_sort/sample_sort.hpp>
|
||||
#include <boost/test/included/test_exec_monitor.hpp>
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
namespace bss = boost::sort::sample_detail;
|
||||
using namespace boost::sort::common;
|
||||
|
||||
std::mt19937_64 my_rand(0);
|
||||
|
||||
void test3();
|
||||
void test4();
|
||||
void test5();
|
||||
void test6();
|
||||
void test7();
|
||||
void test8();
|
||||
void test9();
|
||||
|
||||
struct xk
|
||||
{
|
||||
unsigned tail : 4;
|
||||
unsigned num : 28;
|
||||
xk ( uint32_t n =0 , uint32_t t =0): tail (t), num(n){};
|
||||
bool operator< (xk A) const { return (num < A.num); };
|
||||
};
|
||||
void test3()
|
||||
{
|
||||
typedef typename std::vector<xk>::iterator iter_t;
|
||||
typedef std::less<xk> compare;
|
||||
|
||||
std::mt19937_64 my_rand(0);
|
||||
|
||||
const uint32_t NMAX = 500000;
|
||||
|
||||
std::vector<xk> V1, V2, V3;
|
||||
V1.reserve(NMAX);
|
||||
for (uint32_t i = 0; i < 8; ++i)
|
||||
{
|
||||
for (uint32_t k = 0; k < NMAX; ++k)
|
||||
{
|
||||
uint32_t NM = my_rand();
|
||||
xk G;
|
||||
G.num = NM >> 3;
|
||||
G.tail = i;
|
||||
V1.push_back(G);
|
||||
};
|
||||
};
|
||||
V3 = V2 = V1;
|
||||
bss::sample_sort<iter_t, compare>(V1.begin(), V1.end());
|
||||
std::stable_sort(V2.begin(), V2.end());
|
||||
bss::sample_sort<iter_t, compare>(V3.begin(), V3.end(), 0);
|
||||
|
||||
BOOST_CHECK(V1.size() == V2.size());
|
||||
for (uint32_t i = 0; i < V1.size(); ++i)
|
||||
{
|
||||
BOOST_CHECK(V1[i].num == V2[i].num and V1[i].tail == V2[i].tail);
|
||||
};
|
||||
|
||||
BOOST_CHECK(V3.size() == V2.size());
|
||||
for (uint32_t i = 0; i < V3.size(); ++i)
|
||||
{
|
||||
BOOST_CHECK(V3[i].num == V2[i].num and V3[i].tail == V2[i].tail);
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
void test4(void)
|
||||
{
|
||||
typedef typename std::vector<uint64_t>::iterator iter_t;
|
||||
typedef std::less<uint64_t> compare;
|
||||
|
||||
const uint32_t NElem = 500000;
|
||||
std::vector<uint64_t> V1;
|
||||
std::mt19937_64 my_rand(0);
|
||||
|
||||
for (uint32_t i = 0; i < NElem; ++i)
|
||||
V1.push_back(my_rand() % NElem);
|
||||
|
||||
// bss::sample_sort unsorted
|
||||
bss::sample_sort<iter_t, compare>(V1.begin(), V1.end());
|
||||
for (unsigned i = 1; i < NElem; i++)
|
||||
{
|
||||
BOOST_CHECK(V1[i - 1] <= V1[i]);
|
||||
};
|
||||
|
||||
V1.clear();
|
||||
for (uint32_t i = 0; i < NElem; ++i)
|
||||
V1.push_back(i);
|
||||
|
||||
// bss::sample_sort sorted
|
||||
bss::sample_sort<iter_t, compare>(V1.begin(), V1.end());
|
||||
for (unsigned i = 1; i < NElem; i++)
|
||||
{
|
||||
BOOST_CHECK(V1[i - 1] <= V1[i]);
|
||||
};
|
||||
|
||||
V1.clear();
|
||||
for (uint32_t i = 0; i < NElem; ++i)
|
||||
V1.push_back(NElem - i);
|
||||
|
||||
// bss::sample_sort reverse sorted
|
||||
bss::sample_sort<iter_t, compare>(V1.begin(), V1.end());
|
||||
for (unsigned i = 1; i < NElem; i++)
|
||||
{
|
||||
BOOST_CHECK(V1[i - 1] <= V1[i]);
|
||||
};
|
||||
|
||||
V1.clear();
|
||||
for (uint32_t i = 0; i < NElem; ++i)
|
||||
V1.push_back(1000);
|
||||
|
||||
// bss::sample_sort equals
|
||||
bss::sample_sort<iter_t, compare>(V1.begin(), V1.end());
|
||||
for (unsigned i = 1; i < NElem; i++)
|
||||
{
|
||||
BOOST_CHECK(V1[i - 1] == V1[i]);
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
void test5(void)
|
||||
{
|
||||
typedef typename std::vector<uint64_t>::iterator iter_t;
|
||||
typedef std::less<uint64_t> compare;
|
||||
const uint32_t KMax = 500000;
|
||||
|
||||
std::vector<uint64_t> K, M;
|
||||
std::mt19937_64 my_rand(0);
|
||||
std::less<uint64_t> comp;
|
||||
|
||||
for (uint32_t i = 0; i < KMax; ++i)
|
||||
K.push_back(my_rand());
|
||||
M = K;
|
||||
|
||||
// bss::sample_sort - random elements
|
||||
uint64_t *Ptr = std::get_temporary_buffer<uint64_t>(KMax).first;
|
||||
if (Ptr == nullptr) throw std::bad_alloc();
|
||||
range<uint64_t *> Rbuf(Ptr, Ptr + KMax);
|
||||
|
||||
bss::sample_sort<iter_t, compare>(K.begin(), K.end(), comp,
|
||||
std::thread::hardware_concurrency(), Rbuf);
|
||||
|
||||
std::return_temporary_buffer(Ptr);
|
||||
|
||||
std::stable_sort(M.begin(), M.end(), comp);
|
||||
for (unsigned i = 0; i < KMax; i++)
|
||||
BOOST_CHECK(M[i] == K[i]);
|
||||
}
|
||||
;
|
||||
|
||||
void test6(void)
|
||||
{
|
||||
typedef typename std::vector<uint64_t>::iterator iter_t;
|
||||
typedef std::less<uint64_t> compare;
|
||||
std::vector<uint64_t> V;
|
||||
|
||||
for (uint32_t i = 0; i < 2083333; ++i)
|
||||
V.push_back(i);
|
||||
bss::sample_sort<iter_t, compare>(V.begin(), V.end());
|
||||
for (uint32_t i = 0; i < V.size(); ++i)
|
||||
{
|
||||
BOOST_CHECK(V[i] == i);
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
void test7(void)
|
||||
{
|
||||
typedef typename std::vector<uint64_t>::iterator iter_t;
|
||||
typedef std::less<uint64_t> compare;
|
||||
|
||||
const uint32_t NELEM = 416667;
|
||||
std::vector<uint64_t> A;
|
||||
|
||||
for (uint32_t i = 0; i < 1000; ++i)
|
||||
A.push_back(0);
|
||||
for (uint32_t i = 0; i < NELEM; ++i)
|
||||
A.push_back(NELEM - i);
|
||||
for (uint32_t i = 0; i < 1000; ++i)
|
||||
A.push_back(0);
|
||||
|
||||
bss::sample_sort<iter_t, compare>(A.begin() + 1000,
|
||||
A.begin() + (1000 + NELEM));
|
||||
|
||||
for (iter_t it = A.begin() + 1000; it != A.begin() + (1000 + NELEM); ++it)
|
||||
{
|
||||
BOOST_CHECK((*(it - 1)) <= (*it));
|
||||
};
|
||||
|
||||
BOOST_CHECK (A[998] == 0 and A[999] == 0 and A[1000 + NELEM] == 0
|
||||
and A[1001 + NELEM] == 0);
|
||||
|
||||
A.clear();
|
||||
for (uint32_t i = 0; i < 1000; ++i)
|
||||
A.push_back(999999999);
|
||||
for (uint32_t i = 0; i < NELEM; ++i)
|
||||
A.push_back(NELEM - i);
|
||||
for (uint32_t i = 0; i < 1000; ++i)
|
||||
A.push_back(999999999);
|
||||
|
||||
bss::sample_sort<iter_t, compare>
|
||||
(A.begin() + 1000, A.begin() + (1000 + NELEM));
|
||||
|
||||
for (iter_t it = A.begin() + 1001; it != A.begin() + (1000 + NELEM); ++it)
|
||||
{
|
||||
BOOST_CHECK((*(it - 1)) <= (*it));
|
||||
};
|
||||
BOOST_CHECK (A[998] == 999999999
|
||||
and A[999] == 999999999
|
||||
and A[1000 + NELEM] == 999999999
|
||||
and A[1001 + NELEM] == 999999999);
|
||||
|
||||
std::vector<uint64_t> B(NELEM + 2000, 0);
|
||||
|
||||
A.clear();
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back(NELEM - i);
|
||||
|
||||
range<uint64_t *> Rbuf(&B[1000], (&B[1000]) + NELEM);
|
||||
bss::sample_sort<iter_t, compare>
|
||||
( A.begin(), A.end(), std::less<uint64_t>(),
|
||||
std::thread::hardware_concurrency(), Rbuf);
|
||||
|
||||
for (iter_t it = A.begin() + 1; it != A.end(); ++it)
|
||||
{
|
||||
BOOST_CHECK((*(it - 1)) <= (*it));
|
||||
};
|
||||
BOOST_CHECK (B[998] == 0 and B[999] == 0 and B[1000 + NELEM] == 0
|
||||
and B[1001 + NELEM] == 0);
|
||||
|
||||
for (uint32_t i = 0; i < B.size(); ++i) B[i] = 999999999;
|
||||
A.clear();
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back(NELEM - i);
|
||||
|
||||
bss::sample_sort<iter_t, std::less<uint64_t> >
|
||||
(A.begin(), A.end(), std::less<uint64_t>(),
|
||||
std::thread::hardware_concurrency(), Rbuf);
|
||||
|
||||
for (iter_t it = A.begin() + 1; it != A.end(); ++it)
|
||||
{
|
||||
if ((*(it - 1)) > (*it)) std::cout << "error 2\n";
|
||||
};
|
||||
BOOST_CHECK (B[998] == 999999999 and B[999] == 999999999
|
||||
and B[1000 + NELEM] == 999999999
|
||||
and B[1001 + NELEM] == 999999999);
|
||||
}
|
||||
;
|
||||
void test8(void)
|
||||
{
|
||||
typedef typename std::vector<uint64_t>::iterator iter_t;
|
||||
typedef std::less<uint64_t> compare;
|
||||
const uint32_t KMax = 66000;
|
||||
|
||||
std::vector<uint64_t> K, M;
|
||||
std::mt19937_64 my_rand(0);
|
||||
std::less<uint64_t> comp;
|
||||
|
||||
for (uint32_t i = 0; i < KMax; ++i)
|
||||
K.push_back(my_rand());
|
||||
M = K;
|
||||
|
||||
bss::sample_sort<iter_t, compare>(K.begin(), K.end(), 300);
|
||||
|
||||
std::stable_sort(M.begin(), M.end(), comp);
|
||||
for (unsigned i = 0; i < KMax; i++)
|
||||
BOOST_CHECK(M[i] == K[i]);
|
||||
};
|
||||
|
||||
void test9 (void)
|
||||
{
|
||||
typedef typename std::vector<xk>::iterator iter_t;
|
||||
typedef std::less<xk> compare_t;
|
||||
std::mt19937 my_rand (0);
|
||||
std::vector<xk> V ;
|
||||
const uint32_t NELEM = 500000;
|
||||
V.reserve(NELEM * 10);
|
||||
|
||||
|
||||
for (uint32_t k =0 ; k < 10 ; ++k)
|
||||
{ for ( uint32_t i =0 ; i < NELEM ; ++i)
|
||||
{ V.emplace_back(i , k);
|
||||
};
|
||||
iter_t first = V.begin() + (k * NELEM);
|
||||
iter_t last = first + NELEM ;
|
||||
std::shuffle( first, last, my_rand);
|
||||
};
|
||||
bss::sample_sort<iter_t, compare_t>( V.begin() , V.end(), compare_t());
|
||||
for ( uint32_t i =0 ; i < ( NELEM * 10); ++i)
|
||||
{ BOOST_CHECK ( V[i].num == (i / 10) and V[i].tail == (i %10) );
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
int test_main(int, char *[])
|
||||
{
|
||||
test3();
|
||||
test4();
|
||||
test5();
|
||||
test6();
|
||||
test7();
|
||||
test8();
|
||||
test9();
|
||||
return 0;
|
||||
};
|
||||
430
test/test_spinsort.cpp
Normal file
430
test/test_spinsort.cpp
Normal file
@@ -0,0 +1,430 @@
|
||||
//----------------------------------------------------------------------------
|
||||
/// @file test_spinsort.cpp
|
||||
/// @brief test program of the spinsort algorithm
|
||||
///
|
||||
/// @author Copyright (c) 2016 Francisco José Tapia (fjtapia@gmail.com )\n
|
||||
/// Distributed under the Boost Software License, Version 1.0.\n
|
||||
/// ( See accompanying file LICENSE_1_0.txt or copy at
|
||||
/// http://www.boost.org/LICENSE_1_0.txt )
|
||||
/// @version 0.1
|
||||
///
|
||||
/// @remarks
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <ciso646>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <boost/sort/spinsort/spinsort.hpp>
|
||||
#include <boost/test/included/test_exec_monitor.hpp>
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
|
||||
using namespace boost::sort;
|
||||
using spin_detail::check_stable_sort;
|
||||
using spin_detail::range_sort;
|
||||
using common::range;
|
||||
|
||||
void test2 ( );
|
||||
void test3 ( );
|
||||
void test4 ( );
|
||||
void test5 ( );
|
||||
void test6 ( );
|
||||
void test7 ( );
|
||||
|
||||
struct xk
|
||||
{
|
||||
unsigned tail : 4;
|
||||
unsigned num : 28;
|
||||
xk ( uint32_t n =0 , uint32_t t =0): tail (t), num(n){};
|
||||
bool operator< (xk A) const { return (num < A.num); };
|
||||
};
|
||||
|
||||
void test1 ( )
|
||||
{
|
||||
|
||||
std::mt19937_64 my_rand (0);
|
||||
typedef typename std::vector< uint64_t >::iterator iter_t;
|
||||
typedef std::less< uint64_t > compare;
|
||||
typedef range< iter_t > range_it;
|
||||
|
||||
std::vector< uint64_t > V1, V2, V3;
|
||||
uint32_t NELEM = 0;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Range of 40 , randomly filled level 1
|
||||
//----------------------------------------------------------------------
|
||||
NELEM = 40;
|
||||
for (uint32_t i = 0; i < NELEM; ++i) {
|
||||
V1.push_back (my_rand ( ) % 10000);
|
||||
};
|
||||
V2 = V1;
|
||||
range_it R2 (V2.begin ( ), V2.end ( ));
|
||||
|
||||
V3.resize (NELEM, 0);
|
||||
range_it RAux (V3.begin ( ), V3.end ( ));
|
||||
range_sort (R2, RAux, compare ( ), 1);
|
||||
|
||||
std::sort (V1.begin ( ), V1.end ( ));
|
||||
|
||||
for (uint32_t i = 0; i < NELEM; ++i) {
|
||||
BOOST_CHECK (V1[ i ] == V3[ i ]);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Range of 75, randomly filled , level 2
|
||||
//---------------------------------------------------------------------
|
||||
V1.clear ( );
|
||||
V2.clear ( );
|
||||
V3.clear ( );
|
||||
NELEM = 75;
|
||||
|
||||
for (uint32_t i = 0; i < NELEM; ++i) {
|
||||
V1.push_back (my_rand ( ) % 10000);
|
||||
};
|
||||
V2 = V1;
|
||||
R2 = range_it (V2.begin ( ), V2.end ( ));
|
||||
|
||||
V3.resize (NELEM, 0);
|
||||
RAux = range_it (V3.begin ( ), V3.end ( ));
|
||||
range_sort (RAux, R2, compare ( ), 2);
|
||||
std::sort (V1.begin ( ), V1.end ( ));
|
||||
|
||||
for (uint32_t i = 0; i < NELEM; ++i) {
|
||||
BOOST_CHECK (V1[ i ] == V2[ i ]);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Range of 200, randomly filled , level 3
|
||||
//---------------------------------------------------------------------
|
||||
V1.clear ( );
|
||||
V2.clear ( );
|
||||
V3.clear ( );
|
||||
NELEM = 200;
|
||||
|
||||
for (uint32_t i = 0; i < NELEM; ++i) {
|
||||
V1.push_back (my_rand ( ) % 10000);
|
||||
};
|
||||
V2 = V1;
|
||||
R2 = range_it (V2.begin ( ), V2.end ( ));
|
||||
|
||||
V3.resize (NELEM, 0);
|
||||
RAux = range_it (V3.begin ( ), V3.end ( ));
|
||||
|
||||
range_sort (R2, RAux, compare ( ), 3);
|
||||
|
||||
std::sort (V1.begin ( ), V1.end ( ));
|
||||
|
||||
for (uint32_t i = 0; i < NELEM; ++i) {
|
||||
BOOST_CHECK (V1[ i ] == V3[ i ]);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Range of 400, randomly filled , level 4
|
||||
//---------------------------------------------------------------------
|
||||
V1.clear ( );
|
||||
V2.clear ( );
|
||||
V3.clear ( );
|
||||
NELEM = 400;
|
||||
|
||||
for (uint32_t i = 0; i < NELEM; ++i) {
|
||||
V1.push_back (my_rand ( ) % 10000);
|
||||
};
|
||||
V2 = V1;
|
||||
R2 = range_it (V2.begin ( ), V2.end ( ));
|
||||
|
||||
V3.resize (NELEM, 0);
|
||||
RAux = range_it (V3.begin ( ), V3.end ( ));
|
||||
|
||||
range_sort (RAux, R2, compare ( ), 4);
|
||||
std::sort (V1.begin ( ), V1.end ( ));
|
||||
|
||||
for (uint32_t i = 0; i < NELEM; ++i) {
|
||||
BOOST_CHECK (V1[ i ] == V2[ i ]);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
void test2 ( )
|
||||
{
|
||||
uint64_t V1[ 300 ];
|
||||
typedef std::less< uint64_t > compare_t;
|
||||
compare_t comp;
|
||||
|
||||
for (uint32_t i = 0; i < 200; ++i) V1[ i ] = i;
|
||||
indirect_spinsort (&V1[ 0 ], &V1[ 200 ], comp);
|
||||
//spinsort< uint64_t *, compare_t > (&V1[ 0 ], &V1[ 200 ], comp);
|
||||
for (unsigned i = 1; i < 200; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < 200; ++i) V1[ i ] = 199 - i;
|
||||
spinsort< uint64_t *, compare_t > (&V1[ 0 ], &V1[ 200 ], comp);
|
||||
for (unsigned i = 1; i < 200; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < 300; ++i) V1[ i ] = 299 - i;
|
||||
|
||||
spinsort< uint64_t *, compare_t > (&V1[ 0 ], &V1[ 300 ], comp);
|
||||
for (unsigned i = 1; i < 300; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < 300; ++i) V1[ i ] = 88;
|
||||
|
||||
spinsort< uint64_t *, compare_t > (&V1[ 0 ], &V1[ 300 ], comp);
|
||||
for (unsigned i = 1; i < 300; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
};
|
||||
|
||||
void test3 ( )
|
||||
{
|
||||
typedef typename std::vector< xk >::iterator iter_t;
|
||||
typedef std::less< xk > compare_t;
|
||||
std::mt19937_64 my_rand (0);
|
||||
|
||||
const uint32_t NMAX = 500000;
|
||||
|
||||
|
||||
std::vector< xk > V1, V2, V3;
|
||||
V1.reserve (NMAX);
|
||||
for (uint32_t i = 0; i < 8; ++i) {
|
||||
for (uint32_t k = 0; k < NMAX; ++k) {
|
||||
uint32_t NM = my_rand ( );
|
||||
xk G;
|
||||
G.num = NM >> 3;
|
||||
G.tail = i;
|
||||
V1.push_back (G);
|
||||
};
|
||||
};
|
||||
V3 = V2 = V1;
|
||||
spinsort< iter_t, compare_t > (V1.begin ( ), V1.end ( ), compare_t ( ));
|
||||
std::stable_sort (V2.begin ( ), V2.end ( ));
|
||||
|
||||
BOOST_CHECK (V1.size ( ) == V2.size ( ));
|
||||
for (uint32_t i = 0; i < V1.size ( ); ++i) {
|
||||
BOOST_CHECK (V1[ i ].num == V2[ i ].num and
|
||||
V1[ i ].tail == V2[ i ].tail);
|
||||
};
|
||||
};
|
||||
|
||||
void test4 (void)
|
||||
{
|
||||
typedef std::less< uint64_t > compare_t;
|
||||
typedef typename std::vector< uint64_t >::iterator iter_t;
|
||||
|
||||
const uint32_t NElem = 500000;
|
||||
std::vector< uint64_t > V1;
|
||||
std::mt19937_64 my_rand (0);
|
||||
compare_t comp;
|
||||
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (my_rand ( ) % NElem);
|
||||
|
||||
spinsort< iter_t, compare_t > (V1.begin ( ), V1.end ( ), comp);
|
||||
for (unsigned i = 1; i < NElem; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
V1.clear ( );
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (i);
|
||||
spinsort< iter_t, compare_t > (V1.begin ( ), V1.end ( ), comp);
|
||||
for (unsigned i = 1; i < NElem; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
V1.clear ( );
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (NElem - i);
|
||||
spinsort< iter_t, compare_t > (V1.begin ( ), V1.end ( ), comp);
|
||||
for (unsigned i = 1; i < NElem; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] <= V1[ i ]);
|
||||
};
|
||||
|
||||
V1.clear ( );
|
||||
for (uint32_t i = 0; i < NElem; ++i) V1.push_back (1000);
|
||||
spinsort< iter_t, compare_t > (V1.begin ( ), V1.end ( ), comp);
|
||||
for (unsigned i = 1; i < NElem; i++) {
|
||||
BOOST_CHECK (V1[ i - 1 ] == V1[ i ]);
|
||||
};
|
||||
};
|
||||
|
||||
void test5 (void)
|
||||
{
|
||||
typedef std::vector< uint64_t >::iterator iter_t;
|
||||
typedef std::less< uint64_t > compare;
|
||||
|
||||
const uint32_t KMax = 500000;
|
||||
|
||||
std::vector< uint64_t > K, M;
|
||||
std::mt19937_64 my_rand (0);
|
||||
compare comp;
|
||||
|
||||
for (uint32_t i = 0; i < KMax; ++i) K.push_back (my_rand ( ));
|
||||
M = K;
|
||||
|
||||
uint64_t *Ptr = std::get_temporary_buffer< uint64_t > (KMax >> 1).first;
|
||||
if (Ptr == nullptr) throw std::bad_alloc ( );
|
||||
range< uint64_t * > Rbuf (Ptr, Ptr + (KMax >> 1));
|
||||
|
||||
spin_detail::spinsort< iter_t, compare > (K.begin ( ), K.end ( ), comp, Rbuf);
|
||||
|
||||
std::return_temporary_buffer (Ptr);
|
||||
|
||||
std::stable_sort (M.begin ( ), M.end ( ), comp);
|
||||
for (unsigned i = 0; i < KMax; i++) BOOST_CHECK (M[ i ] == K[ i ]);
|
||||
};
|
||||
|
||||
void test6 (void)
|
||||
{
|
||||
typedef std::vector< uint64_t >::iterator iter_t;
|
||||
typedef std::less< uint64_t > compare_t;
|
||||
std::vector< uint64_t > V;
|
||||
|
||||
for (uint32_t i = 0; i < 2083333; ++i) V.push_back (i);
|
||||
spinsort< iter_t, compare_t > (V.begin ( ), V.end ( ), compare_t ( ));
|
||||
for (uint32_t i = 0; i < V.size ( ); ++i) {
|
||||
BOOST_CHECK (V[ i ] == i);
|
||||
};
|
||||
};
|
||||
|
||||
void test7 (void)
|
||||
{
|
||||
typedef typename std::vector< uint64_t >::iterator iter_t;
|
||||
typedef std::less< uint64_t > compare_t;
|
||||
|
||||
compare_t comp;
|
||||
const uint32_t NELEM = 416667;
|
||||
const uint32_t N1 = (NELEM + 1) / 2;
|
||||
std::vector< uint64_t > A;
|
||||
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (0);
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back (NELEM - i);
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (0);
|
||||
|
||||
spinsort< iter_t, compare_t > (A.begin ( ) + 1000,
|
||||
A.begin ( ) + (1000 + NELEM), comp);
|
||||
|
||||
for (iter_t it = A.begin ( ) + 1000; it != A.begin ( ) + (1000 + NELEM);
|
||||
++it)
|
||||
{
|
||||
BOOST_CHECK ((*(it - 1)) <= (*it));
|
||||
};
|
||||
BOOST_CHECK (A[ 998 ] == 0 and A[ 999 ] == 0 and A[ 1000 + NELEM ] == 0 and
|
||||
A[ 1001 + NELEM ] == 0);
|
||||
|
||||
|
||||
A.clear ( );
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (999999999);
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back (NELEM - i);
|
||||
for (uint32_t i = 0; i < 1000; ++i) A.push_back (999999999);
|
||||
|
||||
spinsort< iter_t, compare_t > (A.begin ( ) + 1000,
|
||||
A.begin ( ) + (1000 + NELEM), comp);
|
||||
|
||||
for (iter_t it = A.begin ( ) + 1001; it != A.begin ( ) + (1000 + NELEM);
|
||||
++it)
|
||||
{
|
||||
BOOST_CHECK ((*(it - 1)) <= (*it));
|
||||
};
|
||||
BOOST_CHECK (A[ 998 ] == 999999999 and A[ 999 ] == 999999999 and
|
||||
A[ 1000 + NELEM ] == 999999999 and
|
||||
A[ 1001 + NELEM ] == 999999999);
|
||||
|
||||
std::vector< uint64_t > B (N1 + 2000, 0);
|
||||
|
||||
A.clear ( );
|
||||
range< uint64_t * > Rbuf (&B[ 1000 ], (&B[ 1000 ]) + N1);
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back (NELEM - i);
|
||||
|
||||
spin_detail::spinsort< iter_t, compare_t > (A.begin ( ), A.end ( ),
|
||||
comp, Rbuf);
|
||||
for (iter_t it = A.begin ( ) + 1; it != A.end ( ); ++it) {
|
||||
if ((*(it - 1)) > (*it)) std::cout << "error 1\n";
|
||||
};
|
||||
BOOST_CHECK (B[ 998 ] == 0 and B[ 999 ] == 0 and B[ 1000 + N1 ] == 0 and
|
||||
B[ 1001 + N1 ] == 0);
|
||||
|
||||
for (uint32_t i = 0; i < B.size ( ); ++i) B[ i ] = 999999999;
|
||||
A.clear ( );
|
||||
for (uint32_t i = 0; i < NELEM; ++i) A.push_back (NELEM - i);
|
||||
spin_detail::spinsort< iter_t, compare_t > (A.begin ( ), A.end ( ),
|
||||
comp, Rbuf);
|
||||
|
||||
for (iter_t it = A.begin ( ) + 1; it != A.end ( ); ++it) {
|
||||
BOOST_CHECK ((*(it - 1)) <= (*it));
|
||||
};
|
||||
BOOST_CHECK (B[ 998 ] == 999999999 and B[ 999 ] == 999999999 and
|
||||
B[ 1000 + N1 ] == 999999999 and B[ 1001 + N1 ] == 999999999);
|
||||
};
|
||||
void test8 (void)
|
||||
{
|
||||
typedef typename std::vector<uint64_t>::iterator iter_t ;
|
||||
typedef range<iter_t> range_it ;
|
||||
std::less<uint64_t> comp ;
|
||||
|
||||
std::vector<uint64_t> V = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19,
|
||||
21, 23, 25, 27, 29, 31, 33, 35, 37, 39,
|
||||
41, 43, 45, 47, 49, 51, 53, 55, 57, 59,
|
||||
14, 2, 4, 6, 8, 10, 12, 16, 18, 20};
|
||||
range_it rdata (V.begin() , V.end());
|
||||
std::vector<uint64_t> aux (40,0 );
|
||||
range_it raux ( aux.begin() , aux.end());
|
||||
|
||||
check_stable_sort ( rdata, raux, comp );
|
||||
for ( uint32_t i =0 ; i < V.size() ; ++i)
|
||||
std::cout<<V[i]<<", ";
|
||||
std::cout<<std::endl;
|
||||
|
||||
V = {59, 57, 55, 53, 51, 49, 47, 45, 43, 41,
|
||||
39, 37, 35, 33, 31, 29, 27, 25, 23, 21,
|
||||
19, 17, 15, 13, 11, 9, 7, 5, 3, 1,
|
||||
14, 2, 6, 16, 18, 20, 12, 4, 8, 10};
|
||||
rdata = range_it (V.begin() , V.end());
|
||||
aux.assign (40,0);
|
||||
raux = range_it ( aux.begin() , aux.end());
|
||||
check_stable_sort ( rdata, raux, comp );
|
||||
for ( uint32_t i =0 ; i < V.size() ; ++i)
|
||||
std::cout<<V[i]<<", ";
|
||||
std::cout<<std::endl;
|
||||
|
||||
}
|
||||
void test9 (void)
|
||||
{
|
||||
typedef typename std::vector<xk>::iterator iter_t;
|
||||
typedef std::less<xk> compare_t;
|
||||
std::mt19937 my_rand (0);
|
||||
std::vector<xk> V ;
|
||||
const uint32_t NELEM = 1000000;
|
||||
V.reserve(NELEM * 10);
|
||||
|
||||
|
||||
for (uint32_t k =0 ; k < 10 ; ++k)
|
||||
{ for ( uint32_t i =0 ; i < NELEM ; ++i)
|
||||
{ V.emplace_back(i , k);
|
||||
};
|
||||
iter_t first = V.begin() + (k * NELEM);
|
||||
iter_t last = first + NELEM ;
|
||||
std::shuffle( first, last, my_rand);
|
||||
};
|
||||
spinsort( V.begin() , V.end(), compare_t());
|
||||
for ( uint32_t i =0 ; i < ( NELEM * 10); ++i)
|
||||
{ BOOST_CHECK ( V[i].num == (i / 10) and V[i].tail == (i %10) );
|
||||
};
|
||||
}
|
||||
int test_main (int, char *[])
|
||||
{
|
||||
test1 ( );
|
||||
test2 ( );
|
||||
test3 ( );
|
||||
test4 ( );
|
||||
test5 ( );
|
||||
test6 ( );
|
||||
test7 ( );
|
||||
test8 ( );
|
||||
test9 ( );
|
||||
return 0;
|
||||
};
|
||||
Reference in New Issue
Block a user