// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2011-2018 Gael Guennebaud // // 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 #if EIGEN_COMP_GNUC #pragma GCC diagnostic ignored "-Wshadow" #endif #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, nor relocatable. 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; } #if EIGEN_HAS_CXX11 AnnoyingScalar(long long _v) { init(); *v = _v; } #endif AnnoyingScalar(const AnnoyingScalar& other) { init(); *v = *(other.v); } ~AnnoyingScalar() { if(v!=&data) delete v; instances--; } void init() { if(internal::random()) 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 : NumTraits { enum { RequireInitialization = true }; typedef AnnoyingScalar Real; typedef AnnoyingScalar Nested; typedef AnnoyingScalar Literal; typedef AnnoyingScalar NonInteger; }; template<> inline AnnoyingScalar test_precision() { return test_precision(); } namespace numext { template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool (isfinite)(const AnnoyingScalar& x) { return (numext::isfinite)(*x.v); } } namespace internal { template<> EIGEN_STRONG_INLINE AnnoyingScalar pcmp_eq(const AnnoyingScalar& a, const AnnoyingScalar& b) { return AnnoyingScalar(pcmp_eq(*a.v, *b.v)); } template<> EIGEN_STRONG_INLINE AnnoyingScalar pselect(const AnnoyingScalar& mask, const AnnoyingScalar& a, const AnnoyingScalar& b) { return numext::equal_strict(*mask.v, 0.f) ? b : a; } template<> EIGEN_STRONG_INLINE double cast(const AnnoyingScalar& x) { return double(*x.v); } template<> EIGEN_STRONG_INLINE float cast(const AnnoyingScalar& x) { return *x.v; } } } // namespace Eigen AnnoyingScalar get_test_precision(const AnnoyingScalar&) { return Eigen::test_precision(); } AnnoyingScalar test_relative_error(const AnnoyingScalar &a, const AnnoyingScalar &b) { return test_relative_error(*a.v, *b.v); } inline bool test_isApprox(const AnnoyingScalar &a, const AnnoyingScalar &b) { return internal::isApprox(*a.v, *b.v, test_precision()); } inline bool test_isMuchSmallerThan(const AnnoyingScalar &a, const AnnoyingScalar &b) { return test_isMuchSmallerThan(*a.v, *b.v); } #endif // EIGEN_TEST_ANNOYING_SCALAR_H