Skip to content

Commit

Permalink
Protect ska_sorter against unsupported types + tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Morwenn committed Jan 10, 2017
1 parent d3515c5 commit a98ac36
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 1 deletion.
72 changes: 72 additions & 0 deletions include/cpp-sort/detail/ska_sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,22 @@
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <limits>
#include <tuple>
#include <type_traits>
#include <utility>
#include <cpp-sort/sorters/pdq_sorter.h>
#include <cpp-sort/utility/as_function.h>
#include <cpp-sort/utility/detection.h>
#include <cpp-sort/utility/logical_traits.h>

namespace cppsort
{
namespace detail
{
////////////////////////////////////////////////////////////
// ska_sort algorithm

inline auto to_unsigned_or_bool(bool b)
-> bool
{
Expand Down Expand Up @@ -952,6 +958,72 @@ namespace detail
detail::inplace_radix_sort<128, 1024>(std::move(begin), std::move(end),
std::move(projection));
}

////////////////////////////////////////////////////////////
// Whether a type is sortable with ska_sort

template<typename T>
struct is_ska_sortable;

template<typename T>
using has_indexing_operator_t
= std::decay_t<decltype(std::declval<T&>()[0])>;

template<template<typename...> class Op, typename... Args>
using is_index_ska_sortable = is_ska_sortable<utility::detected_t<Op, Args...>>;

// A bit hackish, but I'm bad at workarounds...
template<>
struct is_ska_sortable<utility::nonesuch>:
std::false_type
{};

template<typename T>
struct is_ska_sortable:
utility::disjunction<
std::is_integral<T>,
is_index_ska_sortable<has_indexing_operator_t, T>
>
{};

template<typename T>
struct is_ska_sortable<T*>:
std::true_type
{};

template<>
struct is_ska_sortable<float>:
std::integral_constant<bool,
sizeof(float) == sizeof(std::uint32_t) &&
std::numeric_limits<float>::is_iec559
>
{};

template<>
struct is_ska_sortable<double>:
std::integral_constant<bool,
sizeof(double) == sizeof(std::uint64_t) &&
std::numeric_limits<double>::is_iec559
>
{};

template<typename T, typename U>
struct is_ska_sortable<std::pair<T, U>>:
utility::conjunction<
is_ska_sortable<T>,
is_ska_sortable<U>
>
{};

template<typename... Args>
struct is_ska_sortable<std::tuple<Args...>>:
utility::conjunction<
is_ska_sortable<Args>...
>
{};

template<typename T>
constexpr bool is_ska_sortable_v = is_ska_sortable<T>::value;
}}

#endif // CPPSORT_DETAIL_SKA_SORT_H_
5 changes: 4 additions & 1 deletion include/cpp-sort/sorters/ska_sorter.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <utility>
#include <cpp-sort/sorter_facade.h>
#include <cpp-sort/sorter_traits.h>
#include <cpp-sort/utility/as_function.h>
#include <cpp-sort/utility/functional.h>
#include <cpp-sort/utility/static_const.h>
#include "../detail/iterator_traits.h"
Expand All @@ -55,7 +56,9 @@ namespace cppsort
>
auto operator()(RandomAccessIterator first, RandomAccessIterator last,
Projection projection={}) const
-> void
-> std::enable_if_t<detail::is_ska_sortable_v<
std::decay_t<decltype(utility::as_function(projection)(*first))>
>>
{
static_assert(
std::is_base_of<
Expand Down
77 changes: 77 additions & 0 deletions testsuite/sorters/ska_sorter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
* THE SOFTWARE.
*/
#include <algorithm>
#include <cstdint>
#include <ctime>
#include <deque>
#include <iterator>
#include <limits>
#include <numeric>
#include <random>
#include <string>
Expand Down Expand Up @@ -89,3 +92,77 @@ TEST_CASE( "ska_sorter tests", "[ska_sorter]" )
CHECK( std::is_sorted(std::begin(vec), std::end(vec)) );
}
}

namespace
{
template<typename T>
constexpr bool is_ska_sortable = cppsort::detail::is_ska_sortable_v<T>;
}

TEST_CASE( "is_ska_sortable", "[ska_sorter]" )
{
// This isn't really common, but we will be testing
// a function that isn't exposed in the interface for
// the sake of it

SECTION( "built-in integral types" )
{
CHECK( is_ska_sortable<bool> );
CHECK( is_ska_sortable<char> );
CHECK( is_ska_sortable<unsigned char> );
CHECK( is_ska_sortable<signed char> );
CHECK( is_ska_sortable<wchar_t> );
CHECK( is_ska_sortable<char16_t> );
CHECK( is_ska_sortable<char32_t> );
CHECK( is_ska_sortable<unsigned short> );
CHECK( is_ska_sortable<signed short> );
CHECK( is_ska_sortable<unsigned int> );
CHECK( is_ska_sortable<signed int> );
CHECK( is_ska_sortable<unsigned long> );
CHECK( is_ska_sortable<signed long> );
CHECK( is_ska_sortable<unsigned long long> );
CHECK( is_ska_sortable<signed long long> );
}

SECTION( "built-in floating point types" )
{
CHECK(( is_ska_sortable<float> ||
sizeof(float) != sizeof(std::uint32_t) ||
not std::numeric_limits<float>::is_iec559 ));

CHECK(( is_ska_sortable<double> ||
sizeof(double) != sizeof(std::uint64_t) ||
not std::numeric_limits<double>::is_iec559 ));

CHECK_FALSE( is_ska_sortable<long double> );
}

SECTION( "standard collections" )
{
// Srings
CHECK( is_ska_sortable<std::string> );
CHECK( is_ska_sortable<std::wstring> );
CHECK( is_ska_sortable<std::basic_string<char16_t>> );

// Other collections
CHECK( is_ska_sortable<std::vector<int>> );
CHECK( is_ska_sortable<std::vector<std::string>> );
CHECK( is_ska_sortable<std::vector<std::vector<std::string>>> );
CHECK( is_ska_sortable<std::deque<std::vector<long long>>> );
CHECK_FALSE( is_ska_sortable<std::deque<long double>> );
}

SECTION( "pairs and tuples" )
{
// std::pair
CHECK(( is_ska_sortable<std::pair<int, int>> ));
CHECK(( is_ska_sortable<std::pair<int, std::deque<bool>>> ));
CHECK(( is_ska_sortable<std::pair<std::vector<std::pair<int, long>>, std::deque<bool>>> ));
CHECK_FALSE(( is_ska_sortable<std::pair<std::vector<std::pair<int, long double>>, std::deque<bool>>> ));

// std::tuple
CHECK(( is_ska_sortable<std::tuple<int>> ));
CHECK(( is_ska_sortable<std::tuple<long int, int, std::string, std::vector<unsigned long long>>> ));
CHECK_FALSE(( is_ska_sortable<std::tuple<std::string, std::vector<unsigned long long>, std::deque<long double>>> ));
}
}

0 comments on commit a98ac36

Please # to comment.