aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/AnnoyingScalar.h
blob: 0f8e70d360eba9ec6b1031b9fd689af909ca08e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// 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>

#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<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 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>(); }

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<float>()); }

inline bool test_isMuchSmallerThan(const AnnoyingScalar &a, const AnnoyingScalar &b)
{ return test_isMuchSmallerThan(*a.v, *b.v); }

#endif // EIGEN_TEST_ANNOYING_SCALAR_H