4coder-non-source/test_data/lots_of_files/safeint_internal.h

2895 lines
91 KiB
C++

/***
*safeint_internal.h - Internal details for SafeInt (see safeint.h)
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* Private internal details for SafeInt.
* The constructs and functions in Microsoft::Utilities::details are not
* meant to be used by external code and can change at any time.
*
****/
#pragma once
#include <crtdbg.h>
#pragma pack(push, _CRT_PACKING)
namespace msl
{
namespace utilities
{
namespace details
{
#pragma warning(push)
#pragma warning(disable:4702)
template < typename T > class NumericType;
template <> class NumericType<bool> { public: enum{ isBool = true, isFloat = false, isInt = false }; };
template <> class NumericType<char> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
template <> class NumericType<unsigned char> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
template <> class NumericType<signed char> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
template <> class NumericType<short> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
template <> class NumericType<unsigned short> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
#if _NATIVE_WCHAR_T_DEFINED
template <> class NumericType<wchar_t> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
#endif /* _NATIVE_WCHAR_T_DEFINED */
template <> class NumericType<int> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
template <> class NumericType<unsigned int> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
template <> class NumericType<long> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
template <> class NumericType<unsigned long> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
template <> class NumericType<__int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
template <> class NumericType<unsigned __int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
template <> class NumericType<float> { public: enum{ isBool = false, isFloat = true, isInt = false }; };
template <> class NumericType<double> { public: enum{ isBool = false, isFloat = true, isInt = false }; };
template <> class NumericType<long double> { public: enum{ isBool = false, isFloat = true, isInt = false }; };
// Catch-all for anything not supported
template < typename T > class NumericType { public: enum{ isBool = false, isFloat = false, isInt = false }; };
template < typename T > class IntTraits
{
public:
_STATIC_ASSERT( NumericType<T>::isInt || NumericType<T>::isBool );
enum
{
#pragma warning(suppress:4804)
isSigned = ( (T)(-1) < 0 ),
is64Bit = ( sizeof(T) == 8 ),
is32Bit = ( sizeof(T) == 4 ),
is16Bit = ( sizeof(T) == 2 ),
is8Bit = ( sizeof(T) == 1 ),
isLT32Bit = ( sizeof(T) < 4 ),
isLT64Bit = ( sizeof(T) < 8 ),
isInt8 = ( sizeof(T) == 1 && isSigned ),
isUint8 = ( sizeof(T) == 1 && !isSigned ),
isInt16 = ( sizeof(T) == 2 && isSigned ),
isUint16 = ( sizeof(T) == 2 && !isSigned ),
isInt32 = ( sizeof(T) == 4 && isSigned ),
isUint32 = ( sizeof(T) == 4 && !isSigned ),
isInt64 = ( sizeof(T) == 8 && isSigned ),
isUint64 = ( sizeof(T) == 8 && !isSigned ),
bitCount = ( sizeof(T)*8 ),
#pragma warning(suppress:4804)
isBool = NumericType<T>::isBool
};
#pragma warning(push)
#pragma warning(disable:4310)
const static T maxInt = isSigned ? ((T)~((T)1 << (T)(bitCount-1))) : ((T)(~(T)0));
const static T minInt = isSigned ? ((T)((T)1 << (T)(bitCount-1))) : ((T)0);
#pragma warning(pop)
};
// this is strictly internal and not to be used as a policy in SafeInt<>
struct SafeIntErrorPolicy_NoThrow
{
static void SafeIntOnOverflow()
{
}
static void SafeIntOnDivZero()
{
}
};
template < typename T, typename U > class SafeIntCompare
{
public:
enum
{
isBothSigned = (IntTraits< T >::isSigned && IntTraits< U >::isSigned),
isBothUnsigned = (!IntTraits< T >::isSigned && !IntTraits< U >::isSigned),
isLikeSigned = (IntTraits< T >::isSigned == IntTraits< U >::isSigned),
isCastOK = ((isLikeSigned && sizeof(T) >= sizeof(U)) ||
(IntTraits< T >::isSigned && sizeof(T) > sizeof(U))),
isBothLT32Bit = (IntTraits< T >::isLT32Bit && IntTraits< U >::isLT32Bit),
isBothLT64Bit = (IntTraits< T >::isLT64Bit && IntTraits< U >::isLT64Bit)
};
};
template < typename U > class SafeIntCompare< float, U >
{
public:
enum
{
isBothSigned = IntTraits< U >::isSigned,
isBothUnsigned = false,
isLikeSigned = IntTraits< U >::isSigned,
isCastOK = true
};
};
template < typename U > class SafeIntCompare< double, U >
{
public:
enum
{
isBothSigned = IntTraits< U >::isSigned,
isBothUnsigned = false,
isLikeSigned = IntTraits< U >::isSigned,
isCastOK = true
};
};
template < typename U > class SafeIntCompare< long double, U >
{
public:
enum
{
isBothSigned = IntTraits< U >::isSigned,
isBothUnsigned = false,
isLikeSigned = IntTraits< U >::isSigned,
isCastOK = true
};
};
//all of the arithmetic operators can be solved by the same code within
//each of these regions without resorting to compile-time constant conditionals
//most operators collapse the problem into less than the 22 zones, but this is used
//as the first cut
//using this also helps ensure that we handle all of the possible cases correctly
template < typename T, typename U > class IntRegion
{
public:
enum
{
//unsigned-unsigned zone
IntZone_UintLT32_UintLT32 = SafeIntCompare< T,U >::isBothUnsigned && SafeIntCompare< T,U >::isBothLT32Bit,
IntZone_Uint32_UintLT64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit,
IntZone_UintLT32_Uint32 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit,
IntZone_Uint64_Uint = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is64Bit,
IntZone_UintLT64_Uint64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit,
//unsigned-signed
IntZone_UintLT32_IntLT32 = !IntTraits< T >::isSigned && IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit,
IntZone_Uint32_IntLT64 = IntTraits< T >::isUint32 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit,
IntZone_UintLT32_Int32 = !IntTraits< T >::isSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::isInt32,
IntZone_Uint64_Int = IntTraits< T >::isUint64 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit,
IntZone_UintLT64_Int64 = !IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isInt64,
IntZone_Uint64_Int64 = IntTraits< T >::isUint64 && IntTraits< U >::isInt64,
//signed-signed
IntZone_IntLT32_IntLT32 = SafeIntCompare< T,U >::isBothSigned && SafeIntCompare< T, U >::isBothLT32Bit,
IntZone_Int32_IntLT64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit,
IntZone_IntLT32_Int32 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit,
IntZone_Int64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isInt64 && IntTraits< U >::isInt64,
IntZone_Int64_Int = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is64Bit && IntTraits< U >::isLT64Bit,
IntZone_IntLT64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit,
//signed-unsigned
IntZone_IntLT32_UintLT32 = IntTraits< T >::isSigned && !IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit,
IntZone_Int32_UintLT32 = IntTraits< T >::isInt32 && !IntTraits< U >::isSigned && IntTraits< U >::isLT32Bit,
IntZone_IntLT64_Uint32 = IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isUint32,
IntZone_Int64_UintLT64 = IntTraits< T >::isInt64 && !IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit,
IntZone_Int_Uint64 = IntTraits< T >::isSigned && IntTraits< U >::isUint64 && IntTraits< T >::isLT64Bit,
IntZone_Int64_Uint64 = IntTraits< T >::isInt64 && IntTraits< U >::isUint64
};
};
// useful function to help with getting the magnitude of a negative number
enum AbsMethod
{
AbsMethodInt,
AbsMethodInt64,
AbsMethodNoop
};
template < typename T >
class GetAbsMethod
{
public:
enum
{
method = IntTraits< T >::isLT64Bit && IntTraits< T >::isSigned ? AbsMethodInt :
IntTraits< T >::isInt64 ? AbsMethodInt64 : AbsMethodNoop
};
};
template < typename T, int Method = GetAbsMethod< T >::method > class AbsValueHelper;
template < typename T > class AbsValueHelper < T, AbsMethodInt >
{
public:
static unsigned __int32 Abs( T t ) throw()
{
_ASSERTE( t < 0 );
return (unsigned __int32)-t;
}
};
template < typename T > class AbsValueHelper < T, AbsMethodInt64 >
{
public:
static unsigned __int64 Abs( T t ) throw()
{
_ASSERTE( t < 0 );
return (unsigned __int64)-t;
}
};
template < typename T > class AbsValueHelper < T, AbsMethodNoop >
{
public:
static T Abs( T t ) throw()
{
// Why are you calling Abs on an unsigned number ???
_ASSERTE( ("AbsValueHelper::Abs should not be called with an unsigned integer type", 0) );
return t;
}
};
template < typename T, typename E, bool fSigned > class NegationHelper;
template < typename T, typename E > class NegationHelper < T, E, true > // Signed
{
public:
static SafeIntError Negative( T t, T& ret )
{
// corner case
if( t != IntTraits< T >::minInt )
{
// cast prevents unneeded checks in the case of small ints
ret = -t;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename E > class NegationHelper < T, E, false > // unsigned
{
public:
static SafeIntError Negative( T t, T& ret ) throw()
{
_SAFEINT_UNSIGNED_NEGATION_BEHAVIOR();
#pragma warning(suppress:4127)
_ASSERTE( !IntTraits<T>::isLT32Bit );
#pragma warning(suppress:4146)
ret = -t;
return SafeIntNoError;
}
};
//core logic to determine casting behavior
enum CastMethod
{
CastOK = 0,
CastCheckLTZero,
CastCheckGTMax,
CastCheckMinMaxUnsigned,
CastCheckMinMaxSigned,
CastFromFloat,
CastToBool,
CastFromBool
};
template < typename ToType, typename FromType >
class GetCastMethod
{
public:
enum
{
method = ( IntTraits< FromType >::isBool &&
!IntTraits< ToType >::isBool ) ? CastFromBool :
( !IntTraits< FromType >::isBool &&
IntTraits< ToType >::isBool ) ? CastToBool :
( NumericType< FromType >::isFloat &&
!NumericType< ToType >::isFloat ) ? CastFromFloat :
( SafeIntCompare< ToType, FromType >::isCastOK ||
( NumericType< ToType >::isFloat &&
!NumericType< FromType >::isFloat ) ) ? CastOK :
( ( IntTraits< ToType >::isSigned &&
!IntTraits< FromType >::isSigned &&
sizeof( FromType ) >= sizeof( ToType ) ) ||
( SafeIntCompare< ToType, FromType >::isBothUnsigned &&
sizeof( FromType ) > sizeof( ToType ) ) ) ? CastCheckGTMax :
( !IntTraits< ToType >::isSigned &&
IntTraits< FromType >::isSigned &&
sizeof( ToType ) >= sizeof( FromType ) ) ? CastCheckLTZero :
( !IntTraits< ToType >::isSigned ) ? CastCheckMinMaxUnsigned
: CastCheckMinMaxSigned
};
};
template < typename T, typename U, typename E,
int Method = GetCastMethod< T, U >::method > class SafeCastHelper;
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastOK >
{
public:
static SafeIntError Cast( U u, T& t ) throw()
{
t = (T)u;
return SafeIntNoError;
}
};
// special case floats and doubles
// tolerate loss of precision
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastFromFloat >
{
public:
static SafeIntError Cast( U u, T& t )
{
if( u <= (U)IntTraits< T >::maxInt &&
u >= (U)IntTraits< T >::minInt )
{
t = (T)u;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
// Match on any method where a bool is cast to type T
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastFromBool >
{
public:
static SafeIntError Cast( bool b, T& t ) throw()
{
t = (T)( b ? 1 : 0 );
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastToBool >
{
public:
static SafeIntError Cast( T t, bool& b ) throw()
{
b = !!t;
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckLTZero >
{
public:
static SafeIntError Cast( U u, T& t )
{
if( u < 0 )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
t = (T)u;
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckGTMax >
{
public:
static SafeIntError Cast( U u, T& t )
{
if( u > IntTraits< T >::maxInt )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
t = (T)u;
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckMinMaxUnsigned >
{
public:
static SafeIntError Cast( U u, T& t )
{
// U is signed - T could be either signed or unsigned
if( u > IntTraits< T >::maxInt || u < 0 )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
t = (T)u;
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckMinMaxSigned >
{
public:
static SafeIntError Cast( U u, T& t )
{
// T, U are signed
if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
t = (T)u;
return SafeIntNoError;
}
};
//core logic to determine whether a comparison is valid, or needs special treatment
enum ComparisonMethod
{
ComparisonMethod_Ok = 0,
ComparisonMethod_CastInt,
ComparisonMethod_CastInt64,
ComparisonMethod_UnsignedT,
ComparisonMethod_UnsignedU
};
template < typename T, typename U >
class ValidComparison
{
public:
enum
{
#if _SAFEINT_USE_ANSI_CONVERSIONS
method = ComparisonMethod_Ok
#else /* _SAFEINT_USE_ANSI_CONVERSIONS */
method = ( ( SafeIntCompare< T, U >::isLikeSigned ) ? ComparisonMethod_Ok :
( ( IntTraits< T >::isSigned && sizeof(T) < 8 && sizeof(U) < 4 ) ||
( IntTraits< U >::isSigned && sizeof(T) < 4 && sizeof(U) < 8 ) ) ? ComparisonMethod_CastInt :
( ( IntTraits< T >::isSigned && sizeof(U) < 8 ) ||
( IntTraits< U >::isSigned && sizeof(T) < 8 ) ) ? ComparisonMethod_CastInt64 :
( !IntTraits< T >::isSigned ) ? ComparisonMethod_UnsignedT :
ComparisonMethod_UnsignedU )
#endif /* _SAFEINT_USE_ANSI_CONVERSIONS */
};
};
template <typename T, typename U, int Method = ValidComparison< T, U >::method > class EqualityTest;
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_Ok >
{
public:
static bool IsEquals( const T t, const U u ) throw() { return ( t == u ); }
};
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt >
{
public:
static bool IsEquals( const T t, const U u ) throw() { return ( (int)t == (int)u ); }
};
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt64 >
{
public:
static bool IsEquals( const T t, const U u ) throw() { return ( (__int64)t == (__int64)u ); }
};
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedT >
{
public:
static bool IsEquals( const T t, const U u ) throw()
{
//one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
if( u < 0 )
{
return false;
}
//else safe to cast to type T
return ( t == (T)u );
}
};
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedU>
{
public:
static bool IsEquals( const T t, const U u ) throw()
{
//one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
if( t < 0 )
{
return false;
}
//else safe to cast to type U
return ( (U)t == u );
}
};
template <typename T, typename U, int Method = ValidComparison< T, U >::method > class GreaterThanTest;
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_Ok >
{
public:
static bool GreaterThan( const T t, const U u ) throw() { return ( t > u ); }
};
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt >
{
public:
static bool GreaterThan( const T t, const U u ) throw() { return ( (int)t > (int)u ); }
};
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt64 >
{
public:
static bool GreaterThan( const T t, const U u ) throw() { return ( (__int64)t > (__int64)u ); }
};
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedT >
{
public:
static bool GreaterThan( const T t, const U u ) throw()
{
// one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
if( u < 0 )
{
return SafeIntNoError;
}
// else safe to cast to type T
return ( t > (T)u );
}
};
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedU >
{
public:
static bool GreaterThan( const T t, const U u ) throw()
{
// one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
if( t < 0 )
{
return false;
}
// else safe to cast to type U
return ( (U)t > u );
}
};
// Modulus is simpler than comparison, but follows much the same logic
// using this set of functions, it can't fail except in a div 0 situation
template <typename T, typename U, typename E, int Method = ValidComparison< T, U >::method > class ModulusHelper;
template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_Ok>
{
public:
static SafeIntError Modulus( const T& t, const U& u, T& result )
{
if(u == 0)
{
E::SafeIntOnDivZero();
return SafeIntDivideByZero;
}
// trap corner case
#pragma warning(suppress:4127)
if( IntTraits< U >::isSigned )
{
if(u == -1)
{
result = 0;
return SafeIntNoError;
}
}
result = (T)(t % u);
return SafeIntNoError;
}
};
template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_CastInt>
{
public:
static SafeIntError Modulus( const T& t, const U& u, T& result )
{
if(u == 0)
{
E::SafeIntOnDivZero();
return SafeIntDivideByZero;
}
// trap corner case
#pragma warning(suppress:4127)
if( IntTraits< U >::isSigned )
{
if(u == -1)
{
result = 0;
return SafeIntNoError;
}
}
result = (T)(t % u);
return SafeIntNoError;
}
};
template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_CastInt64>
{
public:
static SafeIntError Modulus( const T& t, const U& u, T& result )
{
if(u == 0)
{
E::SafeIntOnDivZero();
return SafeIntDivideByZero;
}
#pragma warning(suppress:4127)
if(IntTraits< U >::isSigned && u == -1)
{
result = 0;
}
else
{
result = (T)((__int64)t % (__int64)u);
}
return SafeIntNoError;
}
};
// T is unsigned __int64, U is any signed int
template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_UnsignedT>
{
public:
static SafeIntError Modulus( const T& t, const U& u, T& result )
{
if(u == 0)
{
E::SafeIntOnDivZero();
return SafeIntDivideByZero;
}
// u could be negative - if so, need to convert to positive
// casts below are always safe due to the way modulus works
if(u < 0)
{
result = (T)(t % AbsValueHelper< U >::Abs(u));
}
else
{
result = (T)(t % u);
}
return SafeIntNoError;
}
};
// U is unsigned __int64, T any signed int
template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_UnsignedU>
{
public:
static SafeIntError Modulus( const T& t, const U& u, T& result )
{
if(u == 0)
{
E::SafeIntOnDivZero();
return SafeIntDivideByZero;
}
//t could be negative - if so, need to convert to positive
if(t < 0)
{
result = -(T)( AbsValueHelper< T >::Abs( t ) % u );
}
else
{
result = (T)((T)t % u);
}
return SafeIntNoError;
}
};
//core logic to determine method to check multiplication
enum MultiplicationState
{
MultiplicationState_CastInt = 0, // One or both signed, smaller than 32-bit
MultiplicationState_CastInt64, // One or both signed, smaller than 64-bit
MultiplicationState_CastUint, // Both are unsigned, smaller than 32-bit
MultiplicationState_CastUint64, // Both are unsigned, both 32-bit or smaller
MultiplicationState_Uint64Uint, // Both are unsigned, lhs 64-bit, rhs 32-bit or smaller
MultiplicationState_Uint64Uint64, // Both are unsigned int64
MultiplicationState_Uint64Int, // lhs is unsigned int64, rhs int32
MultiplicationState_Uint64Int64, // lhs is unsigned int64, rhs signed int64
MultiplicationState_UintUint64, // Both are unsigned, lhs 32-bit or smaller, rhs 64-bit
MultiplicationState_UintInt64, // lhs unsigned 32-bit or less, rhs int64
MultiplicationState_Int64Uint, // lhs int64, rhs unsigned int32
MultiplicationState_Int64Int64, // lhs int64, rhs int64
MultiplicationState_Int64Int, // lhs int64, rhs int32
MultiplicationState_IntUint64, // lhs int, rhs unsigned int64
MultiplicationState_IntInt64, // lhs int, rhs int64
MultiplicationState_Int64Uint64, // lhs int64, rhs uint64
MultiplicationState_Error
};
template < typename T, typename U >
class MultiplicationMethod
{
public:
enum
{
// unsigned-unsigned
method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? MultiplicationState_CastUint :
(IntRegion< T,U >::IntZone_Uint32_UintLT64 ||
IntRegion< T,U >::IntZone_UintLT32_Uint32) ? MultiplicationState_CastUint64 :
SafeIntCompare< T,U >::isBothUnsigned &&
IntTraits< T >::isUint64 && IntTraits< U >::isUint64 ? MultiplicationState_Uint64Uint64 :
(IntRegion< T,U >::IntZone_Uint64_Uint) ? MultiplicationState_Uint64Uint :
(IntRegion< T,U >::IntZone_UintLT64_Uint64) ? MultiplicationState_UintUint64 :
// unsigned-signed
(IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? MultiplicationState_CastInt :
(IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
IntRegion< T,U >::IntZone_UintLT32_Int32) ? MultiplicationState_CastInt64 :
(IntRegion< T,U >::IntZone_Uint64_Int) ? MultiplicationState_Uint64Int :
(IntRegion< T,U >::IntZone_UintLT64_Int64) ? MultiplicationState_UintInt64 :
(IntRegion< T,U >::IntZone_Uint64_Int64) ? MultiplicationState_Uint64Int64 :
// signed-signed
(IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? MultiplicationState_CastInt :
(IntRegion< T,U >::IntZone_Int32_IntLT64 ||
IntRegion< T,U >::IntZone_IntLT32_Int32) ? MultiplicationState_CastInt64 :
(IntRegion< T,U >::IntZone_Int64_Int64) ? MultiplicationState_Int64Int64 :
(IntRegion< T,U >::IntZone_Int64_Int) ? MultiplicationState_Int64Int :
(IntRegion< T,U >::IntZone_IntLT64_Int64) ? MultiplicationState_IntInt64 :
// signed-unsigned
(IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? MultiplicationState_CastInt :
(IntRegion< T,U >::IntZone_Int32_UintLT32 ||
IntRegion< T,U >::IntZone_IntLT64_Uint32) ? MultiplicationState_CastInt64 :
(IntRegion< T,U >::IntZone_Int64_UintLT64) ? MultiplicationState_Int64Uint :
(IntRegion< T,U >::IntZone_Int_Uint64) ? MultiplicationState_IntUint64 :
(IntRegion< T,U >::IntZone_Int64_Uint64 ? MultiplicationState_Int64Uint64 :
MultiplicationState_Error ) )
};
};
template <typename T, typename U, typename E, int Method = MultiplicationMethod< T, U >::method > class MultiplicationHelper;
template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastInt>
{
public:
//accepts signed, both less than 32-bit
static SafeIntError Multiply( const T& t, const U& u, T& ret )
{
int tmp = t * u;
if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
ret = (T)tmp;
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastUint >
{
public:
//accepts unsigned, both less than 32-bit
static SafeIntError Multiply( const T& t, const U& u, T& ret )
{
unsigned int tmp = t * u;
if( tmp > IntTraits< T >::maxInt )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
ret = (T)tmp;
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastInt64>
{
public:
//mixed signed or both signed where at least one argument is 32-bit, and both a 32-bit or less
static SafeIntError Multiply( const T& t, const U& u, T& ret )
{
__int64 tmp = (__int64)t * (__int64)u;
if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt)
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
ret = (T)tmp;
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastUint64>
{
public:
//both unsigned where at least one argument is 32-bit, and both are 32-bit or less
static SafeIntError Multiply( const T& t, const U& u, T& ret )
{
unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u;
if(tmp > (unsigned __int64)IntTraits< T >::maxInt)
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
ret = (T)tmp;
return SafeIntNoError;
}
};
// T = left arg and return type
// U = right arg
template < typename T, typename U, typename E > class LargeIntRegMultiply;
template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >
{
public:
static SafeIntError RegMultiply( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64& ret )
{
unsigned __int32 aHigh, aLow, bHigh, bLow;
// Consider that a*b can be broken up into:
// (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow)
// => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)
// Note - same approach applies for 128 bit math on a 64-bit system
aHigh = (unsigned __int32)(a >> 32);
aLow = (unsigned __int32)a;
bHigh = (unsigned __int32)(b >> 32);
bLow = (unsigned __int32)b;
ret = 0;
if(aHigh == 0)
{
if(bHigh != 0)
{
ret = (unsigned __int64)aLow * (unsigned __int64)bHigh;
}
}
else if(bHigh == 0)
{
if(aHigh != 0)
{
ret = (unsigned __int64)aHigh * (unsigned __int64)bLow;
}
}
else
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
if(ret != 0)
{
unsigned __int64 tmp;
if((unsigned __int32)(ret >> 32) != 0)
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
ret <<= 32;
tmp = (unsigned __int64)aLow * (unsigned __int64)bLow;
ret += tmp;
if(ret < tmp)
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
return SafeIntNoError;
}
ret = (unsigned __int64)aLow * (unsigned __int64)bLow;
return SafeIntNoError;
}
};
template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >
{
public:
static SafeIntError RegMultiply( const unsigned __int64& a, unsigned __int32 b, unsigned __int64& ret )
{
unsigned __int32 aHigh, aLow;
// Consider that a*b can be broken up into:
// (aHigh * 2^32 + aLow) * b
// => (aHigh * b * 2^32) + (aLow * b)
aHigh = (unsigned __int32)(a >> 32);
aLow = (unsigned __int32)a;
ret = 0;
if(aHigh != 0)
{
ret = (unsigned __int64)aHigh * (unsigned __int64)b;
unsigned __int64 tmp;
if((unsigned __int32)(ret >> 32) != 0)
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
ret <<= 32;
tmp = (unsigned __int64)aLow * (unsigned __int64)b;
ret += tmp;
if(ret < tmp)
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
return SafeIntNoError;
}
ret = (unsigned __int64)aLow * (unsigned __int64)b;
return SafeIntNoError;
}
};
template< typename E > class LargeIntRegMultiply< unsigned __int64, signed __int32, E >
{
public:
static SafeIntError RegMultiply( const unsigned __int64& a, signed __int32 b, unsigned __int64& ret )
{
if( b < 0 && a != 0 )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
return LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::RegMultiply(a, (unsigned __int32)b, ret);
}
};
template< typename E > class LargeIntRegMultiply< unsigned __int64, signed __int64, E >
{
public:
static SafeIntError RegMultiply( const unsigned __int64& a, signed __int64 b, unsigned __int64& ret )
{
if( b < 0 && a != 0 )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
return LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::RegMultiply(a, (unsigned __int64)b, ret);
}
};
template< typename E > class LargeIntRegMultiply< signed __int32, unsigned __int64, E >
{
public:
static SafeIntError RegMultiply( signed __int32 a, const unsigned __int64& b, signed __int32& ret )
{
unsigned __int32 bHigh, bLow;
bool fIsNegative = false;
// Consider that a*b can be broken up into:
// (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow)
// => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)
bHigh = (unsigned __int32)(b >> 32);
bLow = (unsigned __int32)b;
ret = 0;
if(bHigh != 0 && a != 0)
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
if( a < 0 )
{
a = -a;
fIsNegative = true;
}
unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow;
if( !fIsNegative )
{
if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt )
{
ret = (signed __int32)tmp;
return SafeIntNoError;
}
}
else
{
if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 )
{
ret = -( (signed __int32)tmp );
return SafeIntNoError;
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename E > class LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >
{
public:
static SafeIntError RegMultiply( unsigned __int32 a, const unsigned __int64& b, unsigned __int32& ret )
{
// Consider that a*b can be broken up into:
// (bHigh * 2^32 + bLow) * a
// => (bHigh * a * 2^32) + (bLow * a)
// In this case, the result must fit into 32-bits
// If bHigh != 0 && a != 0, immediate error.
if( (unsigned __int32)(b >> 32) != 0 && a != 0 )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
unsigned __int64 tmp = b * (unsigned __int64)a;
if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
ret = (unsigned __int32)tmp;
return SafeIntNoError;
}
};
template < typename E > class LargeIntRegMultiply< unsigned __int32, signed __int64, E >
{
public:
static SafeIntError RegMultiply( unsigned __int32 a, const signed __int64& b, unsigned __int32& ret )
{
if( b < 0 && a != 0 )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
return LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >::RegMultiply( a, (unsigned __int64)b, ret );
}
};
template < typename E > class LargeIntRegMultiply< signed __int64, signed __int64, E >
{
public:
static SafeIntError RegMultiply( const signed __int64& a, const signed __int64& b, signed __int64& ret )
{
bool aNegative = false;
bool bNegative = false;
unsigned __int64 tmp;
__int64 a1 = a;
__int64 b1 = b;
if( a1 < 0 )
{
aNegative = true;
a1 = -a1;
}
if( b1 < 0 )
{
bNegative = true;
b1 = -b1;
}
if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::
RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, (unsigned __int64)tmp ) == SafeIntNoError )
{
// The unsigned multiplication didn't overflow
if( aNegative ^ bNegative )
{
// Result must be negative
if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
{
ret = -(signed __int64)tmp;
return SafeIntNoError;
}
}
else
{
// Result must be positive
if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
{
ret = (signed __int64)tmp;
return SafeIntNoError;
}
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename E > class LargeIntRegMultiply< signed __int64, unsigned __int32, E >
{
public:
static SafeIntError RegMultiply( const signed __int64& a, unsigned __int32 b, signed __int64& ret )
{
bool aNegative = false;
unsigned __int64 tmp;
__int64 a1 = a;
if( a1 < 0 )
{
aNegative = true;
a1 = -a1;
}
if( LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::RegMultiply( (unsigned __int64)a1, b, tmp ) == SafeIntNoError )
{
// The unsigned multiplication didn't overflow
if( aNegative )
{
// Result must be negative
if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
{
ret = -(signed __int64)tmp;
return SafeIntNoError;
}
}
else
{
// Result must be positive
if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
{
ret = (signed __int64)tmp;
return SafeIntNoError;
}
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename E > class LargeIntRegMultiply< signed __int64, signed __int32, E >
{
public:
static SafeIntError RegMultiply( const signed __int64& a, signed __int32 b, signed __int64& ret )
{
bool aNegative = false;
bool bNegative = false;
unsigned __int64 tmp;
__int64 a1 = a;
__int64 b1 = b;
if( a1 < 0 )
{
aNegative = true;
a1 = -a1;
}
if( b1 < 0 )
{
bNegative = true;
b1 = -b1;
}
if( LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::
RegMultiply( (unsigned __int64)a1, (unsigned __int32)b1, (unsigned __int64)tmp ) == SafeIntNoError )
{
// The unsigned multiplication didn't overflow
if( aNegative ^ bNegative )
{
// Result must be negative
if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
{
ret = -(signed __int64)tmp;
return SafeIntNoError;
}
}
else
{
// Result must be positive
if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
{
ret = (signed __int64)tmp;
return SafeIntNoError;
}
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename E > class LargeIntRegMultiply< signed __int32, signed __int64, E >
{
public:
static SafeIntError RegMultiply( signed __int32 a, const signed __int64& b, signed __int32& ret )
{
bool aNegative = false;
bool bNegative = false;
unsigned __int32 tmp;
__int64 b1 = b;
if( a < 0 )
{
aNegative = true;
a = -a;
}
if( b1 < 0 )
{
bNegative = true;
b1 = -b1;
}
if( LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >::
RegMultiply( (unsigned __int32)a, (unsigned __int64)b1, tmp ) == SafeIntNoError )
{
// The unsigned multiplication didn't overflow
if( aNegative ^ bNegative )
{
// Result must be negative
if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt )
{
#pragma warning(suppress:4146)
ret = -tmp;
return SafeIntNoError;
}
}
else
{
// Result must be positive
if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt )
{
ret = (signed __int32)tmp;
return SafeIntNoError;
}
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename E > class LargeIntRegMultiply< signed __int64, unsigned __int64, E >
{
public:
static SafeIntError RegMultiply( const signed __int64& a, const unsigned __int64& b, signed __int64& ret )
{
bool aNegative = false;
unsigned __int64 tmp;
__int64 a1 = a;
if( a1 < 0 )
{
aNegative = true;
a1 = -a1;
}
if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::
RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, tmp ) == SafeIntNoError )
{
// The unsigned multiplication didn't overflow
if( aNegative )
{
// Result must be negative
if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
{
ret = -((signed __int64)tmp);
return SafeIntNoError;
}
}
else
{
// Result must be positive
if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
{
ret = (signed __int64)tmp;
return SafeIntNoError;
}
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename E > class MultiplicationHelper< unsigned __int64, unsigned __int64, E, MultiplicationState_Uint64Uint64 >
{
public:
static SafeIntError Multiply( const unsigned __int64& t, const unsigned __int64& u, unsigned __int64& ret )
{
return LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::RegMultiply( t, u, ret );
}
};
template < typename U, typename E > class MultiplicationHelper<unsigned __int64, U, E, MultiplicationState_Uint64Uint >
{
public:
//U is any unsigned int 32-bit or less
static SafeIntError Multiply( const unsigned __int64& t, const U& u, unsigned __int64& ret )
{
return LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::RegMultiply( t, (unsigned __int32)u, ret );
}
};
// converse of the previous function
template < typename T, typename E > class MultiplicationHelper< T, unsigned __int64, E, MultiplicationState_UintUint64 >
{
public:
// T is any unsigned int up to 32-bit
static SafeIntError Multiply( const T& t, const unsigned __int64& u, T& ret )
{
unsigned __int32 tmp;
if( LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >::RegMultiply( t, u, tmp ) == SafeIntNoError &&
SafeCastHelper< T, unsigned __int32, E >::Cast(tmp, ret) == SafeIntNoError )
{
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename U, typename E > class MultiplicationHelper< unsigned __int64, U, E, MultiplicationState_Uint64Int >
{
public:
//U is any signed int, up to 64-bit
static SafeIntError Multiply(const unsigned __int64& t, const U& u, unsigned __int64& ret)
{
return LargeIntRegMultiply< unsigned __int64, signed __int32, E >::RegMultiply(t, (signed __int32)u, ret);
}
};
template < typename E > class MultiplicationHelper<unsigned __int64, __int64, E, MultiplicationState_Uint64Int64 >
{
public:
static SafeIntError Multiply(const unsigned __int64& t, const __int64& u, unsigned __int64& ret)
{
return LargeIntRegMultiply< unsigned __int64, __int64, E >::RegMultiply(t, u, ret);
}
};
template < typename T, typename E > class MultiplicationHelper< T, __int64, E, MultiplicationState_UintInt64 >
{
public:
//T is unsigned up to 32-bit
static SafeIntError Multiply( const T& t, const __int64& u, T& ret )
{
unsigned __int32 tmp;
if( LargeIntRegMultiply< unsigned __int32, __int64, E >::RegMultiply( (unsigned __int32)t, u, tmp ) == SafeIntNoError &&
SafeCastHelper< T, unsigned __int32, E >::Cast( tmp, ret ) == SafeIntNoError )
{
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename U, typename E > class MultiplicationHelper<__int64, U, E, MultiplicationState_Int64Uint >
{
public:
//U is unsigned up to 32-bit
static SafeIntError Multiply( const __int64& t, const U& u, __int64& ret )
{
return LargeIntRegMultiply< __int64, unsigned __int32, E >::RegMultiply( t, (unsigned __int32)u, ret );
}
};
template < typename E > class MultiplicationHelper<__int64, __int64, E, MultiplicationState_Int64Int64 >
{
public:
static SafeIntError Multiply( const __int64& t, const __int64& u, __int64& ret )
{
return LargeIntRegMultiply< __int64, __int64, E >::RegMultiply( t, u, ret );
}
};
template < typename U, typename E > class MultiplicationHelper<__int64, U, E, MultiplicationState_Int64Int>
{
public:
//U is signed up to 32-bit
static SafeIntError Multiply( const __int64& t, U u, __int64& ret )
{
return LargeIntRegMultiply< __int64, __int32, E >::RegMultiply( t, (__int32)u, ret );
}
};
template < typename T, typename E > class MultiplicationHelper< T, unsigned __int64, E, MultiplicationState_IntUint64 >
{
public:
//T is signed up to 32-bit
static SafeIntError Multiply(T t, const unsigned __int64& u, T& ret)
{
__int32 tmp;
if( LargeIntRegMultiply< __int32, unsigned __int64, E >::RegMultiply( (__int32)t, u, tmp ) == SafeIntNoError &&
SafeCastHelper< T, __int32, E >::Cast( tmp, ret ) == SafeIntNoError )
{
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename E > class MultiplicationHelper<__int64, unsigned __int64, E, MultiplicationState_Int64Uint64>
{
public:
//U is signed up to 32-bit
static SafeIntError Multiply( const __int64& t, const unsigned __int64& u, __int64& ret )
{
return LargeIntRegMultiply< __int64, unsigned __int64, E >::RegMultiply( t, u, ret );
}
};
template < typename T, typename E > class MultiplicationHelper< T, __int64, E, MultiplicationState_IntInt64>
{
public:
//T is signed, up to 32-bit
static SafeIntError Multiply( T t, const __int64& u, T& ret )
{
__int32 tmp;
if( LargeIntRegMultiply< __int32, __int64, E >::RegMultiply( (__int32)t, u, tmp ) == SafeIntNoError &&
SafeCastHelper< T, __int32, E >::Cast( tmp, ret ) == SafeIntNoError )
{
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
enum DivisionState
{
DivisionState_OK,
DivisionState_UnsignedSigned,
DivisionState_SignedUnsigned32,
DivisionState_SignedUnsigned64,
DivisionState_SignedUnsigned,
DivisionState_SignedSigned
};
template < typename T, typename U > class DivisionMethod
{
public:
enum
{
method = (SafeIntCompare< T, U >::isBothUnsigned ? DivisionState_OK :
(!IntTraits< T >::isSigned && IntTraits< U >::isSigned) ? DivisionState_UnsignedSigned :
(IntTraits< T >::isSigned &&
IntTraits< U >::isUint32 &&
IntTraits< T >::isLT64Bit) ? DivisionState_SignedUnsigned32 :
(IntTraits< T >::isSigned && IntTraits< U >::isUint64) ? DivisionState_SignedUnsigned64 :
(IntTraits< T >::isSigned && !IntTraits< U >::isSigned) ? DivisionState_SignedUnsigned :
DivisionState_SignedSigned)
};
};
template < typename T, typename U, typename E, int Method = DivisionMethod< T, U >::method > class DivisionHelper;
template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_OK >
{
public:
static SafeIntError Divide( const T& t, const U& u, T& result )
{
if( u == 0 )
{
E::SafeIntOnDivZero();
return SafeIntDivideByZero;
}
result = (T)( t/u );
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_UnsignedSigned>
{
public:
static SafeIntError Divide( const T& t, const U& u, T& result )
{
if( u > 0 )
{
result = (T)( t/u );
return SafeIntNoError;
}
if( u == 0 )
{
E::SafeIntOnDivZero();
return SafeIntDivideByZero;
}
// it is always an error to try and divide an unsigned number by a negative signed number
// unless u is bigger than t
if( AbsValueHelper< U >::Abs( u ) > t )
{
result = 0;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedUnsigned32 >
{
public:
static SafeIntError Divide( const T& t, const U& u, T& result )
{
if( u == 0 )
{
E::SafeIntOnDivZero();
return SafeIntDivideByZero;
}
// Test for t > 0
// If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors
// As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional
if( t > 0 )
result = (T)( t/u );
else
result = (T)( (__int64)t/(__int64)u );
return SafeIntNoError;
}
};
template < typename T, typename E > class DivisionHelper< T, unsigned __int64, E, DivisionState_SignedUnsigned64 >
{
public:
static SafeIntError Divide( const T& t, const unsigned __int64& u, T& result )
{
if( u == 0 )
{
E::SafeIntOnDivZero();
return SafeIntDivideByZero;
}
if( u <= (unsigned __int64)IntTraits< T >::maxInt )
{
// Else u can safely be cast to T
#pragma warning(suppress:4127)
if( sizeof( T ) < sizeof( __int64 ) )
result = (T)( (int)t/(int)u );
else
result = (T)((__int64)t/(__int64)u);
}
else // Corner case
if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt )
{
// Min int divided by it's own magnitude is -1
result = -1;
}
else
{
result = 0;
}
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedUnsigned>
{
public:
// T is any signed, U is unsigned and smaller than 32-bit
// In this case, standard operator casting is correct
static SafeIntError Divide( const T& t, const U& u, T& result )
{
if( u == 0 )
{
E::SafeIntOnDivZero();
return SafeIntDivideByZero;
}
result = (T)( t/u );
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedSigned>
{
public:
static SafeIntError Divide( const T& t, const U& u, T& result )
{
if( u == 0 )
{
E::SafeIntOnDivZero();
return SafeIntDivideByZero;
}
// Must test for corner case
if( t == IntTraits< T >::minInt && u == -1 )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
result = (T)( t/u );
return SafeIntNoError;
}
};
enum AdditionState
{
AdditionState_CastIntCheckMax,
AdditionState_CastUintCheckOverflow,
AdditionState_CastUintCheckOverflowMax,
AdditionState_CastUint64CheckOverflow,
AdditionState_CastUint64CheckOverflowMax,
AdditionState_CastIntCheckMinMax,
AdditionState_CastInt64CheckMinMax,
AdditionState_CastInt64CheckMax,
AdditionState_CastUint64CheckMinMax,
AdditionState_CastUint64CheckMinMax2,
AdditionState_CastInt64CheckOverflow,
AdditionState_CastInt64CheckOverflowMinMax,
AdditionState_CastInt64CheckOverflowMax,
AdditionState_ManualCheckInt64Uint64,
AdditionState_ManualCheck,
AdditionState_Error
};
template< typename T, typename U >
class AdditionMethod
{
public:
enum
{
//unsigned-unsigned
method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? AdditionState_CastIntCheckMax :
(IntRegion< T,U >::IntZone_Uint32_UintLT64) ? AdditionState_CastUintCheckOverflow :
(IntRegion< T,U >::IntZone_UintLT32_Uint32) ? AdditionState_CastUintCheckOverflowMax :
(IntRegion< T,U >::IntZone_Uint64_Uint) ? AdditionState_CastUint64CheckOverflow :
(IntRegion< T,U >::IntZone_UintLT64_Uint64) ? AdditionState_CastUint64CheckOverflowMax :
//unsigned-signed
(IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? AdditionState_CastIntCheckMinMax :
(IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
IntRegion< T,U >::IntZone_UintLT32_Int32) ? AdditionState_CastInt64CheckMinMax :
(IntRegion< T,U >::IntZone_Uint64_Int ||
IntRegion< T,U >::IntZone_Uint64_Int64) ? AdditionState_CastUint64CheckMinMax :
(IntRegion< T,U >::IntZone_UintLT64_Int64) ? AdditionState_CastUint64CheckMinMax2 :
//signed-signed
(IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? AdditionState_CastIntCheckMinMax :
(IntRegion< T,U >::IntZone_Int32_IntLT64 ||
IntRegion< T,U >::IntZone_IntLT32_Int32) ? AdditionState_CastInt64CheckMinMax :
(IntRegion< T,U >::IntZone_Int64_Int ||
IntRegion< T,U >::IntZone_Int64_Int64) ? AdditionState_CastInt64CheckOverflow :
(IntRegion< T,U >::IntZone_IntLT64_Int64) ? AdditionState_CastInt64CheckOverflowMinMax :
//signed-unsigned
(IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? AdditionState_CastIntCheckMax :
(IntRegion< T,U >::IntZone_Int32_UintLT32 ||
IntRegion< T,U >::IntZone_IntLT64_Uint32) ? AdditionState_CastInt64CheckMax :
(IntRegion< T,U >::IntZone_Int64_UintLT64) ? AdditionState_CastInt64CheckOverflowMax :
(IntRegion< T,U >::IntZone_Int64_Uint64) ? AdditionState_ManualCheckInt64Uint64 :
(IntRegion< T,U >::IntZone_Int_Uint64) ? AdditionState_ManualCheck :
AdditionState_Error)
};
};
template < typename T, typename U, typename E, int Method = AdditionMethod< T, U >::method > class AdditionHelper;
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastIntCheckMax >
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
//16-bit or less unsigned addition
__int32 tmp = lhs + rhs;
if( tmp <= (__int32)IntTraits< T >::maxInt )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUintCheckOverflow >
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
// 32-bit or less - both are unsigned
unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;
//we added didn't get smaller
if( tmp >= lhs )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUintCheckOverflowMax>
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
// 32-bit or less - both are unsigned
unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;
// We added and it didn't get smaller or exceed maxInt
if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckOverflow>
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
// lhs unsigned __int64, rhs unsigned
unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
// We added and it didn't get smaller
if(tmp >= lhs)
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckOverflowMax >
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
//lhs unsigned __int64, rhs unsigned
unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
// We added and it didn't get smaller
if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastIntCheckMinMax >
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
// 16-bit or less - one or both are signed
__int32 tmp = lhs + rhs;
if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
#pragma warning(push)
#pragma warning(disable:4702)
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckMinMax >
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
// 32-bit or less - one or both are signed
__int64 tmp = (__int64)lhs + (__int64)rhs;
if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
// return E::SafeIntOnOverflow2();
}
};
#pragma warning(pop)
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckMax >
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
// 32-bit or less - lhs signed, rhs unsigned
__int64 tmp = (__int64)lhs + (__int64)rhs;
if( tmp <= IntTraits< T >::maxInt )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckMinMax >
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
// lhs is unsigned __int64, rhs signed
unsigned __int64 tmp;
if( rhs < 0 )
{
// So we're effectively subtracting
tmp = AbsValueHelper< U >::Abs( rhs );
if( tmp <= lhs )
{
result = lhs - tmp;
return SafeIntNoError;
}
}
else
{
// now we know that rhs can be safely cast into an unsigned __int64
tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
// We added and it did not become smaller
if( tmp >= lhs )
{
result = (T)tmp;
return SafeIntNoError;
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckMinMax2>
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
// lhs is unsigned and < 64-bit, rhs signed __int64
if( rhs < 0 )
{
if( lhs >= (unsigned __int64)( -rhs ) )//negation is safe, since rhs is 64-bit
{
result = (T)( lhs + rhs );
return SafeIntNoError;
}
}
else
{
// now we know that rhs can be safely cast into an unsigned __int64
unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
// special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff
// it is not possible for the operation above to overflow, so just check max
if( tmp <= IntTraits< T >::maxInt )
{
result = (T)tmp;
return SafeIntNoError;
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflow>
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
// lhs is signed __int64, rhs signed
__int64 tmp = (__int64)lhs + (__int64)rhs;
if( lhs >= 0 )
{
// mixed sign cannot overflow
if( rhs >= 0 && tmp < lhs )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
}
else
{
// lhs negative
if( rhs < 0 && tmp > lhs )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
}
result = (T)tmp;
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflowMinMax>
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
//rhs is signed __int64, lhs signed
__int64 tmp;
if( AdditionHelper< __int64, __int64, E, AdditionState_CastInt64CheckOverflow >::
Addition( (__int64)lhs, (__int64)rhs, tmp ) == SafeIntNoError &&
tmp <= IntTraits< T >::maxInt &&
tmp >= IntTraits< T >::minInt )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflowMax >
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
//lhs is signed __int64, rhs unsigned < 64-bit
__int64 tmp = lhs + (__int64)rhs;
if( tmp >= lhs )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename E > class AdditionHelper < __int64, unsigned __int64, E, AdditionState_ManualCheckInt64Uint64 >
{
public:
static SafeIntError Addition( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) throw()
{
// rhs is unsigned __int64, lhs __int64
__int64 tmp = lhs + (__int64)rhs;
if( tmp >= lhs )
{
result = tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_ManualCheck >
{
public:
static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
{
// rhs is unsigned __int64, lhs signed, 32-bit or less
if( (unsigned __int32)( rhs >> 32 ) == 0 )
{
// Now it just happens to work out that the standard behavior does what we want
// Adding explicit casts to show exactly what's happening here
__int32 tmp = (__int32)( (unsigned __int32)rhs + (unsigned __int32)lhs );
if( tmp >= lhs &&
SafeCastHelper< T, __int32, E >::Cast( tmp, result ) == SafeIntNoError )
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
enum SubtractionState
{
SubtractionState_BothUnsigned,
SubtractionState_CastIntCheckMinMax,
SubtractionState_CastIntCheckMin,
SubtractionState_CastInt64CheckMinMax,
SubtractionState_CastInt64CheckMin,
SubtractionState_Uint64Int,
SubtractionState_UintInt64,
SubtractionState_Int64Int,
SubtractionState_IntInt64,
SubtractionState_Int64Uint,
SubtractionState_IntUint64,
SubtractionState_Int64Uint64,
// states for SubtractionMethod2
SubtractionState_BothUnsigned2,
SubtractionState_CastIntCheckMinMax2,
SubtractionState_CastInt64CheckMinMax2,
SubtractionState_Uint64Int2,
SubtractionState_UintInt642,
SubtractionState_Int64Int2,
SubtractionState_IntInt642,
SubtractionState_Int64Uint2,
SubtractionState_IntUint642,
SubtractionState_Int64Uint642,
SubtractionState_Error
};
template < typename T, typename U > class SubtractionMethod
{
public:
enum
{
// unsigned-unsigned
method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 ||
(IntRegion< T,U >::IntZone_Uint32_UintLT64) ||
(IntRegion< T,U >::IntZone_UintLT32_Uint32) ||
(IntRegion< T,U >::IntZone_Uint64_Uint) ||
(IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned :
// unsigned-signed
(IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax :
(IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckMinMax :
(IntRegion< T,U >::IntZone_Uint64_Int ||
IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int :
(IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt64 :
// signed-signed
(IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax :
(IntRegion< T,U >::IntZone_Int32_IntLT64 ||
IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckMinMax :
(IntRegion< T,U >::IntZone_Int64_Int ||
IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int :
(IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt64 :
// signed-unsigned
(IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckMin :
(IntRegion< T,U >::IntZone_Int32_UintLT32 ||
IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckMin :
(IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint :
(IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint64 :
(IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint64 :
SubtractionState_Error)
};
};
// this is for the case of U - SafeInt< T, E >
template < typename T, typename U > class SubtractionMethod2
{
public:
enum
{
// unsigned-unsigned
method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 ||
(IntRegion< T,U >::IntZone_Uint32_UintLT64) ||
(IntRegion< T,U >::IntZone_UintLT32_Uint32) ||
(IntRegion< T,U >::IntZone_Uint64_Uint) ||
(IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned2 :
// unsigned-signed
(IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax2 :
(IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckMinMax2 :
(IntRegion< T,U >::IntZone_Uint64_Int ||
IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int2 :
(IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt642 :
// signed-signed
(IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax2 :
(IntRegion< T,U >::IntZone_Int32_IntLT64 ||
IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckMinMax2 :
(IntRegion< T,U >::IntZone_Int64_Int ||
IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int2 :
(IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt642 :
// signed-unsigned
(IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckMinMax2 :
(IntRegion< T,U >::IntZone_Int32_UintLT32 ||
IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckMinMax2 :
(IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint2 :
(IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint642 :
(IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint642 :
SubtractionState_Error)
};
};
template < typename T, typename U, typename E, int Method = SubtractionMethod< T, U >::method > class SubtractionHelper;
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_BothUnsigned >
{
public:
static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
{
// both are unsigned - easy case
if( rhs <= lhs )
{
result = (T)( lhs - rhs );
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_BothUnsigned2 >
{
public:
static SafeIntError Subtract( const T& lhs, const U& rhs, U& result )
{
// both are unsigned - easy case
// Except we do have to check for overflow - lhs could be larger than result can hold
if( rhs <= lhs )
{
T tmp = (T)(lhs - rhs);
return SafeCastHelper< U, T, E>::Cast( tmp, result);
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastIntCheckMinMax >
{
public:
static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
{
// both values are 16-bit or less
// rhs is signed, so could end up increasing or decreasing
__int32 tmp = lhs - rhs;
if( SafeCastHelper< T, __int32, E >::Cast( tmp, result ) == SafeIntNoError )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_CastIntCheckMinMax2 >
{
public:
static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
{
// both values are 16-bit or less
// rhs is signed, so could end up increasing or decreasing
__int32 tmp = lhs - rhs;
return SafeCastHelper< T, __int32, E >::Cast( tmp, result );
}
};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastIntCheckMin >
{
public:
static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
{
// both values are 16-bit or less
// rhs is unsigned - check only minimum
__int32 tmp = lhs - rhs;
if( tmp >= (__int32)IntTraits< T >::minInt )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastInt64CheckMinMax >
{
public:
static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
{
// both values are 32-bit or less
// rhs is signed, so could end up increasing or decreasing
__int64 tmp = (__int64)lhs - (__int64)rhs;
return SafeCastHelper< T, __int64, E >::Cast( tmp, result );
}
};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_CastInt64CheckMinMax2 >
{
public:
static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
{
// both values are 32-bit or less
// rhs is signed, so could end up increasing or decreasing
__int64 tmp = (__int64)lhs - (__int64)rhs;
return SafeCastHelper< T, __int64, E >::Cast( tmp, result );
}
};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastInt64CheckMin >
{
public:
static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
{
// both values are 32-bit or less
// rhs is unsigned - check only minimum
__int64 tmp = (__int64)lhs - (__int64)rhs;
if( tmp >= (__int64)IntTraits< T >::minInt )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Uint64Int >
{
public:
static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
{
// lhs is an unsigned __int64, rhs signed
// must first see if rhs is positive or negative
if( rhs >= 0 )
{
if( (unsigned __int64)rhs <= lhs )
{
result = (T)( lhs - (unsigned __int64)rhs );
return SafeIntNoError;
}
}
else
{
// we're now effectively adding
T tmp = lhs + AbsValueHelper< U >::Abs( rhs );
if(tmp >= lhs)
{
result = tmp;
return SafeIntNoError;
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Uint64Int2 >
{
public:
static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
{
// U is unsigned __int64, T is signed
if( rhs < 0 )
{
// treat this as addition
unsigned __int64 tmp;
tmp = lhs + (unsigned __int64)AbsValueHelper< T >::Abs( rhs );
// must check for addition overflow and max
if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
{
result = (T)tmp;
return SafeIntNoError;
}
}
else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works
{
// result is negative
// implies that lhs must fit into T, and result cannot overflow
// Also allows us to drop to 32-bit math, which is faster on a 32-bit system
result = (T)lhs - (T)rhs;
return SafeIntNoError;
}
else
{
// result is positive
unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;
if( tmp <= IntTraits< T >::maxInt )
{
result = (T)tmp;
return SafeIntNoError;
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_UintInt64 >
{
public:
static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
{
// lhs is an unsigned int32 or smaller, rhs signed __int64
// must first see if rhs is positive or negative
if( rhs >= 0 )
{
if( (unsigned __int64)rhs <= lhs )
{
result = (T)( lhs - (T)rhs );
return SafeIntNoError;
}
}
else
{
// we're now effectively adding
// since lhs is 32-bit, and rhs cannot exceed 2^63
// this addition cannot overflow
unsigned __int64 tmp = lhs + (unsigned __int64)( -rhs ); // negation safe
// but we could exceed MaxInt
if(tmp <= IntTraits< T >::maxInt)
{
result = (T)tmp;
return SafeIntNoError;
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_UintInt642 >
{
public:
static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
{
// U unsigned 32-bit or less, T __int64
if( rhs >= 0 )
{
// overflow not possible
result = (T)( (__int64)lhs - rhs );
return SafeIntNoError;
}
else
{
// we effectively have an addition
// which cannot overflow internally
unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs );
if( tmp <= (unsigned __int64)IntTraits< T >::maxInt )
{
result = (T)tmp;
return SafeIntNoError;
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Int64Int >
{
public:
static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
{
// lhs is an __int64, rhs signed (up to 64-bit)
// we have essentially 4 cases:
//
// 1) lhs positive, rhs positive - overflow not possible
// 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error
// 3) lhs negative, rhs positive - check result <= lhs
// 4) lhs negative, rhs negative - overflow not possible
__int64 tmp = lhs - rhs;
// Note - ideally, we can order these so that true conditionals
// lead to success, which enables better pipelining
// It isn't practical here
if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2
( rhs >= 0 && tmp > lhs ) ) // condition 3
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
result = (T)tmp;
return SafeIntNoError;
}
};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Int64Int2 >
{
public:
static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
{
// lhs __int64, rhs any signed int (including __int64)
__int64 tmp = lhs - rhs;
// we have essentially 4 cases:
//
// 1) lhs positive, rhs positive - overflow not possible in tmp
// 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error
// 3) lhs negative, rhs positive - check result <= lhs
// 4) lhs negative, rhs negative - overflow not possible in tmp
if( lhs >= 0 )
{
// if both positive, overflow to negative not possible
// which is why we'll explicitly check maxInt, and not call SafeCast
#pragma warning(suppress:4127)
if( ( IntTraits< T >::isLT64Bit && tmp > IntTraits< T >::maxInt ) ||
( rhs < 0 && tmp < lhs ) )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
}
else
{
// lhs negative
#pragma warning(suppress:4127)
if( ( IntTraits< T >::isLT64Bit && tmp < IntTraits< T >::minInt) ||
( rhs >=0 && tmp > lhs ) )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
}
result = (T)tmp;
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_IntInt64 >
{
public:
static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
{
// lhs is a 32-bit int or less, rhs __int64
// we have essentially 4 cases:
//
// lhs positive, rhs positive - rhs could be larger than lhs can represent
// lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int
// lhs negative, rhs positive - check tmp <= lhs and tmp < min int
// lhs negative, rhs negative - addition cannot internally overflow, check against max
__int64 tmp = (__int64)lhs - rhs;
if( lhs >= 0 )
{
// first case
if( rhs >= 0 )
{
if( tmp >= IntTraits< T >::minInt )
{
result = (T)tmp;
return SafeIntNoError;
}
}
else
{
// second case
if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
{
result = (T)tmp;
return SafeIntNoError;
}
}
}
else
{
// lhs < 0
// third case
if( rhs >= 0 )
{
if( tmp <= lhs && tmp >= IntTraits< T >::minInt )
{
result = (T)tmp;
return SafeIntNoError;
}
}
else
{
// fourth case
if( tmp <= IntTraits< T >::maxInt )
{
result = (T)tmp;
return SafeIntNoError;
}
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_IntInt642 >
{
public:
static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
{
// lhs is any signed int32 or smaller, rhs is int64
__int64 tmp = (__int64)lhs - rhs;
if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) ||
( rhs > 0 && tmp > lhs ) )
{
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
//else OK
}
result = (T)tmp;
return SafeIntNoError;
}
};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Int64Uint >
{
public:
static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
{
// lhs is a 64-bit int, rhs unsigned int32 or smaller
__int64 tmp = lhs - (__int64)rhs;
if( tmp <= lhs )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Int64Uint2 >
{
public:
// lhs is __int64, rhs is unsigned 32-bit or smaller
static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
{
__int64 tmp = lhs - (__int64)rhs;
if( tmp <= IntTraits< T >::maxInt && tmp >= IntTraits< T >::minInt )
{
result = (T)tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_IntUint64 >
{
public:
static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
{
// lhs is any signed int, rhs unsigned int64
// check against available range
// We need the absolute value of IntTraits< T >::minInt
// This will give it to us without extraneous compiler warnings
const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1;
if( lhs < 0 )
{
if( rhs <= AbsMinIntT - AbsValueHelper< T >::Abs( lhs ) )
{
result = (T)( lhs - rhs );
return SafeIntNoError;
}
}
else
{
if( rhs <= AbsMinIntT + (unsigned __int64)lhs )
{
result = (T)( lhs - rhs );
return SafeIntNoError;
}
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_IntUint642 >
{
public:
static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
{
// We run into upcasting problems on comparison - needs 2 checks
if( lhs >= 0 && (T)lhs >= rhs )
{
result = (T)((U)lhs - (U)rhs);
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename E > class SubtractionHelper< __int64, unsigned __int64, E, SubtractionState_Int64Uint64 >
{
public:
static SafeIntError Subtract( const __int64& lhs, const unsigned __int64& rhs, __int64& result )
{
// if we subtract, and it gets larger, there's a problem
__int64 tmp = lhs - (__int64)rhs;
if( tmp <= lhs )
{
result = tmp;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
template < typename E > class SubtractionHelper< __int64, unsigned __int64, E, SubtractionState_Int64Uint642 >
{
public:
// If lhs is negative, immediate problem - return must be positive, and subtracting only makes it
// get smaller. If rhs > lhs, then it would also go negative, which is the other case
static SafeIntError Subtract( const __int64& lhs, const unsigned __int64& rhs, unsigned __int64& result )
{
if( lhs >= 0 && (unsigned __int64)lhs >= rhs )
{
result = (unsigned __int64)lhs - rhs;
return SafeIntNoError;
}
E::SafeIntOnOverflow();
return SafeIntArithmeticOverflow;
}
};
enum BinaryState
{
BinaryState_OK,
BinaryState_Int8,
BinaryState_Int16,
BinaryState_Int32
};
template < typename T, typename U > class BinaryMethod
{
public:
enum
{
// If both operands are unsigned OR
// return type is smaller than rhs OR
// return type is larger and rhs is unsigned
// Then binary operations won't produce unexpected results
method = ( sizeof( T ) <= sizeof( U ) ||
SafeIntCompare< T, U >::isBothUnsigned ||
!IntTraits< U >::isSigned ) ? BinaryState_OK :
IntTraits< U >::isInt8 ? BinaryState_Int8 :
IntTraits< U >::isInt16 ? BinaryState_Int16
: BinaryState_Int32
};
};
template < typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryAndHelper;
template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_OK >
{
public:
static T And( T lhs, U rhs ){ return (T)( lhs & rhs ); }
};
template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int8 >
{
public:
static T And( T lhs, U rhs )
{
// cast forces sign extension to be zeros
_SAFEINT_BINARY_ASSERT( ( lhs & rhs ) == ( lhs & (unsigned __int8)rhs ) );
return (T)( lhs & (unsigned __int8)rhs );
}
};
template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int16 >
{
public:
static T And( T lhs, U rhs )
{
//cast forces sign extension to be zeros
_SAFEINT_BINARY_ASSERT( ( lhs & rhs ) == ( lhs & (unsigned __int16)rhs ) );
return (T)( lhs & (unsigned __int16)rhs );
}
};
template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int32 >
{
public:
static T And( T lhs, U rhs )
{
//cast forces sign extension to be zeros
_SAFEINT_BINARY_ASSERT( ( lhs & rhs ) == ( lhs & (unsigned __int32)rhs ) );
return (T)( lhs & (unsigned __int32)rhs );
}
};
template < typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryOrHelper;
template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_OK >
{
public:
static T Or( T lhs, U rhs ){ return (T)( lhs | rhs ); }
};
template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int8 >
{
public:
static T Or( T lhs, U rhs )
{
//cast forces sign extension to be zeros
_SAFEINT_BINARY_ASSERT( ( lhs | rhs ) == ( lhs | (unsigned __int8)rhs ) );
return (T)( lhs | (unsigned __int8)rhs );
}
};
template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int16 >
{
public:
static T Or( T lhs, U rhs )
{
//cast forces sign extension to be zeros
_SAFEINT_BINARY_ASSERT( ( lhs | rhs ) == ( lhs | (unsigned __int16)rhs ) );
return (T)( lhs | (unsigned __int16)rhs );
}
};
template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int32 >
{
public:
static T Or( T lhs, U rhs )
{
//cast forces sign extension to be zeros
_SAFEINT_BINARY_ASSERT( ( lhs | rhs ) == ( lhs | (unsigned __int32)rhs ) );
return (T)( lhs | (unsigned __int32)rhs );
}
};
template <typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryXorHelper;
template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_OK >
{
public:
static T Xor( T lhs, U rhs ){ return (T)( lhs ^ rhs ); }
};
template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int8 >
{
public:
static T Xor( T lhs, U rhs )
{
// cast forces sign extension to be zeros
_SAFEINT_BINARY_ASSERT( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int8)rhs ) );
return (T)( lhs ^ (unsigned __int8)rhs );
}
};
template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int16 >
{
public:
static T Xor( T lhs, U rhs )
{
// cast forces sign extension to be zeros
_SAFEINT_BINARY_ASSERT( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int16)rhs ) );
return (T)( lhs ^ (unsigned __int16)rhs );
}
};
template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int32 >
{
public:
static T Xor( T lhs, U rhs )
{
// cast forces sign extension to be zeros
_SAFEINT_BINARY_ASSERT( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int32)rhs ) );
return (T)( lhs ^ (unsigned __int32)rhs );
}
};
#pragma warning(pop)
} // namespace details
} // namespace utilities
} // namespace msl
#pragma pack(pop)