mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-03 21:49:32 +01:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			v3.6.0
			...
			constexpr_
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					c974e30974 | 
@@ -56,7 +56,6 @@ function(add_warnings_to_targets targets)
 | 
			
		||||
          "-Wexit-time-destructors"
 | 
			
		||||
          "-Wextra"
 | 
			
		||||
          "-Wextra-semi"
 | 
			
		||||
          "-Wfloat-equal"
 | 
			
		||||
          "-Wglobal-constructors"
 | 
			
		||||
          "-Winit-self"
 | 
			
		||||
          "-Wmisleading-indentation"
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
 
 | 
			
		||||
@@ -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<>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user