1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2011-2018 Gael Guennebaud <[email protected]>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9
10 #ifndef EIGEN_TEST_ANNOYING_SCALAR_H
11 #define EIGEN_TEST_ANNOYING_SCALAR_H
12
13 #include <ostream>
14
15 #if EIGEN_COMP_GNUC
16 #pragma GCC diagnostic ignored "-Wshadow"
17 #endif
18
19 #ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
20 struct my_exception
21 {
my_exceptionmy_exception22 my_exception() {}
~my_exceptionmy_exception23 ~my_exception() {}
24 };
25 #endif
26
27 // An AnnoyingScalar is a pseudo scalar type that:
28 // - can randomly through an exception in operator +
29 // - randomly allocate on the heap or initialize a reference to itself making it non trivially copyable, nor movable, nor relocatable.
30
31 class AnnoyingScalar
32 {
33 public:
AnnoyingScalar()34 AnnoyingScalar() { init(); *v = 0; }
AnnoyingScalar(long double _v)35 AnnoyingScalar(long double _v) { init(); *v = _v; }
AnnoyingScalar(double _v)36 AnnoyingScalar(double _v) { init(); *v = _v; }
AnnoyingScalar(float _v)37 AnnoyingScalar(float _v) { init(); *v = _v; }
AnnoyingScalar(int _v)38 AnnoyingScalar(int _v) { init(); *v = _v; }
AnnoyingScalar(long _v)39 AnnoyingScalar(long _v) { init(); *v = _v; }
40 #if EIGEN_HAS_CXX11
AnnoyingScalar(long long _v)41 AnnoyingScalar(long long _v) { init(); *v = _v; }
42 #endif
AnnoyingScalar(const AnnoyingScalar & other)43 AnnoyingScalar(const AnnoyingScalar& other) { init(); *v = *(other.v); }
~AnnoyingScalar()44 ~AnnoyingScalar() {
45 if(v!=&data)
46 delete v;
47 instances--;
48 }
49
init()50 void init() {
51 if(internal::random<bool>())
52 v = new float;
53 else
54 v = &data;
55 instances++;
56 }
57
58 AnnoyingScalar operator+(const AnnoyingScalar& other) const
59 {
60 #ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
61 countdown--;
62 if(countdown<=0 && !dont_throw)
63 throw my_exception();
64 #endif
65 return AnnoyingScalar(*v+*other.v);
66 }
67
68 AnnoyingScalar operator-() const
69 { return AnnoyingScalar(-*v); }
70
71 AnnoyingScalar operator-(const AnnoyingScalar& other) const
72 { return AnnoyingScalar(*v-*other.v); }
73
74 AnnoyingScalar operator*(const AnnoyingScalar& other) const
75 { return AnnoyingScalar((*v)*(*other.v)); }
76
77 AnnoyingScalar operator/(const AnnoyingScalar& other) const
78 { return AnnoyingScalar((*v)/(*other.v)); }
79
80 AnnoyingScalar& operator+=(const AnnoyingScalar& other) { *v += *other.v; return *this; }
81 AnnoyingScalar& operator-=(const AnnoyingScalar& other) { *v -= *other.v; return *this; }
82 AnnoyingScalar& operator*=(const AnnoyingScalar& other) { *v *= *other.v; return *this; }
83 AnnoyingScalar& operator/=(const AnnoyingScalar& other) { *v /= *other.v; return *this; }
84 AnnoyingScalar& operator= (const AnnoyingScalar& other) { *v = *other.v; return *this; }
85
86 bool operator==(const AnnoyingScalar& other) const { return *v == *other.v; }
87 bool operator!=(const AnnoyingScalar& other) const { return *v != *other.v; }
88 bool operator<=(const AnnoyingScalar& other) const { return *v <= *other.v; }
89 bool operator< (const AnnoyingScalar& other) const { return *v < *other.v; }
90 bool operator>=(const AnnoyingScalar& other) const { return *v >= *other.v; }
91 bool operator> (const AnnoyingScalar& other) const { return *v > *other.v; }
92
93 float* v;
94 float data;
95 static int instances;
96 #ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
97 static int countdown;
98 static bool dont_throw;
99 #endif
100 };
101
real(const AnnoyingScalar & x)102 AnnoyingScalar real(const AnnoyingScalar &x) { return x; }
imag(const AnnoyingScalar &)103 AnnoyingScalar imag(const AnnoyingScalar & ) { return 0; }
conj(const AnnoyingScalar & x)104 AnnoyingScalar conj(const AnnoyingScalar &x) { return x; }
sqrt(const AnnoyingScalar & x)105 AnnoyingScalar sqrt(const AnnoyingScalar &x) { return std::sqrt(*x.v); }
abs(const AnnoyingScalar & x)106 AnnoyingScalar abs (const AnnoyingScalar &x) { return std::abs(*x.v); }
cos(const AnnoyingScalar & x)107 AnnoyingScalar cos (const AnnoyingScalar &x) { return std::cos(*x.v); }
sin(const AnnoyingScalar & x)108 AnnoyingScalar sin (const AnnoyingScalar &x) { return std::sin(*x.v); }
acos(const AnnoyingScalar & x)109 AnnoyingScalar acos(const AnnoyingScalar &x) { return std::acos(*x.v); }
atan2(const AnnoyingScalar & y,const AnnoyingScalar & x)110 AnnoyingScalar atan2(const AnnoyingScalar &y,const AnnoyingScalar &x) { return std::atan2(*y.v,*x.v); }
111
112 std::ostream& operator<<(std::ostream& stream,const AnnoyingScalar& x) {
113 stream << (*(x.v));
114 return stream;
115 }
116
117 int AnnoyingScalar::instances = 0;
118
119 #ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
120 int AnnoyingScalar::countdown = 0;
121 bool AnnoyingScalar::dont_throw = false;
122 #endif
123
124 namespace Eigen {
125 template<>
126 struct NumTraits<AnnoyingScalar> : NumTraits<float>
127 {
128 enum {
129 RequireInitialization = 1,
130 };
131 typedef AnnoyingScalar Real;
132 typedef AnnoyingScalar Nested;
133 typedef AnnoyingScalar Literal;
134 typedef AnnoyingScalar NonInteger;
135 };
136
137 template<> inline AnnoyingScalar test_precision<AnnoyingScalar>() { return test_precision<float>(); }
138
139 namespace numext {
140 template<>
141 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
142 bool (isfinite)(const AnnoyingScalar& x) {
143 return (numext::isfinite)(*x.v);
144 }
145 }
146
147 namespace internal {
148 template<> EIGEN_STRONG_INLINE double cast(const AnnoyingScalar& x) { return double(*x.v); }
149 template<> EIGEN_STRONG_INLINE float cast(const AnnoyingScalar& x) { return *x.v; }
150 }
151 } // namespace Eigen
152
153 AnnoyingScalar get_test_precision(const AnnoyingScalar&)
154 { return Eigen::test_precision<AnnoyingScalar>(); }
155
156 AnnoyingScalar test_relative_error(const AnnoyingScalar &a, const AnnoyingScalar &b)
157 { return test_relative_error(*a.v, *b.v); }
158
159 inline bool test_isApprox(const AnnoyingScalar &a, const AnnoyingScalar &b)
160 { return internal::isApprox(*a.v, *b.v, test_precision<float>()); }
161
162 inline bool test_isMuchSmallerThan(const AnnoyingScalar &a, const AnnoyingScalar &b)
163 { return test_isMuchSmallerThan(*a.v, *b.v); }
164
165 #endif // EIGEN_TEST_ANNOYING_SCALAR_H
166