Spaces:
Runtime error
Runtime error
// define some common lists of types | |
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; | |
// A type that behaves as if it was a normal numeric type, | |
// so it can be used in the same tests as "normal" numeric types. | |
// NOTE: This is explicitly NOT proclaimed trivially reloctable. | |
class custom_numeric | |
{ | |
public: | |
__host__ __device__ | |
custom_numeric() | |
{ | |
fill(0); | |
} | |
__host__ __device__ | |
custom_numeric(int i) | |
{ | |
fill(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; | |
} | |
// cast to void * instead of bool to fool overload resolution | |
// WTB C++11 explicit conversion operators | |
__host__ __device__ | |
operator void *() const | |
{ | |
// static cast first to avoid MSVC warning C4312 | |
return reinterpret_cast<void *>(static_cast<std::size_t>(value[0])); | |
} | |
DEFINE_OPERATOR(++) | |
DEFINE_OPERATOR(--) | |
DEFINE_OPERATOR(+) | |
DEFINE_OPERATOR(-) | |
DEFINE_OPERATOR(~) | |
DEFINE_OPERATOR(+) | |
DEFINE_OPERATOR(-) | |
DEFINE_OPERATOR(*) | |
DEFINE_OPERATOR(/) | |
DEFINE_OPERATOR(%) | |
DEFINE_OPERATOR(<<) | |
DEFINE_OPERATOR(>>) | |
DEFINE_OPERATOR(&) | |
DEFINE_OPERATOR(|) | |
DEFINE_OPERATOR(^) | |
DEFINE_OPERATOR(+) | |
DEFINE_OPERATOR(-) | |
DEFINE_OPERATOR(*) | |
DEFINE_OPERATOR(/) | |
DEFINE_OPERATOR(%) | |
DEFINE_OPERATOR(<<) | |
DEFINE_OPERATOR(>>) | |
DEFINE_OPERATOR(&) | |
DEFINE_OPERATOR(|) | |
DEFINE_OPERATOR(^) | |
DEFINE_OPERATOR(==) | |
DEFINE_OPERATOR(!=) | |
DEFINE_OPERATOR(<) | |
DEFINE_OPERATOR(<=) | |
DEFINE_OPERATOR(>) | |
DEFINE_OPERATOR(>=) | |
DEFINE_OPERATOR(&&) | |
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; | |
} | |
} | |
}; | |
namespace thrust | |
{ | |
template <> | |
struct numeric_limits<custom_numeric> : numeric_limits<int> {}; | |
namespace detail | |
{ | |
// For random number generation | |
template<> | |
class integer_traits<custom_numeric> | |
: public integer_traits_base<int, INT_MIN, INT_MAX> | |
{}; | |
}} // namespace thrust::detail | |
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; | |
// if the name begins with "struct ", chop it off | |
chop_prefix(result, "struct "); | |
// if the name begins with "class ", chop it off | |
chop_prefix(result, "class "); | |
const std::size_t first_lt = result.find_first_of("<"); | |
if (first_lt < result.size()) | |
// chop everything including and after first "<" | |
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: | |
// executed immediately after each test | |
// \param test The UnitTest of interest | |
// \param concise Whether or not to suppress output | |
// \return true if all is well; false if the tests must be immediately aborted | |
virtual bool post_test_sanity_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(); | |
}; | |
// Macro to create a single unittest | |
// Macro to create host and device versions of a | |
// unit test for a bunch of data types | |
// Same as above, but only for integral types | |
// Macro to create instances of a test for several data types. | |
// Macro to create instances of a test for several data types and array sizes | |
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() | |
{ | |
// get the first type in the list | |
typedef typename unittest::get_type<TypeList,0>::type first_type; | |
unittest::for_each_type<TypeList,TestName,first_type,0> for_each; | |
// loop over the types | |
for_each(); | |
} | |
}; // end SimpleUnitTest | |
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) | |
{ | |
// get the first type in the list | |
typedef typename unittest::get_type<TypeList,0>::type first_type; | |
unittest::for_each_type<TypeList,TestName,first_type,0> loop; | |
// loop over the types | |
loop(sizes[i]); | |
} | |
} | |
}; // end VariableUnitTest | |
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() | |
{ | |
// zip up the type list with Alloc | |
typedef typename unittest::transform1<TypeList, Alloc>::type AllocList; | |
// zip up the type list & alloc list with Vector | |
typedef typename unittest::transform2<TypeList, AllocList, Vector>::type VectorList; | |
// get the first type in the list | |
typedef typename unittest::get_type<VectorList,0>::type first_type; | |
unittest::for_each_type<VectorList,TestName,first_type,0> loop; | |
// loop over the types | |
loop(0); | |
} | |
}; // end VectorUnitTest | |