Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/src/catch2
diff options
context:
space:
mode:
authorChris Thrasher2024-05-16 13:23:38 -0600
committerChris Thrasher2024-05-18 09:42:42 -0600
commitc974e3097460a8b47d2db00ce4ee9bbb7a19cef9 (patch)
treeb0eeb90ba10c7118042ded4a3f5a75c87364beee /src/catch2
parent4e8d92bf02f7d1c8006a0e7a5ecabd8e62d98502 (diff)
downloadcatch3-constexpr_approx.tar.gz
Allow for `Catch::Approx` to be used in a `constexpr` contextconstexpr_approx
Diffstat (limited to 'src/catch2')
-rw-r--r--src/catch2/catch_approx.cpp69
-rw-r--r--src/catch2/catch_approx.hpp89
2 files changed, 72 insertions, 86 deletions
diff --git a/src/catch2/catch_approx.cpp b/src/catch2/catch_approx.cpp
index 08c6799b..5d355efb 100644
--- a/src/catch2/catch_approx.cpp
+++ b/src/catch2/catch_approx.cpp
@@ -10,73 +10,14 @@
#include <catch2/internal/catch_reusable_string_stream.hpp>
#include <cmath>
-#include <limits>
-
-namespace {
-
-// Performs equivalent check of std::fabs(lhs - rhs) <= margin
-// But without the subtraction to allow for INFINITY in comparison
-bool marginComparison(double lhs, double rhs, double margin) {
- return (lhs + margin >= rhs) && (rhs + margin >= lhs);
-}
-
-}
namespace Catch {
- Approx::Approx ( double value )
- : m_epsilon( static_cast<double>(std::numeric_limits<float>::epsilon())*100. ),
- m_margin( 0.0 ),
- m_scale( 0.0 ),
- m_value( value )
- {}
-
- Approx Approx::custom() {
- return Approx( 0 );
- }
-
- Approx Approx::operator-() const {
- auto temp(*this);
- temp.m_value = -temp.m_value;
- return temp;
- }
-
-
- std::string Approx::toString() const {
- ReusableStringStream rss;
- rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
- return rss.str();
- }
-
- bool Approx::equalityComparisonImpl(const double other) const {
- // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
- // Thanks to Richard Harris for his help refining the scaled margin value
- return marginComparison(m_value, other, m_margin)
- || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
- }
-
- void Approx::setMargin(double newMargin) {
- CATCH_ENFORCE(newMargin >= 0,
- "Invalid Approx::margin: " << newMargin << '.'
- << " Approx::Margin has to be non-negative.");
- m_margin = newMargin;
- }
-
- void Approx::setEpsilon(double newEpsilon) {
- CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
- "Invalid Approx::epsilon: " << newEpsilon << '.'
- << " Approx::epsilon has to be in [0, 1]");
- m_epsilon = newEpsilon;
- }
-
-namespace literals {
- Approx operator ""_a(long double val) {
- return Approx(val);
- }
- Approx operator ""_a(unsigned long long val) {
- return Approx(val);
- }
-} // end namespace literals
+std::string Approx::toString() const {
+ ReusableStringStream rss;
+ rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
+ return rss.str();
+}
std::string StringMaker<Catch::Approx>::convert(Catch::Approx const& value) {
return value.toString();
diff --git a/src/catch2/catch_approx.hpp b/src/catch2/catch_approx.hpp
index de4d2ab4..831604bc 100644
--- a/src/catch2/catch_approx.hpp
+++ b/src/catch2/catch_approx.hpp
@@ -11,26 +11,67 @@
#include <catch2/catch_tostring.hpp>
#include <type_traits>
+#include <limits>
namespace Catch {
class Approx {
private:
- bool equalityComparisonImpl(double other) const;
- // Sets and validates the new margin (margin >= 0)
- void setMargin(double margin);
+ // Performs equivalent check of std::fabs(lhs - rhs) <= margin
+ // But without the subtraction to allow for INFINITY in comparison
+ constexpr bool marginComparison (double lhs, double rhs, double margin) const {
+ return (lhs + margin >= rhs) && (rhs + margin >= lhs);
+ }
+
+ constexpr double fabs(double value) const {
+ return (value < 0.0) ? -value : value;
+ }
+
+ constexpr bool isinf(double value) const {
+ return value == std::numeric_limits<double>::infinity() || value == -std::numeric_limits<double>::infinity();
+ }
+
+ constexpr bool equalityComparisonImpl(double other) const {
+ // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
+ // Thanks to Richard Harris for his help refining the scaled margin value
+ return marginComparison(m_value, other, m_margin)
+ || marginComparison(m_value, other, m_epsilon * (m_scale + fabs(isinf(m_value)? 0 : m_value)));
+ }
+
// Sets and validates the new epsilon (0 < epsilon < 1)
- void setEpsilon(double epsilon);
+ constexpr void setEpsilon(double epsilon) {
+ if(epsilon < 0)
+ throw std::domain_error("Invalid Approx::epsilon. Approx::epsilon has to be in [0, 1]");
+ m_epsilon = epsilon;
+ }
+
+ // Sets and validates the new margin (margin >= 0)
+ constexpr void setMargin(double margin) {
+ if(margin < 0)
+ throw std::domain_error("Invalid Approx::margin. Approx::Margin has to be non-negative.");
+ m_margin = margin;
+ }
public:
- explicit Approx ( double value );
+ constexpr inline explicit Approx ( double value )
+ : m_epsilon( static_cast<double>(std::numeric_limits<float>::epsilon())*100. ),
+ m_margin( 0.0 ),
+ m_scale( 0.0 ),
+ m_value( value )
+ {}
- static Approx custom();
+ static constexpr Approx custom() {
+ return Approx( 0.0 );
+ }
- Approx operator-() const;
+ constexpr Approx operator-() const {
+ auto temp(*this);
+ temp.m_value = -temp.m_value;
+ return temp;
+ }
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- Approx operator()( T const& value ) const {
+ constexpr Approx operator()( T const& value ) const {
Approx approx( static_cast<double>(value) );
approx.m_epsilon = m_epsilon;
approx.m_margin = m_margin;
@@ -39,67 +80,67 @@ namespace Catch {
}
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- explicit Approx( T const& value ): Approx(static_cast<double>(value))
+ constexpr inline explicit Approx( T const& value ): Approx(static_cast<double>(value))
{}
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- friend bool operator == ( const T& lhs, Approx const& rhs ) {
+ friend constexpr bool operator == ( const T& lhs, Approx const& rhs ) {
auto lhs_v = static_cast<double>(lhs);
return rhs.equalityComparisonImpl(lhs_v);
}
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- friend bool operator == ( Approx const& lhs, const T& rhs ) {
+ friend constexpr bool operator == ( Approx const& lhs, const T& rhs ) {
return operator==( rhs, lhs );
}
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- friend bool operator != ( T const& lhs, Approx const& rhs ) {
+ friend constexpr bool operator != ( T const& lhs, Approx const& rhs ) {
return !operator==( lhs, rhs );
}
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- friend bool operator != ( Approx const& lhs, T const& rhs ) {
+ friend constexpr bool operator != ( Approx const& lhs, T const& rhs ) {
return !operator==( rhs, lhs );
}
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- friend bool operator <= ( T const& lhs, Approx const& rhs ) {
+ friend constexpr bool operator <= ( T const& lhs, Approx const& rhs ) {
return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
}
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- friend bool operator <= ( Approx const& lhs, T const& rhs ) {
+ friend constexpr bool operator <= ( Approx const& lhs, T const& rhs ) {
return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
}
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- friend bool operator >= ( T const& lhs, Approx const& rhs ) {
+ friend constexpr bool operator >= ( T const& lhs, Approx const& rhs ) {
return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
}
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- friend bool operator >= ( Approx const& lhs, T const& rhs ) {
+ friend constexpr bool operator >= ( Approx const& lhs, T const& rhs ) {
return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
}
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- Approx& epsilon( T const& newEpsilon ) {
+ constexpr Approx& epsilon( T const& newEpsilon ) {
const auto epsilonAsDouble = static_cast<double>(newEpsilon);
setEpsilon(epsilonAsDouble);
return *this;
}
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- Approx& margin( T const& newMargin ) {
+ constexpr Approx& margin( T const& newMargin ) {
const auto marginAsDouble = static_cast<double>(newMargin);
setMargin(marginAsDouble);
return *this;
}
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
- Approx& scale( T const& newScale ) {
+ constexpr Approx& scale( T const& newScale ) {
m_scale = static_cast<double>(newScale);
return *this;
}
@@ -114,8 +155,12 @@ namespace Catch {
};
namespace literals {
- Approx operator ""_a(long double val);
- Approx operator ""_a(unsigned long long val);
+ constexpr Approx operator ""_a(long double val) {
+ return Approx(val);
+ }
+ constexpr Approx operator ""_a(unsigned long long val) {
+ return Approx(val);
+ }
} // end namespace literals
template<>