Skip to content

Commit 979d18a

Browse files
committed
Allow for Catch::Approx to be used in a constexpr context
1 parent 4e8d92b commit 979d18a

File tree

3 files changed

+69
-82
lines changed

3 files changed

+69
-82
lines changed

CMake/CatchMiscFunctions.cmake

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ function(add_warnings_to_targets targets)
5656
"-Wexit-time-destructors"
5757
"-Wextra"
5858
"-Wextra-semi"
59-
"-Wfloat-equal"
6059
"-Wglobal-constructors"
6160
"-Winit-self"
6261
"-Wmisleading-indentation"

src/catch2/catch_approx.cpp

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -10,74 +10,15 @@
1010
#include <catch2/internal/catch_reusable_string_stream.hpp>
1111

1212
#include <cmath>
13-
#include <limits>
14-
15-
namespace {
16-
17-
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
18-
// But without the subtraction to allow for INFINITY in comparison
19-
bool marginComparison(double lhs, double rhs, double margin) {
20-
return (lhs + margin >= rhs) && (rhs + margin >= lhs);
21-
}
22-
23-
}
2413

2514
namespace Catch {
2615

27-
Approx::Approx ( double value )
28-
: m_epsilon( static_cast<double>(std::numeric_limits<float>::epsilon())*100. ),
29-
m_margin( 0.0 ),
30-
m_scale( 0.0 ),
31-
m_value( value )
32-
{}
33-
34-
Approx Approx::custom() {
35-
return Approx( 0 );
36-
}
37-
38-
Approx Approx::operator-() const {
39-
auto temp(*this);
40-
temp.m_value = -temp.m_value;
41-
return temp;
42-
}
43-
44-
4516
std::string Approx::toString() const {
4617
ReusableStringStream rss;
4718
rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
4819
return rss.str();
4920
}
5021

51-
bool Approx::equalityComparisonImpl(const double other) const {
52-
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
53-
// Thanks to Richard Harris for his help refining the scaled margin value
54-
return marginComparison(m_value, other, m_margin)
55-
|| marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
56-
}
57-
58-
void Approx::setMargin(double newMargin) {
59-
CATCH_ENFORCE(newMargin >= 0,
60-
"Invalid Approx::margin: " << newMargin << '.'
61-
<< " Approx::Margin has to be non-negative.");
62-
m_margin = newMargin;
63-
}
64-
65-
void Approx::setEpsilon(double newEpsilon) {
66-
CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
67-
"Invalid Approx::epsilon: " << newEpsilon << '.'
68-
<< " Approx::epsilon has to be in [0, 1]");
69-
m_epsilon = newEpsilon;
70-
}
71-
72-
namespace literals {
73-
Approx operator ""_a(long double val) {
74-
return Approx(val);
75-
}
76-
Approx operator ""_a(unsigned long long val) {
77-
return Approx(val);
78-
}
79-
} // end namespace literals
80-
8122
std::string StringMaker<Catch::Approx>::convert(Catch::Approx const& value) {
8223
return value.toString();
8324
}

src/catch2/catch_approx.hpp

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,69 @@
1111
#include <catch2/catch_tostring.hpp>
1212

1313
#include <type_traits>
14+
#include <limits>
1415

1516
namespace Catch {
1617

1718
class Approx {
1819
private:
19-
bool equalityComparisonImpl(double other) const;
20-
// Sets and validates the new margin (margin >= 0)
21-
void setMargin(double margin);
20+
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
21+
// But without the subtraction to allow for INFINITY in comparison
22+
constexpr bool marginComparison (double lhs, double rhs, double margin) const {
23+
return (lhs + margin >= rhs) && (rhs + margin >= lhs);
24+
}
25+
26+
constexpr double fabs(double value) const {
27+
return (value < 0.0) ? -value : value;
28+
}
29+
30+
constexpr bool isinf(double value) const {
31+
return value == std::numeric_limits<double>::infinity() || value == -std::numeric_limits<double>::infinity();
32+
}
33+
34+
constexpr bool equalityComparisonImpl(double other) const {
35+
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
36+
// Thanks to Richard Harris for his help refining the scaled margin value
37+
return marginComparison(m_value, other, m_margin)
38+
|| marginComparison(m_value, other, m_epsilon * (m_scale + fabs(isinf(m_value)? 0 : m_value)));
39+
}
40+
2241
// Sets and validates the new epsilon (0 < epsilon < 1)
23-
void setEpsilon(double epsilon);
42+
constexpr void setEpsilon(double epsilon) {
43+
// CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0,
44+
// "Invalid Approx::epsilon: " << epsilon << '.'
45+
// << " Approx::epsilon has to be in [0, 1]");
46+
m_epsilon = epsilon;
47+
}
48+
49+
// Sets and validates the new margin (margin >= 0)
50+
constexpr void setMargin(double margin) {
51+
// CATCH_ENFORCE(margin >= 0,
52+
// "Invalid Approx::margin: " << margin << '.'
53+
// << " Approx::Margin has to be non-negative.");
54+
m_margin = margin;
55+
}
2456

2557
public:
26-
explicit Approx ( double value );
58+
constexpr inline explicit Approx ( double value )
59+
: m_epsilon( static_cast<double>(std::numeric_limits<float>::epsilon())*100. ),
60+
m_margin( 0.0 ),
61+
m_scale( 0.0 ),
62+
m_value( value )
63+
{}
2764

28-
static Approx custom();
65+
static constexpr Approx custom() {
66+
return Approx( 0 );
67+
}
2968

30-
Approx operator-() const;
69+
constexpr Approx operator-() const {
70+
auto temp(*this);
71+
temp.m_value = -temp.m_value;
72+
return temp;
73+
}
3174

3275
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
33-
Approx operator()( T const& value ) const {
76+
constexpr Approx operator()( T const& value ) const {
3477
Approx approx( static_cast<double>(value) );
3578
approx.m_epsilon = m_epsilon;
3679
approx.m_margin = m_margin;
@@ -39,67 +82,67 @@ namespace Catch {
3982
}
4083

4184
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
42-
explicit Approx( T const& value ): Approx(static_cast<double>(value))
85+
constexpr inline explicit Approx( T const& value ): Approx(static_cast<double>(value))
4386
{}
4487

4588

4689
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
47-
friend bool operator == ( const T& lhs, Approx const& rhs ) {
90+
friend constexpr bool operator == ( const T& lhs, Approx const& rhs ) {
4891
auto lhs_v = static_cast<double>(lhs);
4992
return rhs.equalityComparisonImpl(lhs_v);
5093
}
5194

5295
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
53-
friend bool operator == ( Approx const& lhs, const T& rhs ) {
96+
friend constexpr bool operator == ( Approx const& lhs, const T& rhs ) {
5497
return operator==( rhs, lhs );
5598
}
5699

57100
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
58-
friend bool operator != ( T const& lhs, Approx const& rhs ) {
101+
friend constexpr bool operator != ( T const& lhs, Approx const& rhs ) {
59102
return !operator==( lhs, rhs );
60103
}
61104

62105
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
63-
friend bool operator != ( Approx const& lhs, T const& rhs ) {
106+
friend constexpr bool operator != ( Approx const& lhs, T const& rhs ) {
64107
return !operator==( rhs, lhs );
65108
}
66109

67110
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
68-
friend bool operator <= ( T const& lhs, Approx const& rhs ) {
111+
friend constexpr bool operator <= ( T const& lhs, Approx const& rhs ) {
69112
return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
70113
}
71114

72115
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
73-
friend bool operator <= ( Approx const& lhs, T const& rhs ) {
116+
friend constexpr bool operator <= ( Approx const& lhs, T const& rhs ) {
74117
return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
75118
}
76119

77120
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
78-
friend bool operator >= ( T const& lhs, Approx const& rhs ) {
121+
friend constexpr bool operator >= ( T const& lhs, Approx const& rhs ) {
79122
return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
80123
}
81124

82125
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
83-
friend bool operator >= ( Approx const& lhs, T const& rhs ) {
126+
friend constexpr bool operator >= ( Approx const& lhs, T const& rhs ) {
84127
return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
85128
}
86129

87130
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
88-
Approx& epsilon( T const& newEpsilon ) {
131+
constexpr Approx& epsilon( T const& newEpsilon ) {
89132
const auto epsilonAsDouble = static_cast<double>(newEpsilon);
90133
setEpsilon(epsilonAsDouble);
91134
return *this;
92135
}
93136

94137
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
95-
Approx& margin( T const& newMargin ) {
138+
constexpr Approx& margin( T const& newMargin ) {
96139
const auto marginAsDouble = static_cast<double>(newMargin);
97140
setMargin(marginAsDouble);
98141
return *this;
99142
}
100143

101144
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
102-
Approx& scale( T const& newScale ) {
145+
constexpr Approx& scale( T const& newScale ) {
103146
m_scale = static_cast<double>(newScale);
104147
return *this;
105148
}
@@ -114,8 +157,12 @@ namespace Catch {
114157
};
115158

116159
namespace literals {
117-
Approx operator ""_a(long double val);
118-
Approx operator ""_a(unsigned long long val);
160+
constexpr Approx operator ""_a(long double val) {
161+
return Approx(val);
162+
}
163+
constexpr Approx operator ""_a(unsigned long long val) {
164+
return Approx(val);
165+
}
119166
} // end namespace literals
120167

121168
template<>

0 commit comments

Comments
 (0)