1 /* 2 * Created by Phil on 28/04/2011. 3 * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. 4 * 5 * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 */ 8 #ifndef TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED 9 #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED 10 11 #include "catch_tostring.h" 12 13 #include <type_traits> 14 15 namespace Catch { 16 namespace Detail { 17 18 class Approx { 19 private: 20 bool equalityComparisonImpl(double other) const; 21 // Validates the new margin (margin >= 0) 22 // out-of-line to avoid including stdexcept in the header 23 void setMargin(double margin); 24 // Validates the new epsilon (0 < epsilon < 1) 25 // out-of-line to avoid including stdexcept in the header 26 void setEpsilon(double epsilon); 27 28 public: 29 explicit Approx ( double value ); 30 31 static Approx custom(); 32 33 Approx operator-() const; 34 35 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> operator()36 Approx operator()( T const& value ) { 37 Approx approx( static_cast<double>(value) ); 38 approx.m_epsilon = m_epsilon; 39 approx.m_margin = m_margin; 40 approx.m_scale = m_scale; 41 return approx; 42 } 43 44 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> Approx(T const & value)45 explicit Approx( T const& value ): Approx(static_cast<double>(value)) 46 {} 47 48 49 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 50 friend bool operator == ( const T& lhs, Approx const& rhs ) { 51 auto lhs_v = static_cast<double>(lhs); 52 return rhs.equalityComparisonImpl(lhs_v); 53 } 54 55 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 56 friend bool operator == ( Approx const& lhs, const T& rhs ) { 57 return operator==( rhs, lhs ); 58 } 59 60 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 61 friend bool operator != ( T const& lhs, Approx const& rhs ) { 62 return !operator==( lhs, rhs ); 63 } 64 65 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 66 friend bool operator != ( Approx const& lhs, T const& rhs ) { 67 return !operator==( rhs, lhs ); 68 } 69 70 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 71 friend bool operator <= ( T const& lhs, Approx const& rhs ) { 72 return static_cast<double>(lhs) < rhs.m_value || lhs == rhs; 73 } 74 75 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 76 friend bool operator <= ( Approx const& lhs, T const& rhs ) { 77 return lhs.m_value < static_cast<double>(rhs) || lhs == rhs; 78 } 79 80 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 81 friend bool operator >= ( T const& lhs, Approx const& rhs ) { 82 return static_cast<double>(lhs) > rhs.m_value || lhs == rhs; 83 } 84 85 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> 86 friend bool operator >= ( Approx const& lhs, T const& rhs ) { 87 return lhs.m_value > static_cast<double>(rhs) || lhs == rhs; 88 } 89 90 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> epsilon(T const & newEpsilon)91 Approx& epsilon( T const& newEpsilon ) { 92 double epsilonAsDouble = static_cast<double>(newEpsilon); 93 setEpsilon(epsilonAsDouble); 94 return *this; 95 } 96 97 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> margin(T const & newMargin)98 Approx& margin( T const& newMargin ) { 99 double marginAsDouble = static_cast<double>(newMargin); 100 setMargin(marginAsDouble); 101 return *this; 102 } 103 104 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> scale(T const & newScale)105 Approx& scale( T const& newScale ) { 106 m_scale = static_cast<double>(newScale); 107 return *this; 108 } 109 110 std::string toString() const; 111 112 private: 113 double m_epsilon; 114 double m_margin; 115 double m_scale; 116 double m_value; 117 }; 118 } // end namespace Detail 119 120 namespace literals { 121 Detail::Approx operator "" _a(long double val); 122 Detail::Approx operator "" _a(unsigned long long val); 123 } // end namespace literals 124 125 template<> 126 struct StringMaker<Catch::Detail::Approx> { 127 static std::string convert(Catch::Detail::Approx const& value); 128 }; 129 130 } // end namespace Catch 131 132 #endif // TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED 133