mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-04-19 08:09:36 +08:00
Generalize ScalarWithExceptions to a full non-copyable and trowing scalar type to be used in other unit tests.
This commit is contained in:
parent
a503fc8725
commit
053ed97c72
151
test/AnnoyingScalar.h
Normal file
151
test/AnnoyingScalar.h
Normal file
@ -0,0 +1,151 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2011-2018 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_TEST_ANNOYING_SCALAR_H
|
||||
#define EIGEN_TEST_ANNOYING_SCALAR_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
|
||||
struct my_exception
|
||||
{
|
||||
my_exception() {}
|
||||
~my_exception() {}
|
||||
};
|
||||
#endif
|
||||
|
||||
// An AnnoyingScalar is a pseudo scalar type that:
|
||||
// - can randomly through an exception in operator +
|
||||
// - randomly allocate on the heap or initialize a reference to itself making it non trivially copyable, nor movable.
|
||||
|
||||
class AnnoyingScalar
|
||||
{
|
||||
public:
|
||||
AnnoyingScalar() { init(); *v = 0; }
|
||||
AnnoyingScalar(long double _v) { init(); *v = _v; }
|
||||
AnnoyingScalar(double _v) { init(); *v = _v; }
|
||||
AnnoyingScalar(float _v) { init(); *v = _v; }
|
||||
AnnoyingScalar(int _v) { init(); *v = _v; }
|
||||
AnnoyingScalar(long _v) { init(); *v = _v; }
|
||||
AnnoyingScalar(const AnnoyingScalar& other) { init(); *v = *(other.v); }
|
||||
~AnnoyingScalar() {
|
||||
if(v!=&data)
|
||||
delete v;
|
||||
instances--;
|
||||
}
|
||||
|
||||
void init() {
|
||||
if(internal::random<bool>())
|
||||
v = new float;
|
||||
else
|
||||
v = &data;
|
||||
instances++;
|
||||
}
|
||||
|
||||
AnnoyingScalar operator+(const AnnoyingScalar& other) const
|
||||
{
|
||||
#ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
|
||||
countdown--;
|
||||
if(countdown<=0 && !dont_throw)
|
||||
throw my_exception();
|
||||
#endif
|
||||
return AnnoyingScalar(*v+*other.v);
|
||||
}
|
||||
|
||||
AnnoyingScalar operator-() const
|
||||
{ return AnnoyingScalar(-*v); }
|
||||
|
||||
AnnoyingScalar operator-(const AnnoyingScalar& other) const
|
||||
{ return AnnoyingScalar(*v-*other.v); }
|
||||
|
||||
AnnoyingScalar operator*(const AnnoyingScalar& other) const
|
||||
{ return AnnoyingScalar((*v)*(*other.v)); }
|
||||
|
||||
AnnoyingScalar operator/(const AnnoyingScalar& other) const
|
||||
{ return AnnoyingScalar((*v)/(*other.v)); }
|
||||
|
||||
AnnoyingScalar& operator+=(const AnnoyingScalar& other) { *v += *other.v; return *this; }
|
||||
AnnoyingScalar& operator-=(const AnnoyingScalar& other) { *v -= *other.v; return *this; }
|
||||
AnnoyingScalar& operator*=(const AnnoyingScalar& other) { *v *= *other.v; return *this; }
|
||||
AnnoyingScalar& operator/=(const AnnoyingScalar& other) { *v /= *other.v; return *this; }
|
||||
AnnoyingScalar& operator= (const AnnoyingScalar& other) { *v = *other.v; return *this; }
|
||||
|
||||
bool operator==(const AnnoyingScalar& other) const { return *v == *other.v; }
|
||||
bool operator!=(const AnnoyingScalar& other) const { return *v != *other.v; }
|
||||
bool operator<=(const AnnoyingScalar& other) const { return *v <= *other.v; }
|
||||
bool operator< (const AnnoyingScalar& other) const { return *v < *other.v; }
|
||||
bool operator>=(const AnnoyingScalar& other) const { return *v >= *other.v; }
|
||||
bool operator> (const AnnoyingScalar& other) const { return *v > *other.v; }
|
||||
|
||||
float* v;
|
||||
float data;
|
||||
static int instances;
|
||||
#ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
|
||||
static int countdown;
|
||||
static bool dont_throw;
|
||||
#endif
|
||||
};
|
||||
|
||||
AnnoyingScalar real(const AnnoyingScalar &x) { return x; }
|
||||
AnnoyingScalar imag(const AnnoyingScalar & ) { return 0; }
|
||||
AnnoyingScalar conj(const AnnoyingScalar &x) { return x; }
|
||||
AnnoyingScalar sqrt(const AnnoyingScalar &x) { return std::sqrt(*x.v); }
|
||||
AnnoyingScalar abs (const AnnoyingScalar &x) { return std::abs(*x.v); }
|
||||
AnnoyingScalar cos (const AnnoyingScalar &x) { return std::cos(*x.v); }
|
||||
AnnoyingScalar sin (const AnnoyingScalar &x) { return std::sin(*x.v); }
|
||||
AnnoyingScalar acos(const AnnoyingScalar &x) { return std::acos(*x.v); }
|
||||
AnnoyingScalar atan2(const AnnoyingScalar &y,const AnnoyingScalar &x) { return std::atan2(*y.v,*x.v); }
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream,const AnnoyingScalar& x) {
|
||||
stream << (*(x.v));
|
||||
return stream;
|
||||
}
|
||||
|
||||
int AnnoyingScalar::instances = 0;
|
||||
|
||||
#ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
|
||||
int AnnoyingScalar::countdown = 0;
|
||||
bool AnnoyingScalar::dont_throw = false;
|
||||
#endif
|
||||
|
||||
namespace Eigen {
|
||||
template<>
|
||||
struct NumTraits<AnnoyingScalar> : NumTraits<float>
|
||||
{
|
||||
enum {
|
||||
RequireInitialization = true
|
||||
};
|
||||
typedef AnnoyingScalar Real;
|
||||
typedef AnnoyingScalar Nested;
|
||||
typedef AnnoyingScalar Literal;
|
||||
typedef AnnoyingScalar NonInteger;
|
||||
};
|
||||
|
||||
template<> inline AnnoyingScalar test_precision<AnnoyingScalar>() { return test_precision<float>(); }
|
||||
|
||||
namespace internal {
|
||||
template<> double cast(const AnnoyingScalar& x) { return double(*x.v); }
|
||||
template<> float cast(const AnnoyingScalar& x) { return *x.v; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AnnoyingScalar get_test_precision(const AnnoyingScalar&)
|
||||
{ return Eigen::test_precision<AnnoyingScalar>(); }
|
||||
|
||||
AnnoyingScalar test_relative_error(AnnoyingScalar a, AnnoyingScalar b)
|
||||
{ return test_relative_error(*a.v, *b.v); }
|
||||
|
||||
inline bool test_isApprox(AnnoyingScalar a, AnnoyingScalar b)
|
||||
{ return internal::isApprox(*a.v, *b.v, test_precision<float>()); }
|
||||
|
||||
inline bool test_isMuchSmallerThan(AnnoyingScalar a, AnnoyingScalar b)
|
||||
{ return test_isMuchSmallerThan(*a.v, *b.v); }
|
||||
|
||||
#endif // EIGEN_TEST_ANNOYING_SCALAR_H
|
@ -8,93 +8,34 @@
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
// Various sanity tests with exceptions:
|
||||
// Various sanity tests with exceptions and non trivially copyable scalar type.
|
||||
// - no memory leak when a custom scalar type trow an exceptions
|
||||
// - todo: complete the list of tests!
|
||||
|
||||
#define EIGEN_STACK_ALLOCATION_LIMIT 100000000
|
||||
|
||||
#include "main.h"
|
||||
|
||||
struct my_exception
|
||||
{
|
||||
my_exception() {}
|
||||
~my_exception() {}
|
||||
};
|
||||
|
||||
class ScalarWithExceptions
|
||||
{
|
||||
public:
|
||||
ScalarWithExceptions() { init(); }
|
||||
ScalarWithExceptions(const float& _v) { init(); *v = _v; }
|
||||
ScalarWithExceptions(const ScalarWithExceptions& other) { init(); *v = *(other.v); }
|
||||
~ScalarWithExceptions() {
|
||||
delete v;
|
||||
instances--;
|
||||
}
|
||||
|
||||
void init() {
|
||||
v = new float;
|
||||
instances++;
|
||||
}
|
||||
|
||||
ScalarWithExceptions operator+(const ScalarWithExceptions& other) const
|
||||
{
|
||||
countdown--;
|
||||
if(countdown<=0)
|
||||
throw my_exception();
|
||||
return ScalarWithExceptions(*v+*other.v);
|
||||
}
|
||||
|
||||
ScalarWithExceptions operator-(const ScalarWithExceptions& other) const
|
||||
{ return ScalarWithExceptions(*v-*other.v); }
|
||||
|
||||
ScalarWithExceptions operator*(const ScalarWithExceptions& other) const
|
||||
{ return ScalarWithExceptions((*v)*(*other.v)); }
|
||||
|
||||
ScalarWithExceptions& operator+=(const ScalarWithExceptions& other)
|
||||
{ *v+=*other.v; return *this; }
|
||||
ScalarWithExceptions& operator-=(const ScalarWithExceptions& other)
|
||||
{ *v-=*other.v; return *this; }
|
||||
ScalarWithExceptions& operator=(const ScalarWithExceptions& other)
|
||||
{ *v = *(other.v); return *this; }
|
||||
|
||||
bool operator==(const ScalarWithExceptions& other) const
|
||||
{ return *v==*other.v; }
|
||||
bool operator!=(const ScalarWithExceptions& other) const
|
||||
{ return *v!=*other.v; }
|
||||
|
||||
float* v;
|
||||
static int instances;
|
||||
static int countdown;
|
||||
};
|
||||
|
||||
ScalarWithExceptions real(const ScalarWithExceptions &x) { return x; }
|
||||
ScalarWithExceptions imag(const ScalarWithExceptions & ) { return 0; }
|
||||
ScalarWithExceptions conj(const ScalarWithExceptions &x) { return x; }
|
||||
|
||||
int ScalarWithExceptions::instances = 0;
|
||||
int ScalarWithExceptions::countdown = 0;
|
||||
|
||||
#include "AnnoyingScalar.h"
|
||||
|
||||
#define CHECK_MEMLEAK(OP) { \
|
||||
ScalarWithExceptions::countdown = 100; \
|
||||
int before = ScalarWithExceptions::instances; \
|
||||
AnnoyingScalar::countdown = 100; \
|
||||
int before = AnnoyingScalar::instances; \
|
||||
bool exception_thrown = false; \
|
||||
try { OP; } \
|
||||
catch (my_exception) { \
|
||||
exception_thrown = true; \
|
||||
VERIFY(ScalarWithExceptions::instances==before && "memory leak detected in " && EIGEN_MAKESTRING(OP)); \
|
||||
VERIFY(AnnoyingScalar::instances==before && "memory leak detected in " && EIGEN_MAKESTRING(OP)); \
|
||||
} \
|
||||
VERIFY(exception_thrown && " no exception thrown in " && EIGEN_MAKESTRING(OP)); \
|
||||
VERIFY( (AnnoyingScalar::dont_throw) || (exception_thrown && " no exception thrown in " && EIGEN_MAKESTRING(OP)) ); \
|
||||
}
|
||||
|
||||
void memoryleak()
|
||||
EIGEN_DECLARE_TEST(exceptions)
|
||||
{
|
||||
typedef Eigen::Matrix<ScalarWithExceptions,Dynamic,1> VectorType;
|
||||
typedef Eigen::Matrix<ScalarWithExceptions,Dynamic,Dynamic> MatrixType;
|
||||
typedef Eigen::Matrix<AnnoyingScalar,Dynamic,1> VectorType;
|
||||
typedef Eigen::Matrix<AnnoyingScalar,Dynamic,Dynamic> MatrixType;
|
||||
|
||||
{
|
||||
AnnoyingScalar::dont_throw = false;
|
||||
int n = 50;
|
||||
VectorType v0(n), v1(n);
|
||||
MatrixType m0(n,n), m1(n,n), m2(n,n);
|
||||
@ -104,10 +45,5 @@ void memoryleak()
|
||||
CHECK_MEMLEAK(m2 = m0 * m1 * m2);
|
||||
CHECK_MEMLEAK((v0+v1).dot(v0+v1));
|
||||
}
|
||||
VERIFY(ScalarWithExceptions::instances==0 && "global memory leak detected in " && EIGEN_MAKESTRING(OP)); \
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(exceptions)
|
||||
{
|
||||
CALL_SUBTEST( memoryleak() );
|
||||
VERIFY(AnnoyingScalar::instances==0 && "global memory leak detected in " && EIGEN_MAKESTRING(OP));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user