Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 40 additions & 15 deletions include/boost/sort/spreadsort/detail/float_sort.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,36 @@ namespace spreadsort {
Div_type & max, Div_type & min, Right_shift rshift)
{
min = max = rshift(*current, 0);
Div_type prev = min;
RandomAccessIter prev = current;
bool sorted = true;
while (++current < last) {
Div_type value = rshift(*current, 0);
sorted &= value >= prev;
prev = value;
sorted &= *current >= *prev;
prev = current;
if (max < value)
max = value;
else if (value < min)
min = value;
}
return sorted;
}

// Return true if the list is sorted. Otherwise, find the minimum and
// maximum. Uses comp to check if the data is already sorted.
template <class RandomAccessIter, class Div_type, class Right_shift,
class Compare>
inline bool
is_sorted_or_find_extremes(RandomAccessIter current, RandomAccessIter last,
Div_type & max, Div_type & min,
Right_shift rshift, Compare comp)
{
min = max = rshift(*current, 0);
RandomAccessIter prev = current;
bool sorted = true;
while (++current < last) {
Div_type value = rshift(*current, 0);
sorted &= !comp(*current, *prev);
prev = current;
if (max < value)
max = value;
else if (value < min)
Expand Down Expand Up @@ -123,12 +147,12 @@ namespace spreadsort {
Cast_type & max, Cast_type & min)
{
min = max = cast_float_iter<Cast_type, RandomAccessIter>(current);
Cast_type prev = min;
RandomAccessIter prev = current;
bool sorted = true;
while (++current < last) {
Cast_type value = cast_float_iter<Cast_type, RandomAccessIter>(current);
sorted &= value >= prev;
prev = value;
sorted &= *current >= *prev;
prev = current;
if (max < value)
max = value;
else if (value < min)
Expand Down Expand Up @@ -205,8 +229,9 @@ namespace spreadsort {
{
Div_type max, min;
if (is_sorted_or_find_extremes<RandomAccessIter, Div_type>(first, last,
max, min))
max, min))
return;

unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
last - first, rough_log_2_size(Size_type(max - min)));
Div_type div_min = min >> log_divisor;
Expand Down Expand Up @@ -323,7 +348,7 @@ namespace spreadsort {
size_t *bin_sizes, Right_shift rshift, Compare comp)
{
Div_type max, min;
if (is_sorted_or_find_extremes(first, last, max, min, rshift))
if (is_sorted_or_find_extremes(first, last, max, min, rshift, comp))
return;
unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
last - first, rough_log_2_size(Size_type(max - min)));
Expand Down Expand Up @@ -578,7 +603,7 @@ namespace spreadsort {
size_t *bin_sizes, Right_shift rshift, Compare comp)
{
Div_type max, min;
if (is_sorted_or_find_extremes(first, last, max, min, rshift))
if (is_sorted_or_find_extremes(first, last, max, min, rshift, comp))
return;
unsigned log_divisor = get_log_divisor<float_log_mean_bin_size>(
last - first, rough_log_2_size(Size_type(max - min)));
Expand Down Expand Up @@ -679,7 +704,7 @@ namespace spreadsort {
void >::type
float_sort(RandomAccessIter first, RandomAccessIter last)
{
size_t bin_sizes[1 << max_splits];
size_t bin_sizes[1 << max_finishing_splits];
std::vector<RandomAccessIter> bin_cache;
float_sort_rec<RandomAccessIter, boost::int32_t, boost::uint32_t>
(first, last, bin_cache, 0, bin_sizes);
Expand All @@ -694,7 +719,7 @@ namespace spreadsort {
void >::type
float_sort(RandomAccessIter first, RandomAccessIter last)
{
size_t bin_sizes[1 << max_splits];
size_t bin_sizes[1 << max_finishing_splits];
std::vector<RandomAccessIter> bin_cache;
float_sort_rec<RandomAccessIter, boost::int64_t, boost::uint64_t>
(first, last, bin_cache, 0, bin_sizes);
Expand Down Expand Up @@ -727,7 +752,7 @@ namespace spreadsort {
float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
Right_shift rshift)
{
size_t bin_sizes[1 << max_splits];
size_t bin_sizes[1 << max_finishing_splits];
std::vector<RandomAccessIter> bin_cache;
float_sort_rec<RandomAccessIter, Div_type, Right_shift, size_t>
(first, last, bin_cache, 0, bin_sizes, rshift);
Expand All @@ -740,7 +765,7 @@ namespace spreadsort {
float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
Right_shift rshift)
{
size_t bin_sizes[1 << max_splits];
size_t bin_sizes[1 << max_finishing_splits];
std::vector<RandomAccessIter> bin_cache;
float_sort_rec<RandomAccessIter, Div_type, Right_shift, boost::uintmax_t>
(first, last, bin_cache, 0, bin_sizes, rshift);
Expand All @@ -765,7 +790,7 @@ namespace spreadsort {
float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
Right_shift rshift, Compare comp)
{
size_t bin_sizes[1 << max_splits];
size_t bin_sizes[1 << max_finishing_splits];
std::vector<RandomAccessIter> bin_cache;
float_sort_rec<RandomAccessIter, Div_type, Right_shift, Compare,
size_t>
Expand All @@ -780,7 +805,7 @@ namespace spreadsort {
float_sort(RandomAccessIter first, RandomAccessIter last, Div_type,
Right_shift rshift, Compare comp)
{
size_t bin_sizes[1 << max_splits];
size_t bin_sizes[1 << max_finishing_splits];
std::vector<RandomAccessIter> bin_cache;
float_sort_rec<RandomAccessIter, Div_type, Right_shift, Compare,
boost::uintmax_t>
Expand Down
2 changes: 1 addition & 1 deletion include/boost/sort/spreadsort/detail/string_sort.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace spreadsort {
{
const int char_size = sizeof(Unsigned_char_type);
size_t nextOffset = char_offset;
int step_size = max_step_size;
int step_size = max_step_size / char_size;
while (true) {
RandomAccessIter curr = first;
do {
Expand Down
32 changes: 28 additions & 4 deletions include/boost/sort/spreadsort/spreadsort.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ namespace spreadsort {
}

/*!
\brief Generic @c spreadsort variant detecting string element type so call to @c string_sort for @c std::strings and @c std::wstrings.
\details If the data type provided is a string or wstring, @c string_sort is used.
\brief Generic @c spreadsort variant detecting string element type so call to @c string_sort for @c std::strings.
\details If the data type provided is a string, @c string_sort is used.
\note Sorting other data types requires picking between @c integer_sort, @c float_sort and @c string_sort directly,
as @c spreadsort won't accept types that don't have the appropriate @c type_traits.

Expand All @@ -107,12 +107,36 @@ namespace spreadsort {
template <class RandomAccessIter>
inline typename boost::enable_if_c<
is_same<typename std::iterator_traits<RandomAccessIter>::value_type,
typename std::string>::value ||
typename std::string>::value, void >::type
spreadsort(RandomAccessIter first, RandomAccessIter last)
{
string_sort(first, last);
}

/*!
\brief Generic @c spreadsort variant detecting string element type so call to @c string_sort for @c std::wstrings.
\details If the data type provided is a wstring, @c string_sort is used.
\note Sorting other data types requires picking between @c integer_sort, @c float_sort and @c string_sort directly,
as @c spreadsort won't accept types that don't have the appropriate @c type_traits.

\param[in] first Iterator pointer to first element.
\param[in] last Iterator pointing to one beyond the end of data.

\pre [@c first, @c last) is a valid range.
\pre @c RandomAccessIter @c value_type is mutable.
\pre @c RandomAccessIter @c value_type is <a href="http://en.cppreference.com/w/cpp/concept/LessThanComparable">LessThanComparable</a>
\pre @c RandomAccessIter @c value_type supports the @c operator>>,
which returns an integer-type right-shifted a specified number of bits.
\post The elements in the range [@c first, @c last) are sorted in ascending order.
*/
template <class RandomAccessIter>
inline typename boost::enable_if_c<
is_same<typename std::iterator_traits<RandomAccessIter>::value_type,
typename std::wstring>::value, void >::type
spreadsort(RandomAccessIter first, RandomAccessIter last)
{
string_sort(first, last);
unsigned wchar_t unused = '\0';
string_sort(first, last, unused);
}
} // namespace spreadsort
} // namespace sort
Expand Down
97 changes: 63 additions & 34 deletions test/float_sort_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,27 @@ rand_32(bool sign = true) {
return result;
}

static const unsigned input_count = 100000;
static const unsigned input_count = 1000000;

// Helper class to run tests across all float_sort interface variants.
template<class FloatType, class RightShift>
void test_vector(vector<FloatType> base_vec, RightShift shifter) {
vector<FloatType> sorted_vec = base_vec;
vector<FloatType> test_vec = base_vec;
std::sort(sorted_vec.begin(), sorted_vec.end());
//Testing boost::sort::spreadsort version
test_vec = base_vec;
boost::sort::spreadsort::spreadsort(test_vec.begin(), test_vec.end());
BOOST_CHECK(test_vec == sorted_vec);
//One functor
test_vec = base_vec;
float_sort(test_vec.begin(), test_vec.end(), shifter);
BOOST_CHECK(test_vec == sorted_vec);
//Both functors
test_vec = base_vec;
float_sort(test_vec.begin(), test_vec.end(), shifter, less<FloatType>());
BOOST_CHECK(test_vec == sorted_vec);
}

void float_test()
{
Expand All @@ -59,49 +79,58 @@ void float_test()
else
base_vec.push_back(val);
}
vector<float> sorted_vec = base_vec;
vector<float> test_vec = base_vec;
std::sort(sorted_vec.begin(), sorted_vec.end());
//Testing boost::sort::spreadsort version
test_vec = base_vec;
boost::sort::spreadsort::spreadsort(test_vec.begin(), test_vec.end());
BOOST_CHECK(test_vec == sorted_vec);
//One functor
test_vec = base_vec;
float_sort(test_vec.begin(), test_vec.end(), rightshift());
BOOST_CHECK(test_vec == sorted_vec);
//Both functors
test_vec = base_vec;
float_sort(test_vec.begin(), test_vec.end(), rightshift(), less<float>());
BOOST_CHECK(test_vec == sorted_vec);
test_vector(base_vec, rightshift());

// Trying both positive and negative sorted and reverse sorted data.
base_vec.clear();
for (size_t i = 0; i < input_count; ++i) base_vec.push_back(-i);
test_vector(base_vec, rightshift());
base_vec.clear();
for (size_t i = 0; i < input_count; ++i) base_vec.push_back(i - input_count);
test_vector(base_vec, rightshift());
base_vec.clear();
for (size_t i = 0; i < input_count; ++i) base_vec.push_back(input_count - i);
test_vector(base_vec, rightshift());
base_vec.clear();
for (size_t i = 0; i < input_count; ++i) base_vec.push_back(i);
test_vector(base_vec, rightshift());
base_vec.clear();
for (size_t i = 0; i < input_count; ++i) base_vec.push_back(i);
for (size_t i = 0; i < input_count; i += 2) base_vec[i] *= -1;
test_vector(base_vec, rightshift());
}

void double_test() {
vector<double> long_base_vec;
vector<double> base_vec;
for (unsigned u = 0; u < input_count; ++u) {
double val = double
((((boost::int64_t)rand_32()) << ((8 * sizeof(int)) -1)) + rand_32(false));
//As std::sort gives arbitrary results for NaNs and 0.0 vs. -0.0,
//treat all those as just 0.0 for testing
if (!(val < 0.0) && !(0.0 < val))
long_base_vec.push_back(0.0);
base_vec.push_back(0.0);
else
long_base_vec.push_back(val);
base_vec.push_back(val);
}
vector<double> long_sorted_vec = long_base_vec;
vector<double> long_test_vec = long_base_vec;
float_sort(long_test_vec.begin(), long_test_vec.end());
std::sort(long_sorted_vec.begin(), long_sorted_vec.end());
BOOST_CHECK(long_test_vec == long_sorted_vec);
//One functor
long_test_vec = long_base_vec;
float_sort(long_test_vec.begin(), long_test_vec.end(), rightshift_64());
BOOST_CHECK(long_test_vec == long_sorted_vec);
//Both functors
long_test_vec = long_base_vec;
float_sort(long_test_vec.begin(), long_test_vec.end(), rightshift_64(),
less<double>());
BOOST_CHECK(long_test_vec == long_sorted_vec);
test_vector(base_vec, rightshift_64());

// Trying both positive and negative sorted and reverse sorted data.
base_vec.clear();
for (size_t i = 0; i < input_count; ++i) base_vec.push_back(-i);
test_vector(base_vec, rightshift_64());
base_vec.clear();
for (size_t i = 0; i < input_count; ++i) base_vec.push_back(i - input_count);
test_vector(base_vec, rightshift_64());
base_vec.clear();
for (size_t i = 0; i < input_count; ++i) base_vec.push_back(input_count - i);
test_vector(base_vec, rightshift_64());
base_vec.clear();
for (size_t i = 0; i < input_count; ++i) base_vec.push_back(i);
test_vector(base_vec, rightshift_64());
base_vec.clear();
for (size_t i = 0; i < input_count; ++i) base_vec.push_back(i);
for (size_t i = 0; i < input_count; i += 2) base_vec[i] *= -1;
test_vector(base_vec, rightshift_64());
}

// Verify that 0 and 1 elements work correctly.
Expand All @@ -121,6 +150,6 @@ int test_main( int, char*[] )
srand(1);
float_test();
double_test();
corner_test();
corner_test();
return 0;
}
Loading