1 /* 2 * Created by Phil Nash on 8/8/2017. 3 * Copyright 2017 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_DECOMPOSER_H_INCLUDED 9 #define TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED 10 11 #include "catch_tostring.h" 12 #include "catch_stringref.h" 13 14 #include <iosfwd> 15 16 #ifdef _MSC_VER 17 #pragma warning(push) 18 #pragma warning(disable:4389) // '==' : signed/unsigned mismatch 19 #pragma warning(disable:4018) // more "signed/unsigned mismatch" 20 #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) 21 #pragma warning(disable:4180) // qualifier applied to function type has no meaning 22 #endif 23 24 namespace Catch { 25 26 struct ITransientExpression { 27 auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } 28 auto getResult() const -> bool { return m_result; } 29 virtual void streamReconstructedExpression( std::ostream &os ) const = 0; 30 ITransientExpressionITransientExpression31 ITransientExpression( bool isBinaryExpression, bool result ) 32 : m_isBinaryExpression( isBinaryExpression ), 33 m_result( result ) 34 {} 35 36 // We don't actually need a virtual destructor, but many static analysers 37 // complain if it's not here :-( 38 virtual ~ITransientExpression(); 39 40 bool m_isBinaryExpression; 41 bool m_result; 42 43 }; 44 45 void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); 46 47 template<typename LhsT, typename RhsT> 48 class BinaryExpr : public ITransientExpression { 49 LhsT m_lhs; 50 StringRef m_op; 51 RhsT m_rhs; 52 streamReconstructedExpression(std::ostream & os)53 void streamReconstructedExpression( std::ostream &os ) const override { 54 formatReconstructedExpression 55 ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); 56 } 57 58 public: BinaryExpr(bool comparisonResult,LhsT lhs,StringRef op,RhsT rhs)59 BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) 60 : ITransientExpression{ true, comparisonResult }, 61 m_lhs( lhs ), 62 m_op( op ), 63 m_rhs( rhs ) 64 {} 65 }; 66 67 template<typename LhsT> 68 class UnaryExpr : public ITransientExpression { 69 LhsT m_lhs; 70 streamReconstructedExpression(std::ostream & os)71 void streamReconstructedExpression( std::ostream &os ) const override { 72 os << Catch::Detail::stringify( m_lhs ); 73 } 74 75 public: UnaryExpr(LhsT lhs)76 explicit UnaryExpr( LhsT lhs ) 77 : ITransientExpression{ false, lhs ? true : false }, 78 m_lhs( lhs ) 79 {} 80 }; 81 82 83 // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) 84 template<typename LhsT, typename RhsT> 85 auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); } 86 template<typename T> 87 auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } 88 template<typename T> 89 auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } 90 template<typename T> 91 auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } 92 template<typename T> 93 auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } 94 95 template<typename LhsT, typename RhsT> 96 auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); } 97 template<typename T> 98 auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } 99 template<typename T> 100 auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } 101 template<typename T> 102 auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } 103 template<typename T> 104 auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } 105 106 107 template<typename LhsT> 108 class ExprLhs { 109 LhsT m_lhs; 110 public: ExprLhs(LhsT lhs)111 explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} 112 113 template<typename RhsT> 114 auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { 115 return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; 116 } 117 auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const { 118 return { m_lhs == rhs, m_lhs, "==", rhs }; 119 } 120 121 template<typename RhsT> 122 auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { 123 return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; 124 } 125 auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const { 126 return { m_lhs != rhs, m_lhs, "!=", rhs }; 127 } 128 129 template<typename RhsT> 130 auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { 131 return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs }; 132 } 133 template<typename RhsT> 134 auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { 135 return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs }; 136 } 137 template<typename RhsT> 138 auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { 139 return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs }; 140 } 141 template<typename RhsT> 142 auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { 143 return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs }; 144 } 145 146 auto makeUnaryExpr() const -> UnaryExpr<LhsT> { 147 return UnaryExpr<LhsT>{ m_lhs }; 148 } 149 }; 150 151 void handleExpression( ITransientExpression const& expr ); 152 153 template<typename T> handleExpression(ExprLhs<T> const & expr)154 void handleExpression( ExprLhs<T> const& expr ) { 155 handleExpression( expr.makeUnaryExpr() ); 156 } 157 158 struct Decomposer { 159 template<typename T> 160 auto operator <= ( T const& lhs ) -> ExprLhs<T const&> { 161 return ExprLhs<T const&>{ lhs }; 162 } 163 164 auto operator <=( bool value ) -> ExprLhs<bool> { 165 return ExprLhs<bool>{ value }; 166 } 167 }; 168 169 } // end namespace Catch 170 171 #ifdef _MSC_VER 172 #pragma warning(pop) 173 #endif 174 175 #endif // TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED 176