/* * catch_evaluate.hpp * Catch * * Created by Phil on 04/03/2011. * Copyright 2011 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) * */ #ifndef TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED #define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED namespace Catch { namespace Internal { enum Operator { IsEqualTo, IsNotEqualTo, IsLessThan, IsGreaterThan, IsLessThanOrEqualTo, IsGreaterThanOrEqualTo }; template struct OperatorTraits{ static const char* getName(){ return "*error - unknown operator*"; } }; template<> struct OperatorTraits{ static const char* getName(){ return "=="; } }; template<> struct OperatorTraits{ static const char* getName(){ return "!="; } }; template<> struct OperatorTraits{ static const char* getName(){ return "<"; } }; template<> struct OperatorTraits{ static const char* getName(){ return ">"; } }; template<> struct OperatorTraits{ static const char* getName(){ return "<="; } }; template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; // Because we capture the LHS and RHS of a binary condition expression by reference, then // compare the referenced values later, we may get compiler warnings when comparing unsigned // integer types with integer literals (which are signed - int or long, specifically). // To avoid this warning we filter out the problem cases as a set of overloads of the compare // function. In those overloads we cast the unsigned type to its signed equivalent then // perform the comparison. However we also have to handle the case where the signed value is // negative. Comparing a negative value with an unsigned value (which will always be positive) // has fixed logic per operator, so this is captured seperately as an enum value. enum LostSign { None = 0, LhsSignWasLost = 1, RhsSignWasLost = 2 }; // So the compare overloads can be operator agnostic we convey the operator as a template // enum, which is used to specialise an Evaluator for doing the comparison. template class Evaluator{}; template struct Evaluator { enum{ failsWhen = LhsSignWasLost | RhsSignWasLost }; static bool evaluate( const T1& lhs, const T2& rhs) { return lhs == rhs; } }; template struct Evaluator { enum{ failsWhen = None }; static bool evaluate( const T1& lhs, const T2& rhs ) { return lhs != rhs; } }; template struct Evaluator { enum{ failsWhen = RhsSignWasLost }; static bool evaluate( const T1& lhs, const T2& rhs ) { return lhs < rhs; } }; template struct Evaluator { enum{ failsWhen = LhsSignWasLost }; static bool evaluate( const T1& lhs, const T2& rhs ) { return lhs > rhs; } }; template struct Evaluator { enum{ failsWhen = LhsSignWasLost }; static bool evaluate( const T1& lhs, const T2& rhs ) { return lhs >= rhs; } }; template struct Evaluator { enum{ failsWhen = RhsSignWasLost }; static bool evaluate( const T1& lhs, const T2& rhs ) { return lhs <= rhs; } }; // All the special case signed/ unsigned overloads of compare forward to this function, // which, for negative numbers checks the special case fixed logic, otherwise forwards on // to the specialised Evaluator for the operator enum template bool applyEvaluator( const T1& lhs, const T2& rhs, LostSign lostSign ) { typedef Evaluator EvaluatorType; return lostSign == None ? EvaluatorType::evaluate( lhs, rhs ) : ( EvaluatorType::failsWhen & lostSign ) != lostSign; } template LostSign testLhsSign( T lhs ) { return lhs < 0 ? LhsSignWasLost : None; } template LostSign testRhsSign( T rhs ) { return rhs < 0 ? RhsSignWasLost : None; } // "base" overload template bool compare( const T1& lhs, const T2& rhs ) { return Evaluator::evaluate( lhs, rhs ); } // unsigned X to int template bool compare( unsigned int lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ), testRhsSign( rhs ) ); } template bool compare( unsigned long lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ), testRhsSign( rhs ) ); } template bool compare( unsigned char lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ), testRhsSign( rhs ) ); } // unsigned X to long template bool compare( unsigned int lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ), testRhsSign( rhs ) ); } template bool compare( unsigned long lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ), testRhsSign( rhs ) ); } template bool compare( unsigned char lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ), testRhsSign( rhs ) ); } // int to unsigned X template bool compare( int lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs, testLhsSign( lhs ) ); } template bool compare( int lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs, testLhsSign( lhs ) ); } template bool compare( int lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs, testLhsSign( lhs ) ); } // long to unsigned X template bool compare( long lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs, testLhsSign( lhs ) ); } template bool compare( long lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs, testLhsSign( lhs ) ); } template bool compare( long lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs, testLhsSign( lhs ) ); } template bool compare( long lhs, const T* rhs ) { return Evaluator::evaluate( reinterpret_cast( NULL ), rhs ); } template bool compare( long lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } } // end of namespace Internal } // end of namespace Catch #endif // TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED