|
#pragma once |
|
|
|
#include <cstdio> |
|
#include <iostream> |
|
#include <map> |
|
#include <set> |
|
#include <string> |
|
#include <type_traits> |
|
#include <vector> |
|
|
|
#include "meta.h" |
|
#include "util.h" |
|
|
|
#include <thrust/limits.h> |
|
#include <thrust/detail/config.h> |
|
#include <thrust/detail/integer_traits.h> |
|
#include <thrust/mr/host_memory_resource.h> |
|
#include <thrust/mr/device_memory_resource.h> |
|
#include <thrust/mr/universal_memory_resource.h> |
|
#include <thrust/mr/allocator.h> |
|
|
|
|
|
typedef unittest::type_list<int, |
|
unsigned int, |
|
float> ThirtyTwoBitTypes; |
|
|
|
typedef unittest::type_list<long long, |
|
unsigned long long, |
|
double> SixtyFourBitTypes; |
|
|
|
typedef unittest::type_list<char, |
|
signed char, |
|
unsigned char, |
|
short, |
|
unsigned short, |
|
int, |
|
unsigned int, |
|
long, |
|
unsigned long, |
|
long long, |
|
unsigned long long> IntegralTypes; |
|
|
|
typedef unittest::type_list<signed char, |
|
signed short, |
|
signed int, |
|
signed long, |
|
signed long long> SignedIntegralTypes; |
|
|
|
typedef unittest::type_list<unsigned char, |
|
unsigned short, |
|
unsigned int, |
|
unsigned long, |
|
unsigned long long> UnsignedIntegralTypes; |
|
|
|
typedef unittest::type_list<char, |
|
signed char, |
|
unsigned char> ByteTypes; |
|
|
|
typedef unittest::type_list<char, |
|
signed char, |
|
unsigned char, |
|
short, |
|
unsigned short> SmallIntegralTypes; |
|
|
|
typedef unittest::type_list<long long, |
|
unsigned long long> LargeIntegralTypes; |
|
|
|
typedef unittest::type_list<float, |
|
double> FloatingPointTypes; |
|
|
|
|
|
|
|
|
|
class custom_numeric |
|
{ |
|
public: |
|
__host__ __device__ |
|
custom_numeric() |
|
{ |
|
fill(0); |
|
} |
|
|
|
|
|
template <typename T, |
|
typename = typename std::enable_if<std::is_integral<T>::value>::type> |
|
__host__ __device__ |
|
custom_numeric(const T& i) |
|
{ |
|
fill(static_cast<int>(i)); |
|
} |
|
|
|
__host__ __device__ |
|
custom_numeric(const custom_numeric & other) |
|
{ |
|
fill(other.value[0]); |
|
} |
|
|
|
__host__ __device__ |
|
custom_numeric & operator=(int val) |
|
{ |
|
fill(val); |
|
return *this; |
|
} |
|
|
|
__host__ __device__ |
|
custom_numeric & operator=(const custom_numeric & other) |
|
{ |
|
fill(other.value[0]); |
|
return *this; |
|
} |
|
|
|
|
|
|
|
__host__ __device__ |
|
operator void *() const |
|
{ |
|
|
|
return reinterpret_cast<void *>(static_cast<std::size_t>(value[0])); |
|
} |
|
|
|
#define DEFINE_OPERATOR(op) \ |
|
__host__ __device__ \ |
|
custom_numeric & operator op() { \ |
|
fill(op value[0]); \ |
|
return *this; \ |
|
} \ |
|
__host__ __device__ \ |
|
custom_numeric operator op(int) const { \ |
|
custom_numeric ret(*this); \ |
|
op ret; \ |
|
return ret; \ |
|
} |
|
|
|
DEFINE_OPERATOR(++) |
|
DEFINE_OPERATOR(--) |
|
|
|
#undef DEFINE_OPERATOR |
|
|
|
#define DEFINE_OPERATOR(op) \ |
|
__host__ __device__ \ |
|
custom_numeric operator op () const \ |
|
{ \ |
|
return custom_numeric(op value[0]); \ |
|
} |
|
|
|
DEFINE_OPERATOR(+) |
|
DEFINE_OPERATOR(-) |
|
DEFINE_OPERATOR(~) |
|
|
|
#undef DEFINE_OPERATOR |
|
|
|
#define DEFINE_OPERATOR(op) \ |
|
__host__ __device__ \ |
|
custom_numeric operator op (const custom_numeric & other) const \ |
|
{ \ |
|
return custom_numeric(value[0] op other.value[0]); \ |
|
} |
|
|
|
DEFINE_OPERATOR(+) |
|
DEFINE_OPERATOR(-) |
|
DEFINE_OPERATOR(*) |
|
DEFINE_OPERATOR(/) |
|
DEFINE_OPERATOR(%) |
|
DEFINE_OPERATOR(<<) |
|
DEFINE_OPERATOR(>>) |
|
DEFINE_OPERATOR(&) |
|
DEFINE_OPERATOR(|) |
|
DEFINE_OPERATOR(^) |
|
|
|
#undef DEFINE_OPERATOR |
|
|
|
#define CONCAT(X, Y) X ## Y |
|
|
|
#define DEFINE_OPERATOR(op) \ |
|
__host__ __device__ \ |
|
custom_numeric & operator CONCAT(op, =) (const custom_numeric & other) \ |
|
{ \ |
|
fill(value[0] op other.value[0]); \ |
|
return *this; \ |
|
} |
|
|
|
DEFINE_OPERATOR(+) |
|
DEFINE_OPERATOR(-) |
|
DEFINE_OPERATOR(*) |
|
DEFINE_OPERATOR(/) |
|
DEFINE_OPERATOR(%) |
|
DEFINE_OPERATOR(<<) |
|
DEFINE_OPERATOR(>>) |
|
DEFINE_OPERATOR(&) |
|
DEFINE_OPERATOR(|) |
|
DEFINE_OPERATOR(^) |
|
|
|
#undef DEFINE_OPERATOR |
|
|
|
#define DEFINE_OPERATOR(op) \ |
|
__host__ __device__ \ |
|
friend bool operator op (const custom_numeric & lhs, const custom_numeric & rhs) \ |
|
{ \ |
|
return lhs.value[0] op rhs.value[0]; \ |
|
} |
|
|
|
DEFINE_OPERATOR(==) |
|
DEFINE_OPERATOR(!=) |
|
DEFINE_OPERATOR(<) |
|
DEFINE_OPERATOR(<=) |
|
DEFINE_OPERATOR(>) |
|
DEFINE_OPERATOR(>=) |
|
DEFINE_OPERATOR(&&) |
|
DEFINE_OPERATOR(||); |
|
|
|
|
|
#undef DEFINE_OPERATOR |
|
|
|
friend std::ostream & operator<<(std::ostream & os, const custom_numeric & val) |
|
{ |
|
return os << "custom_numeric{" << val.value[0] << "}"; |
|
} |
|
|
|
private: |
|
int value[5]; |
|
|
|
__host__ __device__ |
|
void fill(int val) |
|
{ |
|
for (int i = 0; i < 5; ++i) |
|
{ |
|
value[i] = val; |
|
} |
|
} |
|
}; |
|
|
|
THRUST_NAMESPACE_BEGIN |
|
|
|
template <> |
|
struct numeric_limits<custom_numeric> : numeric_limits<int> {}; |
|
|
|
namespace detail |
|
{ |
|
|
|
|
|
template<> |
|
class integer_traits<custom_numeric> |
|
: public integer_traits_base<int, INT_MIN, INT_MAX> |
|
{}; |
|
|
|
} |
|
|
|
THRUST_NAMESPACE_END |
|
|
|
typedef unittest::type_list<char, |
|
signed char, |
|
unsigned char, |
|
short, |
|
unsigned short, |
|
int, |
|
unsigned int, |
|
long, |
|
unsigned long, |
|
long long, |
|
unsigned long long, |
|
float, |
|
double, |
|
custom_numeric> NumericTypes; |
|
|
|
typedef unittest::type_list<char, |
|
signed char, |
|
unsigned char, |
|
short, |
|
unsigned short, |
|
int, |
|
unsigned int, |
|
long, |
|
unsigned long, |
|
long long, |
|
unsigned long long, |
|
float, |
|
double> BuiltinNumericTypes; |
|
|
|
inline void chop_prefix(std::string& str, const std::string& prefix) |
|
{ |
|
str.replace(str.find(prefix) == 0 ? 0 : str.size(), prefix.size(), ""); |
|
} |
|
|
|
inline std::string base_class_name(const std::string& name) |
|
{ |
|
std::string result = name; |
|
|
|
|
|
chop_prefix(result, "struct "); |
|
|
|
|
|
chop_prefix(result, "class "); |
|
|
|
const std::size_t first_lt = result.find_first_of("<"); |
|
|
|
if (first_lt < result.size()) |
|
|
|
return result.replace(first_lt, result.size(), ""); |
|
else |
|
return result; |
|
} |
|
|
|
enum TestStatus { Pass = 0, Failure = 1, KnownFailure = 2, Error = 3, UnknownException = 4}; |
|
|
|
typedef std::set<std::string> ArgumentSet; |
|
typedef std::map<std::string, std::string> ArgumentMap; |
|
|
|
std::vector<size_t> get_test_sizes(void); |
|
void set_test_sizes(const std::string&); |
|
|
|
class UnitTest { |
|
public: |
|
std::string name; |
|
UnitTest() {} |
|
UnitTest(const char * name); |
|
virtual ~UnitTest() {} |
|
virtual void run() {} |
|
|
|
bool operator<(const UnitTest& u) const |
|
{ |
|
return name < u.name; |
|
} |
|
}; |
|
|
|
class UnitTestDriver; |
|
|
|
class UnitTestDriver |
|
{ |
|
typedef std::map<std::string, UnitTest*> TestMap; |
|
|
|
TestMap test_map; |
|
|
|
bool run_tests(std::vector<UnitTest *>& tests_to_run, const ArgumentMap& kwargs); |
|
|
|
protected: |
|
|
|
|
|
|
|
|
|
virtual bool post_test_smoke_check(const UnitTest &test, bool concise); |
|
|
|
public: |
|
inline virtual ~UnitTestDriver() {}; |
|
|
|
void register_test(UnitTest * test); |
|
virtual bool run_tests(const ArgumentSet& args, const ArgumentMap& kwargs); |
|
void list_tests(void); |
|
|
|
static UnitTestDriver &s_driver(); |
|
}; |
|
|
|
|
|
#define DECLARE_UNITTEST(TEST) \ |
|
class TEST##UnitTest : public UnitTest { \ |
|
public: \ |
|
TEST##UnitTest() : UnitTest(#TEST) {} \ |
|
void run(){ \ |
|
TEST(); \ |
|
} \ |
|
}; \ |
|
TEST##UnitTest TEST##Instance |
|
|
|
#define DECLARE_UNITTEST_WITH_NAME(TEST, NAME) \ |
|
class NAME##UnitTest : public UnitTest { \ |
|
public: \ |
|
NAME##UnitTest() : UnitTest(#NAME) {} \ |
|
void run(){ \ |
|
TEST(); \ |
|
} \ |
|
}; \ |
|
NAME##UnitTest NAME##Instance |
|
|
|
|
|
|
|
#define DECLARE_VECTOR_UNITTEST(VTEST) \ |
|
void VTEST##Host(void) { \ |
|
VTEST< thrust::host_vector<signed char> >(); \ |
|
VTEST< thrust::host_vector<short> >(); \ |
|
VTEST< thrust::host_vector<int> >(); \ |
|
VTEST< thrust::host_vector<float> >(); \ |
|
VTEST< thrust::host_vector<custom_numeric> >(); \ |
|
\ |
|
VTEST< thrust::host_vector<int, \ |
|
thrust::mr::stateless_resource_allocator<int, \ |
|
thrust::host_memory_resource> > >(); \ |
|
} \ |
|
void VTEST##Device(void) { \ |
|
VTEST< thrust::device_vector<signed char> >(); \ |
|
VTEST< thrust::device_vector<short> >(); \ |
|
VTEST< thrust::device_vector<int> >(); \ |
|
VTEST< thrust::device_vector<float> >(); \ |
|
VTEST< thrust::device_vector<custom_numeric> >(); \ |
|
\ |
|
VTEST< thrust::device_vector<int, \ |
|
thrust::mr::stateless_resource_allocator<int, \ |
|
thrust::device_memory_resource> > >(); \ |
|
} \ |
|
void VTEST##Universal(void) { \ |
|
VTEST< thrust::universal_vector<int> >(); \ |
|
VTEST< thrust::device_vector<int, \ |
|
thrust::mr::stateless_resource_allocator<int, \ |
|
thrust::universal_host_pinned_memory_resource> > >();\ |
|
} \ |
|
DECLARE_UNITTEST(VTEST##Host); \ |
|
DECLARE_UNITTEST(VTEST##Device); \ |
|
DECLARE_UNITTEST(VTEST##Universal); |
|
|
|
|
|
#define DECLARE_INTEGRAL_VECTOR_UNITTEST(VTEST) \ |
|
void VTEST##Host(void) { \ |
|
VTEST< thrust::host_vector<signed char> >(); \ |
|
VTEST< thrust::host_vector<short> >(); \ |
|
VTEST< thrust::host_vector<int> >(); \ |
|
} \ |
|
void VTEST##Device(void) { \ |
|
VTEST< thrust::device_vector<signed char> >(); \ |
|
VTEST< thrust::device_vector<short> >(); \ |
|
VTEST< thrust::device_vector<int> >(); \ |
|
} \ |
|
void VTEST##Universal(void) { \ |
|
VTEST< thrust::universal_vector<int> >(); \ |
|
VTEST< thrust::device_vector<int, \ |
|
thrust::mr::stateless_resource_allocator<int, \ |
|
thrust::universal_host_pinned_memory_resource> > >();\ |
|
} \ |
|
DECLARE_UNITTEST(VTEST##Host); \ |
|
DECLARE_UNITTEST(VTEST##Device); \ |
|
DECLARE_UNITTEST(VTEST##Universal); |
|
|
|
|
|
#define DECLARE_GENERIC_UNITTEST(TEST) \ |
|
class TEST##UnitTest : public UnitTest { \ |
|
public: \ |
|
TEST##UnitTest() : UnitTest(#TEST) {} \ |
|
void run() \ |
|
{ \ |
|
TEST<signed char>(); \ |
|
TEST<unsigned char>(); \ |
|
TEST<short>(); \ |
|
TEST<unsigned short>(); \ |
|
TEST<int>(); \ |
|
TEST<unsigned int>(); \ |
|
TEST<float>(); \ |
|
} \ |
|
}; \ |
|
TEST##UnitTest TEST##Instance |
|
|
|
|
|
#define DECLARE_SIZED_UNITTEST(TEST) \ |
|
class TEST##UnitTest : public UnitTest { \ |
|
public: \ |
|
TEST##UnitTest() : UnitTest(#TEST) {} \ |
|
void run() \ |
|
{ \ |
|
std::vector<size_t> sizes = get_test_sizes(); \ |
|
for(size_t i = 0; i != sizes.size(); ++i) \ |
|
{ \ |
|
TEST(sizes[i]); \ |
|
} \ |
|
} \ |
|
}; \ |
|
TEST##UnitTest TEST##Instance |
|
|
|
|
|
#define DECLARE_VARIABLE_UNITTEST(TEST) \ |
|
class TEST##UnitTest : public UnitTest { \ |
|
public: \ |
|
TEST##UnitTest() : UnitTest(#TEST) {} \ |
|
void run() \ |
|
{ \ |
|
std::vector<size_t> sizes = get_test_sizes(); \ |
|
for(size_t i = 0; i != sizes.size(); ++i) \ |
|
{ \ |
|
TEST<signed char>(sizes[i]); \ |
|
TEST<unsigned char>(sizes[i]); \ |
|
TEST<short>(sizes[i]); \ |
|
TEST<unsigned short>(sizes[i]); \ |
|
TEST<int>(sizes[i]); \ |
|
TEST<unsigned int>(sizes[i]); \ |
|
TEST<float>(sizes[i]); \ |
|
TEST<double>(sizes[i]); \ |
|
} \ |
|
} \ |
|
}; \ |
|
TEST##UnitTest TEST##Instance |
|
|
|
#define DECLARE_INTEGRAL_VARIABLE_UNITTEST(TEST) \ |
|
class TEST##UnitTest : public UnitTest { \ |
|
public: \ |
|
TEST##UnitTest() : UnitTest(#TEST) {} \ |
|
void run() \ |
|
{ \ |
|
std::vector<size_t> sizes = get_test_sizes(); \ |
|
for(size_t i = 0; i != sizes.size(); ++i) \ |
|
{ \ |
|
TEST<signed char>(sizes[i]); \ |
|
TEST<unsigned char>(sizes[i]); \ |
|
TEST<short>(sizes[i]); \ |
|
TEST<unsigned short>(sizes[i]); \ |
|
TEST<int>(sizes[i]); \ |
|
TEST<unsigned int>(sizes[i]); \ |
|
} \ |
|
} \ |
|
}; \ |
|
TEST##UnitTest TEST##Instance |
|
|
|
#define DECLARE_GENERIC_UNITTEST_WITH_TYPES_AND_NAME(TEST, TYPES, NAME) \ |
|
::SimpleUnitTest<TEST, TYPES> NAME##_instance(#NAME) \ |
|
|
|
|
|
#define DECLARE_GENERIC_SIZED_UNITTEST_WITH_TYPES_AND_NAME(TEST, TYPES, NAME) \ |
|
::VariableUnitTest<TEST, TYPES> NAME##_instance(#NAME) \ |
|
|
|
|
|
#define DECLARE_GENERIC_UNITTEST_WITH_TYPES(TEST, TYPES) \ |
|
::SimpleUnitTest<TEST, TYPES> TEST##_instance(#TEST) \ |
|
|
|
|
|
#define DECLARE_GENERIC_SIZED_UNITTEST_WITH_TYPES(TEST, TYPES) \ |
|
::VariableUnitTest<TEST, TYPES> TEST##_instance(#TEST) \ |
|
|
|
|
|
template<template <typename> class TestName, typename TypeList> |
|
class SimpleUnitTest : public UnitTest |
|
{ |
|
public: |
|
SimpleUnitTest() |
|
: UnitTest(base_class_name(unittest::type_name<TestName<int> >()).c_str()) {} |
|
|
|
SimpleUnitTest(const char * name) |
|
: UnitTest(name) {} |
|
|
|
void run() |
|
{ |
|
|
|
typedef typename unittest::get_type<TypeList,0>::type first_type; |
|
|
|
unittest::for_each_type<TypeList,TestName,first_type,0> for_each; |
|
|
|
|
|
for_each(); |
|
} |
|
}; |
|
|
|
|
|
template<template <typename> class TestName, typename TypeList> |
|
class VariableUnitTest : public UnitTest |
|
{ |
|
public: |
|
VariableUnitTest() |
|
: UnitTest(base_class_name(unittest::type_name<TestName<int> >()).c_str()) {} |
|
|
|
VariableUnitTest(const char * name) |
|
: UnitTest(name) {} |
|
|
|
void run() |
|
{ |
|
std::vector<size_t> sizes = get_test_sizes(); |
|
for(size_t i = 0; i != sizes.size(); ++i) |
|
{ |
|
|
|
typedef typename unittest::get_type<TypeList,0>::type first_type; |
|
|
|
unittest::for_each_type<TypeList,TestName,first_type,0> loop; |
|
|
|
|
|
loop(sizes[i]); |
|
} |
|
} |
|
}; |
|
|
|
template<template <typename> class TestName, |
|
typename TypeList, |
|
template <typename, typename> class Vector, |
|
template <typename> class Alloc> |
|
struct VectorUnitTest |
|
: public UnitTest |
|
{ |
|
VectorUnitTest() |
|
: UnitTest((base_class_name(unittest::type_name<TestName< Vector<int, Alloc<int> > > >()) + "<" + |
|
base_class_name(unittest::type_name<Vector<int, Alloc<int> > >()) + ">").c_str()) |
|
{ } |
|
|
|
VectorUnitTest(const char * name) |
|
: UnitTest(name) {} |
|
|
|
void run() |
|
{ |
|
|
|
typedef typename unittest::transform1<TypeList, Alloc>::type AllocList; |
|
|
|
|
|
typedef typename unittest::transform2<TypeList, AllocList, Vector>::type VectorList; |
|
|
|
|
|
typedef typename unittest::get_type<VectorList,0>::type first_type; |
|
|
|
unittest::for_each_type<VectorList,TestName,first_type,0> loop; |
|
|
|
|
|
loop(0); |
|
} |
|
}; |
|
|
|
|