#ifndef SAFEINT_HPP
#define SAFEINT_HPP
#define SAFEINT_COMPILER_VISUAL_STUDIO 0
#define SAFEINT_COMPILER_CLANG 1
#define SAFEINT_COMPILER_GCC 2
#define SAFEINT_COMPILER_UNKNOWN -1
#if defined __clang__
#define SAFEINT_COMPILER SAFEINT_COMPILER_CLANG
#elif defined __GNUC__
#define SAFEINT_COMPILER SAFEINT_COMPILER_GCC
#elif defined _MSC_VER
#define SAFEINT_COMPILER SAFEINT_COMPILER_VISUAL_STUDIO
#else
#define SAFEINT_COMPILER SAFEINT_COMPILER_UNKNOWN
#endif
#define SAFEINT_CPLUSPLUS_98 0
#define SAFEINT_CPLUSPLUS_11 1
#define SAFEINT_CPLUSPLUS_14 2
#define SAFEINT_CPLUSPLUS_17 3
#define SAFEINT_CPLUSPLUS_20 4
#define SAFEINT_CPLUSPLUS_23 5
#if SAFEINT_COMPILER == SAFEINT_COMPILER_CLANG || SAFEINT_COMPILER == SAFEINT_COMPILER_GCC
#if __cplusplus < 201103L
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_98
#elif __cplusplus < 201402L
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_11
#elif __cplusplus < 201703L
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_14
#elif __cplusplus < 202002L
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_17
#elif __cplusplus < 202100L
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_20
#else
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_23
#endif
#elif SAFEINT_COMPILER == SAFEINT_COMPILER_VISUAL_STUDIO
#if _MSC_VER < 1900
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_98
#elif _MSC_VER < 1910
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_11
#elif _MSC_VER < 1920
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_14
#else
#if defined(_MSVC_LANG) && _MSVC_LANG > 202002L
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_23
#elif defined(_MSVC_LANG) && _MSVC_LANG >= 202002L
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_20
#elif defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_17
#else
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_14
#endif
#endif
#else
#define SAFEINT_CPLUSPLUS_STD SAFEINT_CPLUSPLUS_98
#endif
#if !defined SAFEINT_USE_CPLUSCPLUS_98
#if (SAFEINT_COMPILER == SAFEINT_COMPILER_CLANG || SAFEINT_COMPILER == SAFEINT_COMPILER_GCC) && SAFEINT_CPLUSPLUS_STD < SAFEINT_CPLUSPLUS_11
#error Must compile with --std=c++11, preferably --std=c++14 to use constexpr improvements
#endif
#endif
#define SAFEINT_CONSTEXPR_NONE 0
#define SAFEINT_CONSTEXPR_CPP11 1
#define SAFEINT_CONSTEXPR_CPP14 2
#if !defined SAFEINT_CONSTEXPR_SUPPORT
#if defined __cpp_constexpr
#if __cpp_constexpr >= 201304L
#define SAFEINT_CONSTEXPR_SUPPORT SAFEINT_CONSTEXPR_CPP14
#elif __cpp_constexpr >= 200704L
#define SAFEINT_CONSTEXPR_SUPPORT SAFEINT_CONSTEXPR_CPP11
#else
#define SAFEINT_CONSTEXPR_SUPPORT SAFEINT_CONSTEXPR_NONE
#endif
#else
#if SAFEINT_COMPILER == SAFEINT_COMPILER_VISUAL_STUDIO
#if SAFEINT_CPLUSPLUS_STD == SAFEINT_CPLUSPLUS_14
#define SAFEINT_CONSTEXPR_SUPPORT SAFEINT_CONSTEXPR_CPP14
#elif SAFEINT_CPLUSPLUS_STD == SAFEINT_CPLUSPLUS_11
#define SAFEINT_CONSTEXPR_SUPPORT SAFEINT_CONSTEXPR_CPP11
#else
#define SAFEINT_CONSTEXPR_SUPPORT SAFEINT_CONSTEXPR_NONE
#endif
#else
#define SAFEINT_CONSTEXPR_SUPPORT SAFEINT_CONSTEXPR_NONE
#endif
#endif
#endif
#if SAFEINT_CONSTEXPR_SUPPORT == SAFEINT_CONSTEXPR_NONE
#define SAFEINT_CONSTEXPR11
#define SAFEINT_CONSTEXPR14
#elif SAFEINT_CONSTEXPR_SUPPORT == SAFEINT_CONSTEXPR_CPP11
#define SAFEINT_CONSTEXPR11 constexpr
#define SAFEINT_CONSTEXPR14
#elif SAFEINT_CPLUSPLUS_STD >= SAFEINT_CPLUSPLUS_14
#define SAFEINT_CONSTEXPR11 constexpr
#define SAFEINT_CONSTEXPR14 constexpr
#else
#error "Unexpected value of SAFEINT_CPLUSPLUS_STD"
#endif
#if !defined SAFEINT_NO_LEGACY_MACROS
#define VISUAL_STUDIO_COMPILER SAFEINT_COMPILER_VISUAL_STUDIO
#define CLANG_COMPILER SAFEINT_COMPILER_CLANG
#define GCC_COMPILER SAFEINT_COMPILER_GCC
#define UNKNOWN_COMPILER SAFEINT_COMPILER_UNKNOWN
#define CPLUSPLUS_98 SAFEINT_CPLUSPLUS_98
#define CPLUSPLUS_11 SAFEINT_CPLUSPLUS_11
#define CPLUSPLUS_14 SAFEINT_CPLUSPLUS_14
#define CPLUSPLUS_17 SAFEINT_CPLUSPLUS_17
#define CPLUSPLUS_STD SAFEINT_CPLUSPLUS_STD
#define CONSTEXPR_NONE SAFEINT_CONSTEXPR_NONE
#define CONSTEXPR_CPP11 SAFEINT_CONSTEXPR_CPP11
#define CONSTEXPR_CPP14 SAFEINT_CONSTEXPR_CPP14
#define CONSTEXPR_SUPPORT SAFEINT_CONSTEXPR_SUPPORT
#endif
#if !defined SAFE_INT_HAS_EXCEPTIONS
#if __cpp_exceptions >= 199711L
#define SAFE_INT_HAS_EXCEPTIONS 1
#else
#define SAFE_INT_HAS_EXCEPTIONS 0
#endif
#endif
#if defined __has_cpp_attribute && __has_cpp_attribute(nodiscard) >= 201603L && SAFEINT_CPLUSPLUS_STD >= SAFEINT_CPLUSPLUS_17
#define SAFE_INT_HAS_NODISCARD 1
#else
#define SAFE_INT_HAS_NODISCARD 0
#endif
#if SAFE_INT_HAS_NODISCARD
#define SAFE_INT_NODISCARD [[nodiscard]]
#else
#define SAFE_INT_NODISCARD
#endif
#if SAFEINT_COMPILER == SAFEINT_COMPILER_VISUAL_STUDIO
#pragma warning( disable: 4514 5045 )
#pragma warning( push )
#pragma warning( disable:4987 4820 4987 4820 )
#endif
#if SAFEINT_COMPILER == SAFEINT_COMPILER_GCC || SAFEINT_COMPILER == SAFEINT_COMPILER_CLANG
#define SAFEINT_NORETURN __attribute__((noreturn))
#define SAFEINT_STDCALL
#define SAFEINT_VISIBLE __attribute__ ((__visibility__("default")))
#define SAFEINT_WEAK __attribute__ ((weak))
#else
#define SAFEINT_NORETURN __declspec(noreturn)
#define SAFEINT_STDCALL __stdcall
#define SAFEINT_VISIBLE
#define SAFEINT_WEAK
#endif
#if defined SAFEINT_REMOVE_NOTHROW || SAFEINT_CPLUSPLUS_STD == SAFEINT_CPLUSPLUS_98
#define SAFEINT_NOTHROW
#else
#define SAFEINT_NOTHROW noexcept
#endif
#include <cstdint>
#include <limits>
#include <type_traits>
#include <cstddef>
#include <cmath>
#if !defined SAFEINT_HAS_INT128
#if defined __SIZEOF_INT128__ && __SIZEOF_INT128__ == 16
#define SAFEINT_HAS_INT128 1
__extension__ typedef __int128 safeint_int128_t;
__extension__ typedef unsigned __int128 safeint_uint128_t;
#else
#define SAFEINT_HAS_INT128 0
#endif
#endif
#if SAFEINT_HAS_INT128
#define SAFEINT_USE_INTRINSICS 0
#endif
#if !defined SAFEINT_USE_INTRINSICS
#if SAFEINT_COMPILER == SAFEINT_COMPILER_VISUAL_STUDIO
#if defined _M_AMD64 && !defined _M_ARM64EC
#include <intrin.h>
#define SAFEINT_USE_INTRINSICS 1
#else
#define SAFEINT_USE_INTRINSICS 0
#endif
#else
#if SAFEINT_COMPILER == SAFEINT_COMPILER_CLANG || SAFEINT_COMPILER == SAFEINT_COMPILER_GCC
#define SAFEINT_USE_INTRINSICS 1
#else
#define SAFEINT_USE_INTRINSICS 0
#endif
#endif
#endif
#if SAFEINT_USE_INTRINSICS && SAFEINT_COMPILER == SAFEINT_COMPILER_VISUAL_STUDIO
#define SAFEINT_CONSTEXPR14_MULTIPLY
#else
#define SAFEINT_CONSTEXPR14_MULTIPLY SAFEINT_CONSTEXPR14
#endif
#if !defined SAFEINT_ASSERT
#include <assert.h>
#define SAFEINT_ASSERT(x) assert(x)
#endif
#if SAFEINT_COMPILER == SAFEINT_COMPILER_VISUAL_STUDIO
#pragma warning( pop )
#endif
static_assert( -1 == static_cast<int>(0xffffffff), "Two's complement signed numbers are required" );
enum SafeIntError
{
SafeIntNoError = 0,
SafeIntArithmeticOverflow,
SafeIntDivideByZero
};
#if defined SafeIntDefaultExceptionHandler
#if !defined SAFEINT_EXCEPTION_HANDLER_CPP
#if SAFE_INT_HAS_EXCEPTIONS
#define SAFEINT_EXCEPTION_HANDLER_CPP 1
#else
#define SAFEINT_EXCEPTION_HANDLER_CPP 0
#endif
#endif
#else
#if defined SAFEINT_ASSERT_ON_EXCEPTION
inline void SafeIntExceptionAssert() SAFEINT_NOTHROW { SAFEINT_ASSERT(false); }
#else
inline void SafeIntExceptionAssert() SAFEINT_NOTHROW {}
#endif
#define SAFEINT_EXCEPTION_WIN32 0
#define SAFEINT_EXCEPTION_ABORT 1
#define SAFEINT_EXCEPTION_CPP 2
#if defined SAFEINT_RAISE_EXCEPTION && !defined SAFE_INT_USE_STDLIB
#define SAFEINT_EXCEPTION_METHOD SAFEINT_EXCEPTION_WIN32
#elif defined SAFEINT_FAILFAST
#define SAFEINT_EXCEPTION_METHOD SAFEINT_EXCEPTION_ABORT
#else
#if SAFE_INT_HAS_EXCEPTIONS
#define SAFEINT_EXCEPTION_METHOD SAFEINT_EXCEPTION_CPP
#else
#define SAFEINT_EXCEPTION_METHOD SAFEINT_EXCEPTION_ABORT
#endif
#endif
#if SAFEINT_EXCEPTION_METHOD == SAFEINT_EXCEPTION_CPP
class SAFEINT_VISIBLE SafeIntException
{
public:
SAFEINT_CONSTEXPR11 SafeIntException(SafeIntError code = SafeIntNoError) SAFEINT_NOTHROW : m_code(code)
{
}
SafeIntError m_code;
};
namespace safeint_exception_handlers
{
template < typename E > class SafeIntExceptionHandler;
template <> class SafeIntExceptionHandler < SafeIntException >
{
public:
static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow()
{
SafeIntExceptionAssert();
throw SafeIntException(SafeIntArithmeticOverflow);
}
static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero()
{
SafeIntExceptionAssert();
throw SafeIntException(SafeIntDivideByZero);
}
};
typedef SafeIntExceptionHandler < SafeIntException > CPlusPlusExceptionHandler;
}
#define SafeIntDefaultExceptionHandler safeint_exception_handlers::CPlusPlusExceptionHandler
#define SAFEINT_EXCEPTION_HANDLER_CPP 1
#endif
#if SAFEINT_EXCEPTION_METHOD == SAFEINT_EXCEPTION_WIN32
#if !defined _WINDOWS_
#error Include windows.h in order to use Win32 exceptions
#endif
namespace safeint_exception_handlers
{
class SafeIntWin32ExceptionHandler
{
public:
static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow() SAFEINT_NOTHROW
{
SafeIntExceptionAssert();
RaiseException(static_cast<DWORD>(EXCEPTION_INT_OVERFLOW), EXCEPTION_NONCONTINUABLE, 0, 0);
}
static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero() SAFEINT_NOTHROW
{
SafeIntExceptionAssert();
RaiseException(static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), EXCEPTION_NONCONTINUABLE, 0, 0);
}
};
}
typedef safeint_exception_handlers::SafeIntWin32ExceptionHandler Win32ExceptionHandler;
#define SafeIntDefaultExceptionHandler Win32ExceptionHandler
#define SAFEINT_EXCEPTION_HANDLER_CPP 0
#endif
#if SAFEINT_EXCEPTION_METHOD == SAFEINT_EXCEPTION_ABORT
#if defined _CRT_SECURE_INVALID_PARAMETER && !defined SAFE_INT_USE_STDLIB
#define SAFE_INT_ABORT(msg) _CRT_SECURE_INVALID_PARAMETER(msg)
#else
#include <stdlib.h>
#define SAFE_INT_ABORT(msg) abort()
#endif
namespace safeint_exception_handlers
{
class SafeInt_InvalidParameter
{
public:
static SAFEINT_NORETURN void SafeIntOnOverflow() SAFEINT_NOTHROW
{
SafeIntExceptionAssert();
SAFE_INT_ABORT("SafeInt Arithmetic Overflow");
}
static SAFEINT_NORETURN void SafeIntOnDivZero() SAFEINT_NOTHROW
{
SafeIntExceptionAssert();
SAFE_INT_ABORT("SafeInt Divide By Zero");
}
};
}
typedef safeint_exception_handlers::SafeInt_InvalidParameter InvalidParameterExceptionHandler;
#define SafeIntDefaultExceptionHandler InvalidParameterExceptionHandler
#define SAFEINT_EXCEPTION_HANDLER_CPP 0
#endif
#endif
#if !defined SAFEINT_CPP_THROW
#if SAFEINT_EXCEPTION_HANDLER_CPP
#define SAFEINT_CPP_THROW
#else
#define SAFEINT_CPP_THROW SAFEINT_NOTHROW
#endif
#endif
namespace safeint_internal
{
template < typename T >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline T safeint_max() SAFEINT_NOTHROW
{
return (std::numeric_limits< T >::max)();
}
template < typename T >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline T safeint_min() SAFEINT_NOTHROW
{
return (std::numeric_limits< T >::min)();
}
template < typename T > class numeric_type;
template <> class numeric_type<bool> { public: enum { isBool = true, isInt = false }; };
template < typename T > class numeric_type
{
public:
enum
{
isBool = false, isInt = std::is_integral<T>::value || std::is_enum<T>::value,
isEnum = std::is_enum<T>::value
};
};
template < typename T > class int_traits
{
public:
static_assert(safeint_internal::numeric_type< T >::isInt, "Integer type required");
static_assert(sizeof(T) <= 8, "SafeInt supports integer types up to 64 bits");
enum
{
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 && std::numeric_limits<T>::is_signed),
isUint8 = (sizeof(T) == 1 && !std::numeric_limits<T>::is_signed),
isInt16 = (sizeof(T) == 2 && std::numeric_limits<T>::is_signed),
isUint16 = (sizeof(T) == 2 && !std::numeric_limits<T>::is_signed),
isInt32 = (sizeof(T) == 4 && std::numeric_limits<T>::is_signed),
isUint32 = (sizeof(T) == 4 && !std::numeric_limits<T>::is_signed),
isInt64 = (sizeof(T) == 8 && std::numeric_limits<T>::is_signed),
isUint64 = (sizeof(T) == 8 && !std::numeric_limits<T>::is_signed),
bitCount = (sizeof(T) * 8),
isBool = ((T)2 == (T)1)
};
};
template < typename T, typename U > class type_compare
{
public:
enum
{
isBothSigned = (std::numeric_limits< T >::is_signed && std::numeric_limits< U >::is_signed),
isBothUnsigned = (!std::numeric_limits< T >::is_signed && !std::numeric_limits< U >::is_signed),
isLikeSigned = ((bool)(std::numeric_limits< T >::is_signed) == (bool)(std::numeric_limits< U >::is_signed)),
isCastOK = ((isLikeSigned && sizeof(T) >= sizeof(U)) ||
(std::numeric_limits< T >::is_signed && sizeof(T) > sizeof(U))),
isBothLT32Bit = (safeint_internal::int_traits< T >::isLT32Bit && safeint_internal::int_traits< U >::isLT32Bit),
isBothLT64Bit = (safeint_internal::int_traits< T >::isLT64Bit && safeint_internal::int_traits< U >::isLT64Bit)
};
};
}
template < typename T, typename U > class IntRegion
{
public:
enum
{
IntZone_UintLT32_UintLT32 = safeint_internal::type_compare< T,U >::isBothUnsigned && safeint_internal::type_compare< T,U >::isBothLT32Bit,
IntZone_Uint32_UintLT64 = safeint_internal::type_compare< T,U >::isBothUnsigned && safeint_internal::int_traits< T >::is32Bit && safeint_internal::int_traits< U >::isLT64Bit,
IntZone_UintLT32_Uint32 = safeint_internal::type_compare< T,U >::isBothUnsigned && safeint_internal::int_traits< T >::isLT32Bit && safeint_internal::int_traits< U >::is32Bit,
IntZone_Uint64_Uint = safeint_internal::type_compare< T,U >::isBothUnsigned && safeint_internal::int_traits< T >::is64Bit,
IntZone_UintLT64_Uint64 = safeint_internal::type_compare< T,U >::isBothUnsigned && safeint_internal::int_traits< T >::isLT64Bit && safeint_internal::int_traits< U >::is64Bit,
IntZone_UintLT32_IntLT32 = !std::numeric_limits< T >::is_signed && std::numeric_limits< U >::is_signed && safeint_internal::type_compare< T,U >::isBothLT32Bit,
IntZone_Uint32_IntLT64 = safeint_internal::int_traits< T >::isUint32 && std::numeric_limits< U >::is_signed && safeint_internal::int_traits< U >::isLT64Bit,
IntZone_UintLT32_Int32 = !std::numeric_limits< T >::is_signed && safeint_internal::int_traits< T >::isLT32Bit && safeint_internal::int_traits< U >::isInt32,
IntZone_Uint64_Int = safeint_internal::int_traits< T >::isUint64 && std::numeric_limits< U >::is_signed && safeint_internal::int_traits< U >::isLT64Bit,
IntZone_UintLT64_Int64 = !std::numeric_limits< T >::is_signed && safeint_internal::int_traits< T >::isLT64Bit && safeint_internal::int_traits< U >::isInt64,
IntZone_Uint64_Int64 = safeint_internal::int_traits< T >::isUint64 && safeint_internal::int_traits< U >::isInt64,
IntZone_IntLT32_IntLT32 = safeint_internal::type_compare< T,U >::isBothSigned && safeint_internal::type_compare< T, U >::isBothLT32Bit,
IntZone_Int32_IntLT64 = safeint_internal::type_compare< T,U >::isBothSigned && safeint_internal::int_traits< T >::is32Bit && safeint_internal::int_traits< U >::isLT64Bit,
IntZone_IntLT32_Int32 = safeint_internal::type_compare< T,U >::isBothSigned && safeint_internal::int_traits< T >::isLT32Bit && safeint_internal::int_traits< U >::is32Bit,
IntZone_Int64_Int64 = safeint_internal::type_compare< T,U >::isBothSigned && safeint_internal::int_traits< T >::isInt64 && safeint_internal::int_traits< U >::isInt64,
IntZone_Int64_Int = safeint_internal::type_compare< T,U >::isBothSigned && safeint_internal::int_traits< T >::is64Bit && safeint_internal::int_traits< U >::isLT64Bit,
IntZone_IntLT64_Int64 = safeint_internal::type_compare< T,U >::isBothSigned && safeint_internal::int_traits< T >::isLT64Bit && safeint_internal::int_traits< U >::is64Bit,
IntZone_IntLT32_UintLT32 = std::numeric_limits< T >::is_signed && !std::numeric_limits< U >::is_signed && safeint_internal::type_compare< T,U >::isBothLT32Bit,
IntZone_Int32_UintLT32 = safeint_internal::int_traits< T >::isInt32 && !std::numeric_limits< U >::is_signed && safeint_internal::int_traits< U >::isLT32Bit,
IntZone_IntLT64_Uint32 = std::numeric_limits< T >::is_signed && safeint_internal::int_traits< T >::isLT64Bit && safeint_internal::int_traits< U >::isUint32,
IntZone_Int64_UintLT64 = safeint_internal::int_traits< T >::isInt64 && !std::numeric_limits< U >::is_signed && safeint_internal::int_traits< U >::isLT64Bit,
IntZone_Int_Uint64 = std::numeric_limits< T >::is_signed && safeint_internal::int_traits< U >::isUint64 && safeint_internal::int_traits< T >::isLT64Bit,
IntZone_Int64_Uint64 = safeint_internal::int_traits< T >::isInt64 && safeint_internal::int_traits< U >::isUint64
};
};
enum AbsMethod
{
AbsMethodInt,
AbsMethodInt64,
AbsMethodNoop
};
template < typename T >
class GetAbsMethod
{
public:
enum
{
method = safeint_internal::int_traits< T >::isLT64Bit && std::numeric_limits< T >::is_signed ? AbsMethodInt :
safeint_internal::int_traits< T >::isInt64 ? AbsMethodInt64 : AbsMethodNoop
};
};
template < typename T, int > class AbsValueHelper;
template < typename T > class AbsValueHelper < T, AbsMethodInt>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static std::uint32_t Abs( T t ) SAFEINT_NOTHROW
{
SAFEINT_ASSERT( t < 0 );
return ~(std::uint32_t)t + 1;
}
};
template < typename T > class AbsValueHelper < T, AbsMethodInt64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static std::uint64_t Abs( T t ) SAFEINT_NOTHROW
{
SAFEINT_ASSERT( t < 0 );
return ~(std::uint64_t)t + 1;
}
};
template < typename T > class AbsValueHelper < T, AbsMethodNoop >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T Abs( T t ) SAFEINT_NOTHROW
{
SAFEINT_ASSERT( false );
return t;
}
};
template < typename T > class SignedNegation;
template <>
class SignedNegation <std::int32_t>
{
public:
SAFEINT_CONSTEXPR11 static std::int32_t Value(std::uint64_t in) SAFEINT_NOTHROW
{
return (std::int32_t)(~(std::uint32_t)in + 1);
}
SAFEINT_CONSTEXPR11 static std::int32_t Value(std::uint32_t in) SAFEINT_NOTHROW
{
return (std::int32_t)(~in + 1);
}
};
template <>
class SignedNegation <std::int64_t>
{
public:
SAFEINT_CONSTEXPR11 static std::int64_t Value(std::uint64_t in) SAFEINT_NOTHROW
{
return (std::int64_t)(~in + 1);
}
};
template < typename T, bool > class NegationHelper;
template < typename T > class NegationHelper <T, true> {
public:
template <typename E>
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T NegativeThrow( T t ) SAFEINT_CPP_THROW
{
if( t != safeint_internal::safeint_min<T>() )
{
return -t;
}
E::SafeIntOnOverflow();
}
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Negative(T t, T& out)
{
if (t != safeint_internal::safeint_min<T>())
{
out = -t;
return true;
}
return false;
}
};
template < typename T > class NegationHelper <T, false> {
public:
template <typename E>
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T NegativeThrow( T t ) SAFEINT_CPP_THROW
{
#if defined SAFEINT_DISALLOW_UNSIGNED_NEGATION
static_assert( sizeof(T) == 0, "Unsigned negation is unsupported" );
#endif
return (T)SignedNegation<std::int64_t>::Value(t);
}
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Negative(T , T& )
{
return false;
}
};
enum CastMethod
{
CastOK = 0,
CastCheckLTZero,
CastCheckGTMax,
CastCheckSafeIntMinMaxUnsigned,
CastCheckSafeIntMinMaxSigned,
CastToFloat,
CastFromFloat,
CastToBool,
CastFromBool,
CastFromEnum
};
template < typename ToType, typename FromType >
class GetCastMethod
{
public:
enum
{
method = ( safeint_internal::numeric_type<FromType>::isEnum ) ? CastFromEnum :
( safeint_internal::int_traits< FromType >::isBool &&
!safeint_internal::int_traits< ToType >::isBool ) ? CastFromBool :
( !safeint_internal::int_traits< FromType >::isBool &&
safeint_internal::int_traits< ToType >::isBool ) ? CastToBool :
( safeint_internal::type_compare< ToType, FromType >::isCastOK ) ? CastOK :
( ( std::numeric_limits< ToType >::is_signed &&
!std::numeric_limits< FromType >::is_signed &&
sizeof( FromType ) >= sizeof( ToType ) ) ||
( safeint_internal::type_compare< ToType, FromType >::isBothUnsigned &&
sizeof( FromType ) > sizeof( ToType ) ) ) ? CastCheckGTMax :
( !std::numeric_limits< ToType >::is_signed &&
std::numeric_limits< FromType >::is_signed &&
sizeof( ToType ) >= sizeof( FromType ) ) ? CastCheckLTZero :
( !std::numeric_limits< ToType >::is_signed ) ? CastCheckSafeIntMinMaxUnsigned
: CastCheckSafeIntMinMaxSigned
};
};
template < typename FromType > class GetCastMethod < float, FromType >
{
public:
enum{ method = CastToFloat };
};
template < typename FromType > class GetCastMethod < double, FromType >
{
public:
enum{ method = CastToFloat };
};
template < typename FromType > class GetCastMethod < long double, FromType >
{
public:
enum{ method = CastToFloat };
};
template < typename ToType > class GetCastMethod < ToType, float >
{
public:
enum{ method = CastFromFloat };
};
template < typename ToType > class GetCastMethod < ToType, double >
{
public:
enum{ method = CastFromFloat };
};
template < typename ToType > class GetCastMethod < ToType, long double >
{
public:
enum{ method = CastFromFloat };
};
template < typename T, typename U, int > class SafeCastHelper;
template < typename T, typename U > class SafeCastHelper < T, U, CastOK >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Cast( U u, T& t ) SAFEINT_NOTHROW
{
t = (T)u;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
{
t = (T)u;
}
};
enum FloatBoundsCase
{
FloatBounds_Int8,
FloatBounds_Uint8,
FloatBounds_Int16,
FloatBounds_Uint16,
FloatBounds_Int32,
FloatBounds_Uint32,
FloatBounds_Int64,
FloatBounds_Uint64
};
template < typename T >
class GetFloatBoundsCase
{
public:
enum
{
method = safeint_internal::int_traits< T >::isInt8 ? FloatBounds_Int8 :
safeint_internal::int_traits< T >::isUint8 ? FloatBounds_Uint8 :
safeint_internal::int_traits< T >::isInt16 ? FloatBounds_Int16 :
safeint_internal::int_traits< T >::isUint16 ? FloatBounds_Uint16 :
safeint_internal::int_traits< T >::isInt32 ? FloatBounds_Int32 :
safeint_internal::int_traits< T >::isUint32 ? FloatBounds_Uint32 :
safeint_internal::int_traits< T >::isInt64 ? FloatBounds_Int64 :
FloatBounds_Uint64
};
};
template < int > class FloatBoundsHelper;
template <> class FloatBoundsHelper < FloatBounds_Int8 >
{
public:
template < typename U > static bool InRange( U u ) SAFEINT_NOTHROW
{
return u > U(-129.0L) && u < U(128.0L);
}
};
template <> class FloatBoundsHelper < FloatBounds_Uint8 >
{
public:
template < typename U > static bool InRange( U u ) SAFEINT_NOTHROW
{
return u >= U(0.0L) && u < U(256.0L);
}
};
template <> class FloatBoundsHelper < FloatBounds_Int16 >
{
public:
template < typename U > static bool InRange( U u ) SAFEINT_NOTHROW
{
return u > U(-32769.0L) && u < U(32768.0L);
}
};
template <> class FloatBoundsHelper < FloatBounds_Uint16 >
{
public:
template < typename U > static bool InRange( U u ) SAFEINT_NOTHROW
{
return u >= U(0.0L) && u < U(65536.0L);
}
};
template <> class FloatBoundsHelper < FloatBounds_Uint32 >
{
public:
template < typename U > static bool InRange( U u ) SAFEINT_NOTHROW
{
return u >= U(0.0L) && u < U(4294967296.0L);
}
};
template <> class FloatBoundsHelper < FloatBounds_Uint64 >
{
public:
template < typename U > static bool InRange( U u ) SAFEINT_NOTHROW
{
return u >= U(0.0L) && u < U(18446744073709551616.0L);
}
};
template <> class FloatBoundsHelper < FloatBounds_Int32 >
{
public:
template < typename U > static bool InRange( U u ) SAFEINT_NOTHROW
{
return InRangeImpl(u,
std::integral_constant< bool,
(std::numeric_limits< U >::digits >= 32) >());
}
private:
template < typename U >
static bool InRangeImpl( U u, std::true_type ) SAFEINT_NOTHROW
{
return u > U(-2147483649.0L) && u < U(2147483648.0L);
}
template < typename U >
static bool InRangeImpl( U u, std::false_type ) SAFEINT_NOTHROW
{
return u >= U(-2147483648.0L) && u < U(2147483648.0L);
}
};
template <> class FloatBoundsHelper < FloatBounds_Int64 >
{
public:
template < typename U > static bool InRange( U u ) SAFEINT_NOTHROW
{
return InRangeImpl(u,
std::integral_constant< bool,
(std::numeric_limits< U >::digits >= 64) >());
}
private:
template < typename U >
static bool InRangeImpl( U u, std::true_type ) SAFEINT_NOTHROW
{
return u > U(-9223372036854775809.0L) && u < U(9223372036854775808.0L);
}
template < typename U >
static bool InRangeImpl( U u, std::false_type ) SAFEINT_NOTHROW
{
return u >= U(-9223372036854775808.0L) && u < U(9223372036854775808.0L);
}
};
template < typename T, typename U > class SafeCastHelper < T, U, CastFromFloat >
{
public:
static bool Cast( U u, T& t ) SAFEINT_NOTHROW
{
if (std::isnan(u)) { return false; }
if (!FloatBoundsHelper< GetFloatBoundsCase< T >::method >::InRange(u))
{
return false;
}
t = (T)u;
return true;
}
template < typename E >
static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
{
if (std::isnan(u)) { E::SafeIntOnOverflow(); }
if (!FloatBoundsHelper< GetFloatBoundsCase< T >::method >::InRange(u))
{
E::SafeIntOnOverflow();
}
t = (T)u;
}
};
template < typename T, typename U > class SafeCastHelper < T, U, CastToFloat >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Cast( U u, T& t ) SAFEINT_NOTHROW
{
return CastImpl( u, t, PrecisionLossPossible() );
}
template < typename E >
SAFEINT_CONSTEXPR14 static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
{
CastThrowImpl< E >( u, t, PrecisionLossPossible() );
}
private:
typedef std::integral_constant< bool,
(std::numeric_limits< U >::digits > std::numeric_limits< T >::digits) >
PrecisionLossPossible;
SAFEINT_CONSTEXPR14 static bool CastImpl( U u, T& t, std::false_type ) SAFEINT_NOTHROW
{
t = (T)u;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void CastThrowImpl( U u, T& t, std::false_type ) SAFEINT_NOTHROW
{
t = (T)u;
}
SAFEINT_CONSTEXPR14 static bool CastImpl( U u, T& t, std::true_type ) SAFEINT_NOTHROW
{
#ifdef SAFEINT_STRICT_FLOAT_CONVERSION
T f = (T)u;
U back;
if ( !SafeCastHelper< U, T, CastFromFloat >::Cast( f, back ) ) { return false; }
if ( back != u ) { return false; }
t = f;
#else
t = (T)u;
#endif
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void CastThrowImpl( U u, T& t, std::true_type ) SAFEINT_CPP_THROW
{
#ifdef SAFEINT_STRICT_FLOAT_CONVERSION
T f = (T)u;
U back;
if ( !SafeCastHelper< U, T, CastFromFloat >::Cast( f, back ) ) { E::SafeIntOnOverflow(); }
if ( back != u ) { E::SafeIntOnOverflow(); }
t = f;
#else
t = (T)u;
#endif
}
};
template < typename T, typename U > class SafeCastHelper < T, U, CastFromEnum >
{
typedef typename std::underlying_type< U >::type underlying;
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Cast(U u, T& t) SAFEINT_NOTHROW
{
return SafeCastHelper< T, underlying, GetCastMethod< T, underlying >::method >::Cast(static_cast<underlying>(u), t);
}
template < typename E >
SAFEINT_CONSTEXPR14 static void CastThrow(U u, T& t) SAFEINT_CPP_THROW
{
SafeCastHelper< T, underlying, GetCastMethod< T, underlying >::method >::template CastThrow< E >(static_cast<underlying>(u), t);
}
};
template < typename T > class SafeCastHelper < T, bool, CastFromBool >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Cast( bool b, T& t ) SAFEINT_NOTHROW
{
t = (T)( b ? 1 : 0 );
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void CastThrow( bool b, T& t ) SAFEINT_CPP_THROW
{
t = (T)( b ? 1 : 0 );
}
};
template < typename T > class SafeCastHelper < bool, T, CastToBool >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Cast( T t, bool& b ) SAFEINT_NOTHROW
{
b = !!t;
return true;
}
};
template < typename T, typename U > class SafeCastHelper < T, U, CastCheckLTZero >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Cast( U u, T& t ) SAFEINT_NOTHROW
{
if( u < 0 )
return false;
t = (T)u;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
{
if( u < 0 )
E::SafeIntOnOverflow();
t = (T)u;
}
};
template < typename T, typename U > class SafeCastHelper < T, U, CastCheckGTMax >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Cast( U u, T& t ) SAFEINT_NOTHROW
{
if( u > (U)safeint_internal::safeint_max<T>() )
return false;
t = (T)u;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
{
if( u > (U)safeint_internal::safeint_max<T>() )
E::SafeIntOnOverflow();
t = (T)u;
}
};
template < typename T, typename U > class SafeCastHelper < T, U, CastCheckSafeIntMinMaxUnsigned >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Cast( U u, T& t ) SAFEINT_NOTHROW
{
if( u > safeint_internal::safeint_max<T>() || u < 0 )
return false;
t = (T)u;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
{
if( u > safeint_internal::safeint_max<T>() || u < 0 )
E::SafeIntOnOverflow();
t = (T)u;
}
};
template < typename T, typename U > class SafeCastHelper < T, U, CastCheckSafeIntMinMaxSigned >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Cast( U u, T& t ) SAFEINT_NOTHROW
{
if( u > safeint_internal::safeint_max<T>() || u < safeint_internal::safeint_min<T>() )
return false;
t = (T)u;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
{
if( u > safeint_internal::safeint_max<T>() || u < safeint_internal::safeint_min<T>() )
E::SafeIntOnOverflow();
t = (T)u;
}
};
enum ComparisonMethod
{
ComparisonMethod_Ok = 0,
ComparisonMethod_CastInt,
ComparisonMethod_CastInt64,
ComparisonMethod_UnsignedT,
ComparisonMethod_UnsignedU
};
template < typename T, typename U >
class ValidComparison
{
public:
enum
{
method = ( ( safeint_internal::type_compare< T, U >::isLikeSigned ) ? ComparisonMethod_Ok :
( ( std::numeric_limits< T >::is_signed && sizeof(T) < 8 && sizeof(U) < 4 ) ||
( std::numeric_limits< U >::is_signed && sizeof(T) < 4 && sizeof(U) < 8 ) ) ? ComparisonMethod_CastInt :
( ( std::numeric_limits< T >::is_signed && sizeof(U) < 8 ) ||
( std::numeric_limits< U >::is_signed && sizeof(T) < 8 ) ) ? ComparisonMethod_CastInt64 :
( !std::numeric_limits< T >::is_signed ) ? ComparisonMethod_UnsignedT :
ComparisonMethod_UnsignedU )
};
};
template <typename T, typename U, int state> class EqualityTest;
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_Ok >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( t == u ); }
};
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( (int)t == (int)u ); }
};
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( (std::int64_t)t == (std::int64_t)u ); }
};
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedT >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW
{
if( u < 0 )
return false;
return ( t == (T)u );
}
};
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedU>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW
{
if( t < 0 )
return false;
return ( (U)t == u );
}
};
template <typename T, typename U, int state> class GreaterThanTest;
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_Ok >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( t > u ); }
};
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( (int)t > (int)u ); }
};
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( (std::int64_t)t > (std::int64_t)u ); }
};
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedT >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW
{
if( u < 0 )
return true;
return ( t > (T)u );
}
};
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedU >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW
{
if( t < 0 )
return false;
return ( (U)t > u );
}
};
template <typename T, typename U, int method > class ModulusHelper;
template <typename U, bool> class mod_corner_case;
template <typename U> class mod_corner_case <U, true> {
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool is_undefined(U u)
{
return (u == -1);
}
};
template <typename U> class mod_corner_case <U, false> {
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool is_undefined(U)
{
return false;
}
};
template <typename T, typename U> class ModulusHelper <T, U, ComparisonMethod_Ok>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
{
if(u == 0)
return SafeIntDivideByZero;
if(mod_corner_case<U, std::numeric_limits< U >::is_signed >::is_undefined(u))
{
result = 0;
return SafeIntNoError;
}
result = (T)(t % u);
return SafeIntNoError;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
{
if(u == 0)
E::SafeIntOnDivZero();
if (mod_corner_case<U, std::numeric_limits< U >::is_signed >::is_undefined(u))
{
result = 0;
return;
}
result = (T)(t % u);
}
};
template <typename T, typename U> class ModulusHelper <T, U, ComparisonMethod_CastInt>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
{
if(u == 0)
return SafeIntDivideByZero;
if (mod_corner_case<U, std::numeric_limits< U >::is_signed >::is_undefined(u))
{
result = 0;
return SafeIntNoError;
}
result = (T)(t % u);
return SafeIntNoError;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
{
if(u == 0)
E::SafeIntOnDivZero();
if (mod_corner_case<U, std::numeric_limits< U >::is_signed >::is_undefined(u))
{
result = 0;
return;
}
result = (T)(t % u);
}
};
template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_CastInt64>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
{
if(u == 0)
return SafeIntDivideByZero;
if (mod_corner_case<U, std::numeric_limits< U >::is_signed >::is_undefined(u))
{
result = 0;
return SafeIntNoError;
}
result = (T)((std::int64_t)t % (std::int64_t)u);
return SafeIntNoError;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
{
if(u == 0)
E::SafeIntOnDivZero();
if (mod_corner_case<U, std::numeric_limits< U >::is_signed >::is_undefined(u))
{
result = 0;
return;
}
result = (T)((std::int64_t)t % (std::int64_t)u);
}
};
template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_UnsignedT>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
{
if(u == 0)
return SafeIntDivideByZero;
if(u < 0)
result = (T)(t % AbsValueHelper< U, GetAbsMethod< U >::method >::Abs(u));
else
result = (T)(t % u);
return SafeIntNoError;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
{
if(u == 0)
E::SafeIntOnDivZero();
if(u < 0)
result = (T)(t % AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ));
else
result = (T)(t % u);
}
};
template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_UnsignedU>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
{
if(u == 0)
return SafeIntDivideByZero;
if(t < 0)
result = (T)( ~( AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( t ) % u ) + 1 );
else
result = (T)((T)t % u);
return SafeIntNoError;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
{
if(u == 0)
E::SafeIntOnDivZero();
if(t < 0)
result = (T)( ~( AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( t ) % u ) + 1);
else
result = (T)( (T)t % u );
}
};
enum MultiplicationState
{
MultiplicationState_CastInt = 0, MultiplicationState_CastInt64, MultiplicationState_CastUint, MultiplicationState_CastUint64, MultiplicationState_Uint64Uint, MultiplicationState_Uint64Uint64, MultiplicationState_Uint64Int, MultiplicationState_Uint64Int64, MultiplicationState_UintUint64, MultiplicationState_UintInt64, MultiplicationState_Int64Uint, MultiplicationState_Int64Int64, MultiplicationState_Int64Int, MultiplicationState_IntUint64, MultiplicationState_IntInt64, MultiplicationState_Int64Uint64, MultiplicationState_Error
};
template < typename T, typename U >
class MultiplicationMethod
{
public:
enum
{
method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? MultiplicationState_CastUint :
(IntRegion< T,U >::IntZone_Uint32_UintLT64 ||
IntRegion< T,U >::IntZone_UintLT32_Uint32) ? MultiplicationState_CastUint64 :
safeint_internal::type_compare< T,U >::isBothUnsigned &&
safeint_internal::int_traits< T >::isUint64 && safeint_internal::int_traits< U >::isUint64 ? MultiplicationState_Uint64Uint64 :
(IntRegion< T,U >::IntZone_Uint64_Uint) ? MultiplicationState_Uint64Uint :
(IntRegion< T,U >::IntZone_UintLT64_Uint64) ? MultiplicationState_UintUint64 :
(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 :
(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 :
(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, int state> class MultiplicationHelper;
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastInt>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
{
int tmp = t * u;
if( tmp > safeint_internal::safeint_max<T>() || tmp < safeint_internal::safeint_min<T>() )
return false;
ret = (T)tmp;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
{
int tmp = t * u;
if( tmp > safeint_internal::safeint_max<T>() || tmp < safeint_internal::safeint_min<T>() )
E::SafeIntOnOverflow();
ret = (T)tmp;
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastUint >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
{
unsigned int tmp = (unsigned int)t * (unsigned int)u;
if( tmp > safeint_internal::safeint_max<T>() )
return false;
ret = (T)tmp;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
{
unsigned int tmp = (unsigned int)( t * u );
if( tmp > safeint_internal::safeint_max<T>() )
E::SafeIntOnOverflow();
ret = (T)tmp;
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastInt64>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
{
std::int64_t tmp = (std::int64_t)t * (std::int64_t)u;
if(tmp > (std::int64_t)safeint_internal::safeint_max<T>() || tmp < (std::int64_t)safeint_internal::safeint_min<T>())
return false;
ret = (T)tmp;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
{
std::int64_t tmp = (std::int64_t)t * (std::int64_t)u;
if(tmp > (std::int64_t)safeint_internal::safeint_max<T>() || tmp < (std::int64_t)safeint_internal::safeint_min<T>())
E::SafeIntOnOverflow();
ret = (T)tmp;
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastUint64>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
{
std::uint64_t tmp = (std::uint64_t)t * (std::uint64_t)u;
if(tmp > (std::uint64_t)safeint_internal::safeint_max<T>())
return false;
ret = (T)tmp;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
{
std::uint64_t tmp = (std::uint64_t)t * (std::uint64_t)u;
if(tmp > (std::uint64_t)safeint_internal::safeint_max<T>())
E::SafeIntOnOverflow();
ret = (T)tmp;
}
};
template < typename T, typename U > class LargeIntRegMultiply;
#if SAFEINT_HAS_INT128
SAFEINT_CONSTEXPR14 inline bool MultiplyUint64(std::uint64_t a, std::uint64_t b, std::uint64_t* pRet) SAFEINT_NOTHROW
{
safeint_uint128_t tmp = (safeint_uint128_t)a * (safeint_uint128_t)b;
if ((tmp >> 64) == 0)
{
*pRet = (std::uint64_t)tmp;
return true;
}
return false;
}
SAFEINT_CONSTEXPR14 inline bool MultiplyInt64(std::int64_t a, std::int64_t b, std::int64_t* pRet) SAFEINT_NOTHROW
{
safeint_int128_t tmp = (safeint_int128_t)a * (safeint_int128_t)b;
*pRet = (std::int64_t)tmp;
std::int64_t tmp_high = (std::int64_t)((safeint_uint128_t)tmp >> 64);
if( (a ^ b) < 0 )
{
if( (tmp_high == -1 && *pRet < 0) ||
(tmp_high == 0 && *pRet == 0))
{
return true;
}
}
else
{
if (tmp_high == 0)
{
return (std::uint64_t)*pRet <= (std::uint64_t)safeint_internal::safeint_max<std::int64_t>();
}
}
return false;
}
#endif
#if SAFEINT_USE_INTRINSICS
#if SAFEINT_COMPILER == SAFEINT_COMPILER_VISUAL_STUDIO
inline bool MultiplyUint64( std::uint64_t a, std::uint64_t b, std::uint64_t* pRet ) SAFEINT_NOTHROW
{
std::uint64_t ulHigh = 0;
*pRet = _umul128(a , b, &ulHigh);
return ulHigh == 0;
}
inline bool MultiplyInt64( std::int64_t a, std::int64_t b, std::int64_t* pRet ) SAFEINT_NOTHROW
{
std::int64_t llHigh = 0;
*pRet = _mul128(a , b, &llHigh);
if( (a ^ b) < 0 )
{
if( llHigh == -1 && *pRet < 0 ||
llHigh == 0 && *pRet == 0 )
{
return true;
}
}
else
{
if( llHigh == 0 && (std::uint64_t)*pRet <= (std::uint64_t)safeint_internal::safeint_max<std::int64_t>() )
return true;
}
return false;
}
#elif SAFEINT_COMPILER == SAFEINT_COMPILER_GCC || SAFEINT_COMPILER == SAFEINT_COMPILER_CLANG
SAFEINT_CONSTEXPR14 inline bool MultiplyUint64(std::uint64_t a, std::uint64_t b, std::uint64_t* pRet) SAFEINT_NOTHROW
{
return !__builtin_umulll_overflow(a, b, (unsigned long long*)pRet);
}
SAFEINT_CONSTEXPR14 inline bool MultiplyInt64(std::int64_t a, std::int64_t b, std::int64_t* pRet) SAFEINT_NOTHROW
{
return !__builtin_smulll_overflow(a, b, (long long*)pRet);
}
#else
# error Intrinsics enabled, no available intrinics defined
#endif
#endif
template<> class LargeIntRegMultiply< std::uint64_t, std::uint64_t >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool RegMultiply( const std::uint64_t& a, const std::uint64_t& b, std::uint64_t* pRet ) SAFEINT_NOTHROW
{
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
return MultiplyUint64( a, b, pRet );
#else
std::uint32_t aHigh = 0, aLow = 0, bHigh = 0, bLow = 0;
aHigh = (std::uint32_t)(a >> 32);
aLow = (std::uint32_t)a;
bHigh = (std::uint32_t)(b >> 32);
bLow = (std::uint32_t)b;
*pRet = 0;
if(aHigh == 0)
{
if(bHigh != 0)
{
*pRet = (std::uint64_t)aLow * (std::uint64_t)bHigh;
}
}
else if(bHigh == 0)
{
if(aHigh != 0)
{
*pRet = (std::uint64_t)aHigh * (std::uint64_t)bLow;
}
}
else
{
return false;
}
if(*pRet != 0)
{
std::uint64_t tmp = 0;
if((std::uint32_t)(*pRet >> 32) != 0)
return false;
*pRet <<= 32;
tmp = (std::uint64_t)aLow * (std::uint64_t)bLow;
*pRet += tmp;
if(*pRet < tmp)
return false;
return true;
}
*pRet = (std::uint64_t)aLow * (std::uint64_t)bLow;
return true;
#endif
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void RegMultiplyThrow( const std::uint64_t& a, const std::uint64_t& b, std::uint64_t* pRet ) SAFEINT_CPP_THROW
{
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
if( !MultiplyUint64( a, b, pRet ) )
E::SafeIntOnOverflow();
#else
std::uint32_t aHigh = 0, aLow = 0, bHigh = 0, bLow = 0;
aHigh = (std::uint32_t)(a >> 32);
aLow = (std::uint32_t)a;
bHigh = (std::uint32_t)(b >> 32);
bLow = (std::uint32_t)b;
*pRet = 0;
if(aHigh == 0)
{
if(bHigh != 0)
{
*pRet = (std::uint64_t)aLow * (std::uint64_t)bHigh;
}
}
else if(bHigh == 0)
{
if(aHigh != 0)
{
*pRet = (std::uint64_t)aHigh * (std::uint64_t)bLow;
}
}
else
{
E::SafeIntOnOverflow();
}
if(*pRet != 0)
{
std::uint64_t tmp = 0;
if((std::uint32_t)(*pRet >> 32) != 0)
E::SafeIntOnOverflow();
*pRet <<= 32;
tmp = (std::uint64_t)aLow * (std::uint64_t)bLow;
*pRet += tmp;
if(*pRet < tmp)
E::SafeIntOnOverflow();
return;
}
*pRet = (std::uint64_t)aLow * (std::uint64_t)bLow;
#endif
}
};
template<> class LargeIntRegMultiply< std::uint64_t, std::uint32_t >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool RegMultiply( const std::uint64_t& a, std::uint32_t b, std::uint64_t* pRet ) SAFEINT_NOTHROW
{
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
return MultiplyUint64( a, (std::uint64_t)b, pRet );
#else
std::uint32_t aHigh = 0, aLow = 0;
aHigh = (std::uint32_t)(a >> 32);
aLow = (std::uint32_t)a;
*pRet = 0;
if(aHigh != 0)
{
*pRet = (std::uint64_t)aHigh * (std::uint64_t)b;
std::uint64_t tmp = 0;
if((std::uint32_t)(*pRet >> 32) != 0)
return false;
*pRet <<= 32;
tmp = (std::uint64_t)aLow * (std::uint64_t)b;
*pRet += tmp;
if(*pRet < tmp)
return false;
return true;
}
*pRet = (std::uint64_t)aLow * (std::uint64_t)b;
return true;
#endif
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void RegMultiplyThrow( const std::uint64_t& a, std::uint32_t b, std::uint64_t* pRet ) SAFEINT_CPP_THROW
{
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
if( !MultiplyUint64( a, (std::uint64_t)b, pRet ) )
E::SafeIntOnOverflow();
#else
std::uint32_t aHigh = 0, aLow = 0;
aHigh = (std::uint32_t)(a >> 32);
aLow = (std::uint32_t)a;
*pRet = 0;
if(aHigh != 0)
{
*pRet = (std::uint64_t)aHigh * (std::uint64_t)b;
std::uint64_t tmp = 0;
if((std::uint32_t)(*pRet >> 32) != 0)
E::SafeIntOnOverflow();
*pRet <<= 32;
tmp = (std::uint64_t)aLow * (std::uint64_t)b;
*pRet += tmp;
if(*pRet < tmp)
E::SafeIntOnOverflow();
return;
}
*pRet = (std::uint64_t)aLow * (std::uint64_t)b;
return;
#endif
}
};
template<> class LargeIntRegMultiply< std::uint64_t, std::int32_t >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool RegMultiply( const std::uint64_t& a, std::int32_t b, std::uint64_t* pRet ) SAFEINT_NOTHROW
{
if( b < 0 && a != 0 )
return false;
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
return MultiplyUint64( a, (std::uint64_t)b, pRet );
#else
return LargeIntRegMultiply< std::uint64_t, std::uint32_t >::RegMultiply(a, (std::uint32_t)b, pRet);
#endif
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void RegMultiplyThrow( const std::uint64_t& a, std::int32_t b, std::uint64_t* pRet ) SAFEINT_CPP_THROW
{
if( b < 0 && a != 0 )
E::SafeIntOnOverflow();
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
if( !MultiplyUint64( a, (std::uint64_t)b, pRet ) )
E::SafeIntOnOverflow();
#else
LargeIntRegMultiply< std::uint64_t, std::uint32_t >::template RegMultiplyThrow< E >( a, (std::uint32_t)b, pRet );
#endif
}
};
template<> class LargeIntRegMultiply< std::uint64_t, std::int64_t >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool RegMultiply( const std::uint64_t& a, std::int64_t b, std::uint64_t* pRet ) SAFEINT_NOTHROW
{
if( b < 0 && a != 0 )
return false;
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
return MultiplyUint64( a, (std::uint64_t)b, pRet );
#else
return LargeIntRegMultiply< std::uint64_t, std::uint64_t >::RegMultiply(a, (std::uint64_t)b, pRet);
#endif
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void RegMultiplyThrow( const std::uint64_t& a, std::int64_t b, std::uint64_t* pRet ) SAFEINT_CPP_THROW
{
if( b < 0 && a != 0 )
E::SafeIntOnOverflow();
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
if( !MultiplyUint64( a, (std::uint64_t)b, pRet ) )
E::SafeIntOnOverflow();
#else
LargeIntRegMultiply< std::uint64_t, std::uint64_t >::template RegMultiplyThrow< E >( a, (std::uint64_t)b, pRet );
#endif
}
};
template<> class LargeIntRegMultiply< std::int32_t, std::uint64_t >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool RegMultiply( std::int32_t a, const std::uint64_t& b, std::int32_t* pRet ) SAFEINT_NOTHROW
{
std::uint32_t bHigh = 0, bLow = 0;
bool fIsNegative = false;
bHigh = (std::uint32_t)(b >> 32);
bLow = (std::uint32_t)b;
*pRet = 0;
if(bHigh != 0 && a != 0)
return false;
if( a < 0 )
{
a = (std::int32_t)AbsValueHelper< std::int32_t, GetAbsMethod< std::int32_t >::method >::Abs(a);
fIsNegative = true;
}
std::uint64_t tmp = (std::uint32_t)a * (std::uint64_t)bLow;
if( !fIsNegative )
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<std::int32_t>() )
{
*pRet = (std::int32_t)tmp;
return true;
}
}
else
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<std::int32_t>()+1 )
{
*pRet = SignedNegation< std::int32_t >::Value( tmp );
return true;
}
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void RegMultiplyThrow( std::int32_t a, const std::uint64_t& b, std::int32_t* pRet ) SAFEINT_CPP_THROW
{
std::uint32_t bHigh = 0, bLow = 0;
bool fIsNegative = false;
bHigh = (std::uint32_t)(b >> 32);
bLow = (std::uint32_t)b;
*pRet = 0;
if(bHigh != 0 && a != 0)
E::SafeIntOnOverflow();
if( a < 0 )
{
a = (std::int32_t)AbsValueHelper< std::int32_t, GetAbsMethod< std::int32_t >::method >::Abs(a);
fIsNegative = true;
}
std::uint64_t tmp = (std::uint32_t)a * (std::uint64_t)bLow;
if( !fIsNegative )
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<std::int32_t>() )
{
*pRet = (std::int32_t)tmp;
return;
}
}
else
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<std::int32_t>()+1 )
{
*pRet = SignedNegation< std::int32_t >::Value( tmp );
return;
}
}
E::SafeIntOnOverflow();
}
};
template<> class LargeIntRegMultiply< std::uint32_t, std::uint64_t >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool RegMultiply( std::uint32_t a, const std::uint64_t& b, std::uint32_t* pRet ) SAFEINT_NOTHROW
{
if( (std::uint32_t)(b >> 32) != 0 && a != 0 )
return false;
std::uint64_t tmp = b * (std::uint64_t)a;
if( (std::uint32_t)(tmp >> 32) != 0 ) return false;
*pRet = (std::uint32_t)tmp;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void RegMultiplyThrow( std::uint32_t a, const std::uint64_t& b, std::uint32_t* pRet ) SAFEINT_CPP_THROW
{
if( (std::uint32_t)(b >> 32) != 0 && a != 0 )
E::SafeIntOnOverflow();
std::uint64_t tmp = b * (std::uint64_t)a;
if( (std::uint32_t)(tmp >> 32) != 0 ) E::SafeIntOnOverflow();
*pRet = (std::uint32_t)tmp;
}
};
template<> class LargeIntRegMultiply< std::uint32_t, std::int64_t >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool RegMultiply( std::uint32_t a, const std::int64_t& b, std::uint32_t* pRet ) SAFEINT_NOTHROW
{
if( b < 0 && a != 0 )
return false;
return LargeIntRegMultiply< std::uint32_t, std::uint64_t >::RegMultiply( a, (std::uint64_t)b, pRet );
}
template < typename E >
SAFEINT_CONSTEXPR14 static void RegMultiplyThrow( std::uint32_t a, const std::int64_t& b, std::uint32_t* pRet ) SAFEINT_CPP_THROW
{
if( b < 0 && a != 0 )
E::SafeIntOnOverflow();
LargeIntRegMultiply< std::uint32_t, std::uint64_t >::template RegMultiplyThrow< E >( a, (std::uint64_t)b, pRet );
}
};
template<> class LargeIntRegMultiply< std::int64_t, std::int64_t >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool RegMultiply( const std::int64_t& a, const std::int64_t& b, std::int64_t* pRet ) SAFEINT_NOTHROW
{
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
return MultiplyInt64( a, b, pRet );
#else
bool aNegative = false;
bool bNegative = false;
std::uint64_t tmp = 0;
std::int64_t a1 = a;
std::int64_t b1 = b;
if( a1 < 0 )
{
aNegative = true;
a1 = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(a1);
}
if( b1 < 0 )
{
bNegative = true;
b1 = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(b1);
}
if( LargeIntRegMultiply< std::uint64_t, std::uint64_t >::RegMultiply( (std::uint64_t)a1, (std::uint64_t)b1, &tmp ) )
{
if( aNegative ^ bNegative )
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_min<std::int64_t>() )
{
*pRet = SignedNegation< std::int64_t >::Value( tmp );
return true;
}
}
else
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<std::int64_t>() )
{
*pRet = (std::int64_t)tmp;
return true;
}
}
}
return false;
#endif
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void RegMultiplyThrow( const std::int64_t& a, const std::int64_t& b, std::int64_t* pRet ) SAFEINT_CPP_THROW
{
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
if( !MultiplyInt64( a, b, pRet ) )
E::SafeIntOnOverflow();
#else
bool aNegative = false;
bool bNegative = false;
std::uint64_t tmp = 0;
std::int64_t a1 = a;
std::int64_t b1 = b;
if( a1 < 0 )
{
aNegative = true;
a1 = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(a1);
}
if( b1 < 0 )
{
bNegative = true;
b1 = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(b1);
}
LargeIntRegMultiply< std::uint64_t, std::uint64_t >::template RegMultiplyThrow< E >( (std::uint64_t)a1, (std::uint64_t)b1, &tmp );
if( aNegative ^ bNegative )
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_min<std::int64_t>() )
{
*pRet = SignedNegation< std::int64_t >::Value( tmp );
return;
}
}
else
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<std::int64_t>() )
{
*pRet = (std::int64_t)tmp;
return;
}
}
E::SafeIntOnOverflow();
#endif
}
};
template<> class LargeIntRegMultiply< std::int64_t, std::uint32_t >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool RegMultiply( const std::int64_t& a, std::uint32_t b, std::int64_t* pRet ) SAFEINT_NOTHROW
{
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
return MultiplyInt64( a, (std::int64_t)b, pRet );
#else
bool aNegative = false;
std::uint64_t tmp = 0;
std::int64_t a1 = a;
if( a1 < 0 )
{
aNegative = true;
a1 = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(a1);
}
if( LargeIntRegMultiply< std::uint64_t, std::uint32_t >::RegMultiply( (std::uint64_t)a1, b, &tmp ) )
{
if( aNegative )
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_min<std::int64_t>() )
{
*pRet = SignedNegation< std::int64_t >::Value( tmp );
return true;
}
}
else
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<std::int64_t>() )
{
*pRet = (std::int64_t)tmp;
return true;
}
}
}
return false;
#endif
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void RegMultiplyThrow( const std::int64_t& a, std::uint32_t b, std::int64_t* pRet ) SAFEINT_CPP_THROW
{
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
if( !MultiplyInt64( a, (std::int64_t)b, pRet ) )
E::SafeIntOnOverflow();
#else
bool aNegative = false;
std::uint64_t tmp = 0;
std::int64_t a1 = a;
if( a1 < 0 )
{
aNegative = true;
a1 = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(a1);
}
LargeIntRegMultiply< std::uint64_t, std::uint32_t >::template RegMultiplyThrow< E >( (std::uint64_t)a1, b, &tmp );
if( aNegative )
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_min<std::int64_t>() )
{
*pRet = SignedNegation< std::int64_t >::Value( tmp );
return;
}
}
else
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<std::int64_t>() )
{
*pRet = (std::int64_t)tmp;
return;
}
}
E::SafeIntOnOverflow();
#endif
}
};
template<> class LargeIntRegMultiply< std::int64_t, std::int32_t >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool RegMultiply( const std::int64_t& a, std::int32_t b, std::int64_t* pRet ) SAFEINT_NOTHROW
{
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
return MultiplyInt64( a, (std::int64_t)b, pRet );
#else
bool aNegative = false;
bool bNegative = false;
std::uint64_t tmp = 0;
std::int64_t a1 = a;
std::int64_t b1 = b;
if( a1 < 0 )
{
aNegative = true;
a1 = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(a1);
}
if( b1 < 0 )
{
bNegative = true;
b1 = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(b1);
}
if( LargeIntRegMultiply< std::uint64_t, std::uint32_t >::RegMultiply( (std::uint64_t)a1, (std::uint32_t)b1, &tmp ) )
{
if( aNegative ^ bNegative )
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_min<std::int64_t>() )
{
*pRet = SignedNegation< std::int64_t >::Value( tmp );
return true;
}
}
else
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<std::int64_t>() )
{
*pRet = (std::int64_t)tmp;
return true;
}
}
}
return false;
#endif
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void RegMultiplyThrow( std::int64_t a, std::int32_t b, std::int64_t* pRet ) SAFEINT_CPP_THROW
{
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
if( !MultiplyInt64( a, (std::int64_t)b, pRet ) )
E::SafeIntOnOverflow();
#else
bool aNegative = false;
bool bNegative = false;
std::uint64_t tmp = 0;
if( a < 0 )
{
aNegative = true;
a = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(a);
}
if( b < 0 )
{
bNegative = true;
b = (std::int32_t)AbsValueHelper< std::int32_t, GetAbsMethod< std::int32_t >::method >::Abs(b);
}
LargeIntRegMultiply< std::uint64_t, std::uint32_t >::template RegMultiplyThrow< E >( (std::uint64_t)a, (std::uint32_t)b, &tmp );
if( aNegative ^ bNegative )
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_min<std::int64_t>() )
{
*pRet = SignedNegation< std::int64_t >::Value( tmp );
return;
}
}
else
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<std::int64_t>() )
{
*pRet = (std::int64_t)tmp;
return;
}
}
E::SafeIntOnOverflow();
#endif
}
};
template<> class LargeIntRegMultiply< std::int32_t, std::int64_t >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool RegMultiply( std::int32_t a, const std::int64_t& b, std::int32_t* pRet ) SAFEINT_NOTHROW
{
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
std::int64_t tmp = 0;
if( MultiplyInt64( a, b, &tmp ) )
{
if( tmp > safeint_internal::safeint_max<std::int32_t>() ||
tmp < safeint_internal::safeint_min<std::int32_t>() )
{
return false;
}
*pRet = (std::int32_t)tmp;
return true;
}
return false;
#else
bool aNegative = false;
bool bNegative = false;
std::uint32_t tmp = 0;
std::int64_t b1 = b;
if( a < 0 )
{
aNegative = true;
a = (std::int32_t)AbsValueHelper< std::int32_t, GetAbsMethod< std::int32_t >::method >::Abs(a);
}
if( b1 < 0 )
{
bNegative = true;
b1 = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(b1);
}
if( LargeIntRegMultiply< std::uint32_t, std::uint64_t >::RegMultiply( (std::uint32_t)a, (std::uint64_t)b1, &tmp ) )
{
if( aNegative ^ bNegative )
{
if( tmp <= (std::uint32_t)safeint_internal::safeint_min<std::int32_t>() )
{
*pRet = SignedNegation< std::int32_t >::Value( tmp );
return true;
}
}
else
{
if( tmp <= (std::uint32_t)safeint_internal::safeint_max<std::int32_t>() )
{
*pRet = (std::int32_t)tmp;
return true;
}
}
}
return false;
#endif
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void RegMultiplyThrow( std::int32_t a, const std::int64_t& b, std::int32_t* pRet ) SAFEINT_CPP_THROW
{
#if SAFEINT_USE_INTRINSICS || SAFEINT_HAS_INT128
std::int64_t tmp = 0;
if( MultiplyInt64( a, b, &tmp ) )
{
if( tmp > safeint_internal::safeint_max<std::int32_t>() ||
tmp < safeint_internal::safeint_min<std::int32_t>() )
{
E::SafeIntOnOverflow();
}
*pRet = (std::int32_t)tmp;
return;
}
E::SafeIntOnOverflow();
#else
bool aNegative = false;
bool bNegative = false;
std::uint32_t tmp = 0;
std::int64_t b2 = b;
if( a < 0 )
{
aNegative = true;
a = (std::int32_t)AbsValueHelper< std::int32_t, GetAbsMethod< std::int32_t >::method >::Abs(a);
}
if( b < 0 )
{
bNegative = true;
b2 = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(b2);
}
LargeIntRegMultiply< std::uint32_t, std::uint64_t >::template RegMultiplyThrow< E >( (std::uint32_t)a, (std::uint64_t)b2, &tmp );
if( aNegative ^ bNegative )
{
if( tmp <= (std::uint32_t)safeint_internal::safeint_min<std::int32_t>() )
{
*pRet = SignedNegation< std::int32_t >::Value( tmp );
return;
}
}
else
{
if( tmp <= (std::uint32_t)safeint_internal::safeint_max<std::int32_t>() )
{
*pRet = (std::int32_t)tmp;
return;
}
}
E::SafeIntOnOverflow();
#endif
}
};
template<> class LargeIntRegMultiply< std::int64_t, std::uint64_t >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool RegMultiply( const std::int64_t& a, const std::uint64_t& b, std::int64_t* pRet ) SAFEINT_NOTHROW
{
bool aNegative = false;
std::uint64_t tmp = 0;
std::int64_t a1 = a;
if( a1 < 0 )
{
aNegative = true;
a1 = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(a1);
}
if( LargeIntRegMultiply< std::uint64_t, std::uint64_t >::RegMultiply( (std::uint64_t)a1, (std::uint64_t)b, &tmp ) )
{
if( aNegative )
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_min<std::int64_t>() )
{
*pRet = SignedNegation< std::int64_t >::Value( tmp );
return true;
}
}
else
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<std::int64_t>() )
{
*pRet = (std::int64_t)tmp;
return true;
}
}
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void RegMultiplyThrow( const std::int64_t& a, const std::uint64_t& b, std::int64_t* pRet ) SAFEINT_CPP_THROW
{
bool aNegative = false;
std::uint64_t tmp = 0;
std::int64_t a1 = a;
if( a1 < 0 )
{
aNegative = true;
a1 = (std::int64_t)AbsValueHelper< std::int64_t, GetAbsMethod< std::int64_t >::method >::Abs(a1);
}
if( LargeIntRegMultiply< std::uint64_t, std::uint64_t >::RegMultiply( (std::uint64_t)a1, (std::uint64_t)b, &tmp ) )
{
if( aNegative )
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_min<std::int64_t>() )
{
*pRet = SignedNegation< std::int64_t >::Value( tmp );
return;
}
}
else
{
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<std::int64_t>() )
{
*pRet = (std::int64_t)tmp;
return;
}
}
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Uint64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
{
static_assert( safeint_internal::int_traits<T>::isUint64 && safeint_internal::int_traits<U>::isUint64, "T, U must be Uint64" );
std::uint64_t t1 = t;
std::uint64_t u1 = u;
std::uint64_t tmp = 0;
bool f = LargeIntRegMultiply< std::uint64_t, std::uint64_t >::RegMultiply( t1, u1, &tmp );
ret = tmp;
return f;
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void MultiplyThrow(const std::uint64_t& t, const std::uint64_t& u, T& ret) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<T>::isUint64 && safeint_internal::int_traits<U>::isUint64, "T, U must be Uint64");
std::uint64_t t1 = t;
std::uint64_t u1 = u;
std::uint64_t tmp = 0;
LargeIntRegMultiply< std::uint64_t, std::uint64_t >::template RegMultiplyThrow< E >( t1, u1, &tmp );
ret = tmp;
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Uint >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
{
static_assert( safeint_internal::int_traits<T>::isUint64, "T must be Uint64" );
std::uint64_t t1 = t;
std::uint64_t tmp = 0;
bool f = LargeIntRegMultiply< std::uint64_t, std::uint32_t >::RegMultiply( t1, (std::uint32_t)u, &tmp );
ret = tmp;
return f;
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<T>::isUint64, "T must be Uint64");
std::uint64_t t1 = t;
std::uint64_t tmp = 0;
LargeIntRegMultiply< std::uint64_t, std::uint32_t >::template RegMultiplyThrow< E >( t1, (std::uint32_t)u, &tmp );
ret = tmp;
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_UintUint64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW
{
static_assert(safeint_internal::int_traits<U>::isUint64, "U must be Uint64");
std::uint64_t u1 = u;
std::uint32_t tmp = 0;
if( LargeIntRegMultiply< std::uint32_t, std::uint64_t >::RegMultiply( t, u1, &tmp ) &&
SafeCastHelper< T, std::uint32_t, GetCastMethod< T, std::uint32_t >::method >::Cast(tmp, ret) )
{
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<U>::isUint64, "U must be Uint64");
std::uint64_t u1 = u;
std::uint32_t tmp = 0;
LargeIntRegMultiply< std::uint32_t, std::uint64_t >::template RegMultiplyThrow< E >( t, u1, &tmp );
SafeCastHelper< T, std::uint32_t, GetCastMethod< T, std::uint32_t >::method >::template CastThrow< E >(tmp, ret);
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Int >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW
{
static_assert(safeint_internal::int_traits<T>::isUint64, "T must be Uint64");
std::uint64_t t1 = t;
std::uint64_t tmp = 0;
bool f = LargeIntRegMultiply< std::uint64_t, std::int32_t >::RegMultiply(t1, (std::int32_t)u, &tmp);
ret = tmp;
return f;
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<T>::isUint64, "T must be Uint64");
std::uint64_t t1 = t;
std::uint64_t tmp = 0;
LargeIntRegMultiply< std::uint64_t, std::int32_t >::template RegMultiplyThrow< E >(t1, (std::int32_t)u, &tmp);
ret = tmp;
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Int64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW
{
static_assert( safeint_internal::int_traits<T>::isUint64 && safeint_internal::int_traits<U>::isInt64, "T must be Uint64, U Int64" );
std::uint64_t t1 = t;
std::int64_t u1 = u;
std::uint64_t tmp = 0;
bool f = LargeIntRegMultiply< std::uint64_t, std::int64_t >::RegMultiply(t1, u1, &tmp);
ret = tmp;
return f;
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<T>::isUint64 && safeint_internal::int_traits<U>::isInt64, "T must be Uint64, U Int64");
std::uint64_t t1 = t;
std::int64_t u1 = u;
std::uint64_t tmp = 0;
LargeIntRegMultiply< std::uint64_t, std::int64_t >::template RegMultiplyThrow< E >(t1, u1, &tmp);
ret = tmp;
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_UintInt64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW
{
static_assert(safeint_internal::int_traits<U>::isInt64, "U must be Int64");
std::int64_t u1 = u;
std::uint32_t tmp = 0;
if( LargeIntRegMultiply< std::uint32_t, std::int64_t >::RegMultiply( (std::uint32_t)t, u1, &tmp ) &&
SafeCastHelper< T, std::uint32_t, GetCastMethod< T, std::uint32_t >::method >::Cast(tmp, ret) )
{
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<U>::isInt64, "U must be Int64");
std::int64_t u1 = u;
std::uint32_t tmp = 0;
LargeIntRegMultiply< std::uint32_t, std::int64_t >::template RegMultiplyThrow< E >( (std::uint32_t)t, u1, &tmp );
SafeCastHelper< T, std::uint32_t, GetCastMethod< T, std::uint32_t >::method >::template CastThrow< E >(tmp, ret);
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Uint >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
{
static_assert(safeint_internal::int_traits<T>::isInt64, "T must be Int64");
std::int64_t t1 = t;
std::int64_t tmp = 0;
bool f = LargeIntRegMultiply< std::int64_t, std::uint32_t >::RegMultiply( t1, (std::uint32_t)u, &tmp );
ret = tmp;
return f;
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<T>::isInt64, "T must be Int64");
std::int64_t t1 = t;
std::int64_t tmp = 0;
LargeIntRegMultiply< std::int64_t, std::uint32_t >::template RegMultiplyThrow< E >( t1, (std::uint32_t)u, &tmp );
ret = tmp;
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Int64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
{
static_assert( safeint_internal::int_traits<T>::isInt64 && safeint_internal::int_traits<U>::isInt64, "T, U must be Int64" );
std::int64_t t1 = t;
std::int64_t u1 = u;
std::int64_t tmp = 0;
bool f = LargeIntRegMultiply< std::int64_t, std::int64_t >::RegMultiply( t1, u1, &tmp );
ret = tmp;
return f;
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<T>::isInt64 && safeint_internal::int_traits<U>::isInt64, "T, U must be Int64");
std::int64_t t1 = t;
std::int64_t u1 = u;
std::int64_t tmp = 0;
LargeIntRegMultiply< std::int64_t, std::int64_t >::template RegMultiplyThrow< E >( t1, u1, &tmp);
ret = tmp;
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Int >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool Multiply( const T& t, U u, T& ret ) SAFEINT_NOTHROW
{
static_assert(safeint_internal::int_traits<T>::isInt64, "T must be Int64");
std::int64_t t1 = t;
std::int64_t tmp = 0;
bool f = LargeIntRegMultiply< std::int64_t, std::int32_t >::RegMultiply( t1, (std::int32_t)u, &tmp);
ret = tmp;
return f;
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void MultiplyThrow( const std::int64_t& t, U u, T& ret ) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<T>::isInt64, "T must be Int64");
std::int64_t t1 = t;
std::int64_t tmp = 0;
LargeIntRegMultiply< std::int64_t, std::int32_t >::template RegMultiplyThrow< E >(t1, (std::int32_t)u, &tmp);
ret = tmp;
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_IntUint64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Multiply(T t, const U& u, T& ret) SAFEINT_NOTHROW
{
static_assert(safeint_internal::int_traits<U>::isUint64, "U must be Uint64");
std::uint64_t u1 = u;
std::int32_t tmp = 0;
if( LargeIntRegMultiply< std::int32_t, std::uint64_t >::RegMultiply( (std::int32_t)t, u1, &tmp ) &&
SafeCastHelper< T, std::int32_t, GetCastMethod< T, std::int32_t >::method >::Cast( tmp, ret ) )
{
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void MultiplyThrow(T t, const std::uint64_t& u, T& ret) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<U>::isUint64, "U must be Uint64");
std::uint64_t u1 = u;
std::int32_t tmp = 0;
LargeIntRegMultiply< std::int32_t, std::uint64_t >::template RegMultiplyThrow< E >( (std::int32_t)t, u1, &tmp );
SafeCastHelper< T, std::int32_t, GetCastMethod< T, std::int32_t >::method >::template CastThrow< E >( tmp, ret );
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Uint64>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
{
static_assert( safeint_internal::int_traits<T>::isInt64 && safeint_internal::int_traits<U>::isUint64, "T must be Int64, U Uint64" );
std::int64_t t1 = t;
std::uint64_t u1 = u;
std::int64_t tmp = 0;
bool f = LargeIntRegMultiply< std::int64_t, std::uint64_t >::RegMultiply( t1, u1, &tmp );
ret = tmp;
return f;
}
template < typename E >
SAFEINT_CONSTEXPR14_MULTIPLY static void MultiplyThrow( const std::int64_t& t, const std::uint64_t& u, T& ret ) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<T>::isInt64 && safeint_internal::int_traits<U>::isUint64, "T must be Int64, U Uint64");
std::int64_t t1 = t;
std::uint64_t u1 = u;
std::int64_t tmp = 0;
LargeIntRegMultiply< std::int64_t, std::uint64_t >::template RegMultiplyThrow< E >( t1, u1, &tmp );
ret = tmp;
}
};
template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_IntInt64>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Multiply( T t, const U& u, T& ret ) SAFEINT_NOTHROW
{
static_assert( safeint_internal::int_traits<U>::isInt64, "U must be Int64" );
std::int64_t u1 = u;
std::int32_t tmp = 0;
if( LargeIntRegMultiply< std::int32_t, std::int64_t >::RegMultiply( (std::int32_t)t, u1, &tmp ) &&
SafeCastHelper< T, std::int32_t, GetCastMethod< T, std::int32_t >::method >::Cast( tmp, ret ) )
{
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void MultiplyThrow(T t, const U& u, T& ret) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<U>::isInt64, "U must be Int64");
std::int64_t u1 = u;
std::int32_t tmp = 0;
LargeIntRegMultiply< std::int32_t, std::int64_t >::template RegMultiplyThrow< E >( (std::int32_t)t, u1, &tmp );
SafeCastHelper< T, std::int32_t, GetCastMethod< T, std::int32_t >::method >::template CastThrow< E >( tmp, ret );
}
};
enum DivisionState
{
DivisionState_OK,
DivisionState_UnsignedSigned,
DivisionState_SignedUnsigned32,
DivisionState_SignedUnsigned64,
DivisionState_SignedUnsigned,
DivisionState_SignedSigned
};
template < typename T, typename U > class DivisionMethod
{
public:
enum
{
method = (safeint_internal::type_compare< T, U >::isBothUnsigned ? DivisionState_OK :
(!std::numeric_limits< T >::is_signed && std::numeric_limits< U >::is_signed) ? DivisionState_UnsignedSigned :
(std::numeric_limits< T >::is_signed &&
safeint_internal::int_traits< U >::isUint32 &&
safeint_internal::int_traits< T >::isLT64Bit) ? DivisionState_SignedUnsigned32 :
(std::numeric_limits< T >::is_signed && safeint_internal::int_traits< U >::isUint64) ? DivisionState_SignedUnsigned64 :
(std::numeric_limits< T >::is_signed && !std::numeric_limits< U >::is_signed) ? DivisionState_SignedUnsigned :
DivisionState_SignedSigned)
};
};
template < typename T, typename U, int state > class DivisionHelper;
template < typename T, typename U > class DivisionHelper< T, U, DivisionState_OK >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
{
if( u == 0 )
return SafeIntDivideByZero;
if( t == 0 )
{
result = 0;
return SafeIntNoError;
}
result = (T)( t/u );
return SafeIntNoError;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
{
if( u == 0 )
E::SafeIntOnDivZero();
if( t == 0 )
{
result = 0;
return;
}
result = (T)( t/u );
}
};
template < typename T, typename U > class DivisionHelper< T, U, DivisionState_UnsignedSigned>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
{
if( u == 0 )
return SafeIntDivideByZero;
if( t == 0 )
{
result = 0;
return SafeIntNoError;
}
if( u > 0 )
{
result = (T)( t/u );
return SafeIntNoError;
}
if( AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ) > t )
{
result = 0;
return SafeIntNoError;
}
return SafeIntArithmeticOverflow;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
{
if( u == 0 )
E::SafeIntOnDivZero();
if( t == 0 )
{
result = 0;
return;
}
if( u > 0 )
{
result = (T)( t/u );
return;
}
if( AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ) > t )
{
result = 0;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned32 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
{
if( u == 0 )
return SafeIntDivideByZero;
if( t == 0 )
{
result = 0;
return SafeIntNoError;
}
if( t > 0 )
result = (T)( t/u );
else
result = (T)( (std::int64_t)t/(std::int64_t)u );
return SafeIntNoError;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
{
if( u == 0 )
{
E::SafeIntOnDivZero();
}
if( t == 0 )
{
result = 0;
return;
}
if( t > 0 )
result = (T)( t/u );
else
result = (T)( (std::int64_t)t/(std::int64_t)u );
}
};
template < typename T, typename U, bool > class div_signed_uint64;
template < typename T, typename U> class div_signed_uint64 <T, U, true> {
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T divide(T t, U u) { return (T)((std::int32_t)t / (std::int32_t)u); }
};
template < typename T, typename U> class div_signed_uint64 <T, U, false>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T divide(T t, U u) { return (T)((std::int64_t)t / (std::int64_t)u); }
};
template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static SafeIntError Divide( const T& t, const std::uint64_t& u, T& result ) SAFEINT_NOTHROW
{
static_assert(safeint_internal::int_traits<U>::isUint64, "U must be Uint64");
if( u == 0 )
{
return SafeIntDivideByZero;
}
if( t == 0 )
{
result = 0;
return SafeIntNoError;
}
if( u <= (std::uint64_t)safeint_internal::safeint_max<T>() )
{
result = div_signed_uint64 < T, U, sizeof(T) < sizeof(std::int64_t) > ::divide(t, u);
}
else if( t == safeint_internal::safeint_min<T>() && u == (std::uint64_t)safeint_internal::safeint_min<T>() )
{
result = -1;
}
else
{
result = 0;
}
return SafeIntNoError;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void DivideThrow( const T& t, const std::uint64_t& u, T& result ) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits<U>::isUint64, "U must be Uint64");
if( u == 0 )
{
E::SafeIntOnDivZero();
}
if( t == 0 )
{
result = 0;
return;
}
if( u <= (std::uint64_t)safeint_internal::safeint_max<T>() )
{
result = div_signed_uint64 < T, U, sizeof(T) < sizeof(std::int64_t) > ::divide(t, u);
}
else if( t == safeint_internal::safeint_min<T>() && u == (std::uint64_t)safeint_internal::safeint_min<T>() )
{
result = -1;
}
else
{
result = 0;
}
}
};
template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
{
if( u == 0 )
{
return SafeIntDivideByZero;
}
if( t == 0 )
{
result = 0;
return SafeIntNoError;
}
result = (T)( t/u );
return SafeIntNoError;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
{
if( u == 0 )
{
E::SafeIntOnDivZero();
}
if( t == 0 )
{
result = 0;
return;
}
result = (T)( t/u );
}
};
template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedSigned>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
{
if( u == 0 )
{
return SafeIntDivideByZero;
}
if( t == 0 )
{
result = 0;
return SafeIntNoError;
}
if( t == safeint_internal::safeint_min<T>() && u == (U)-1 )
return SafeIntArithmeticOverflow;
result = (T)( t/u );
return SafeIntNoError;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
{
if(u == 0)
{
E::SafeIntOnDivZero();
}
if( t == 0 )
{
result = 0;
return;
}
if( t == safeint_internal::safeint_min<T>() && u == (U)-1 )
E::SafeIntOnOverflow();
result = (T)( t/u );
}
};
enum AdditionState
{
AdditionState_CastIntCheckMax,
AdditionState_CastUintCheckOverflow,
AdditionState_CastUintCheckOverflowMax,
AdditionState_CastUint64CheckOverflow,
AdditionState_CastUint64CheckOverflowMax,
AdditionState_CastIntCheckSafeIntMinMax,
AdditionState_CastInt64CheckSafeIntMinMax,
AdditionState_CastInt64CheckMax,
AdditionState_CastUint64CheckSafeIntMinMax,
AdditionState_CastUint64CheckSafeIntMinMax2,
AdditionState_CastInt64CheckOverflow,
AdditionState_CastInt64CheckOverflowSafeIntMinMax,
AdditionState_CastInt64CheckOverflowMax,
AdditionState_ManualCheckInt64Uint64,
AdditionState_ManualCheck,
AdditionState_Error
};
template< typename T, typename U >
class AdditionMethod
{
public:
enum
{
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 :
(IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? AdditionState_CastIntCheckSafeIntMinMax :
(IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
IntRegion< T,U >::IntZone_UintLT32_Int32) ? AdditionState_CastInt64CheckSafeIntMinMax :
(IntRegion< T,U >::IntZone_Uint64_Int ||
IntRegion< T,U >::IntZone_Uint64_Int64) ? AdditionState_CastUint64CheckSafeIntMinMax :
(IntRegion< T,U >::IntZone_UintLT64_Int64) ? AdditionState_CastUint64CheckSafeIntMinMax2 :
(IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? AdditionState_CastIntCheckSafeIntMinMax :
(IntRegion< T,U >::IntZone_Int32_IntLT64 ||
IntRegion< T,U >::IntZone_IntLT32_Int32) ? AdditionState_CastInt64CheckSafeIntMinMax :
(IntRegion< T,U >::IntZone_Int64_Int ||
IntRegion< T,U >::IntZone_Int64_Int64) ? AdditionState_CastInt64CheckOverflow :
(IntRegion< T,U >::IntZone_IntLT64_Int64) ? AdditionState_CastInt64CheckOverflowSafeIntMinMax :
(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, int method > class AdditionHelper;
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastIntCheckMax >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::int32_t tmp = lhs + rhs;
if( tmp <= (std::int32_t)safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int32_t tmp = lhs + rhs;
if( tmp <= (std::int32_t)safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUintCheckOverflow >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::uint32_t tmp = (std::uint32_t)lhs + (std::uint32_t)rhs;
if( tmp >= lhs )
{
result = (T)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::uint32_t tmp = (std::uint32_t)lhs + (std::uint32_t)rhs;
if( tmp >= lhs )
{
result = (T)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUintCheckOverflowMax>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::uint32_t tmp = (std::uint32_t)lhs + (std::uint32_t)rhs;
if( tmp >= lhs && tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::uint32_t tmp = (std::uint32_t)lhs + (std::uint32_t)rhs;
if( tmp >= lhs && tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckOverflow>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::uint64_t tmp = (std::uint64_t)lhs + (std::uint64_t)rhs;
if(tmp >= lhs)
{
result = (T)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::uint64_t tmp = (std::uint64_t)lhs + (std::uint64_t)rhs;
if(tmp >= lhs)
{
result = (T)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckOverflowMax >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::uint64_t tmp = (std::uint64_t)lhs + (std::uint64_t)rhs;
if( tmp >= lhs && tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::uint64_t tmp = (std::uint64_t)lhs + (std::uint64_t)rhs;
if( tmp >= lhs && tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastIntCheckSafeIntMinMax >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::int32_t tmp = lhs + rhs;
if( tmp <= (std::int32_t)safeint_internal::safeint_max<T>() && tmp >= (std::int32_t)safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int32_t tmp = lhs + rhs;
if( tmp <= (std::int32_t)safeint_internal::safeint_max<T>() && tmp >= (std::int32_t)safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckSafeIntMinMax >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::int64_t tmp = (std::int64_t)lhs + (std::int64_t)rhs;
if( tmp <= (std::int64_t)safeint_internal::safeint_max<T>() && tmp >= (std::int64_t)safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int64_t tmp = (std::int64_t)lhs + (std::int64_t)rhs;
if( tmp <= (std::int64_t)safeint_internal::safeint_max<T>() && tmp >= (std::int64_t)safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckMax >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::int64_t tmp = (std::int64_t)lhs + (std::int64_t)rhs;
if( tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int64_t tmp = (std::int64_t)lhs + (std::int64_t)rhs;
if( tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckSafeIntMinMax >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::uint64_t tmp = 0;
if( rhs < 0 )
{
tmp = AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs );
if( tmp <= lhs )
{
result = lhs - tmp;
return true;
}
}
else
{
tmp = (std::uint64_t)lhs + (std::uint64_t)rhs;
if( tmp >= lhs )
{
result = (T)tmp;
return true;
}
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::uint64_t tmp = 0;
if( rhs < 0 )
{
tmp = AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs );
if( tmp <= lhs )
{
result = lhs - tmp;
return;
}
}
else
{
tmp = (std::uint64_t)lhs + (std::uint64_t)rhs;
if( tmp >= lhs )
{
result = (T)tmp;
return;
}
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckSafeIntMinMax2>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
if( rhs < 0 )
{
if( lhs >= ~(std::uint64_t)( rhs ) + 1 ) {
result = (T)( lhs + rhs );
return true;
}
}
else
{
std::uint64_t tmp = (std::uint64_t)lhs + (std::uint64_t)rhs;
if( tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return true;
}
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
if( rhs < 0 )
{
if( lhs >= ~(std::uint64_t)( rhs ) + 1) {
result = (T)( lhs + rhs );
return;
}
}
else
{
std::uint64_t tmp = (std::uint64_t)lhs + (std::uint64_t)rhs;
if( tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return;
}
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflow>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::int64_t tmp = (std::int64_t)((std::uint64_t)lhs + (std::uint64_t)rhs);
if( lhs >= 0 )
{
if( rhs >= 0 && tmp < lhs )
return false;
}
else
{
if( rhs < 0 && tmp > lhs )
return false;
}
result = (T)tmp;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int64_t tmp = (std::int64_t)((std::uint64_t)lhs + (std::uint64_t)rhs);
if( lhs >= 0 )
{
if( rhs >= 0 && tmp < lhs )
E::SafeIntOnOverflow();
}
else
{
if( rhs < 0 && tmp > lhs )
E::SafeIntOnOverflow();
}
result = (T)tmp;
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflowSafeIntMinMax>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::int64_t tmp = 0;
if( AdditionHelper< std::int64_t, std::int64_t, AdditionState_CastInt64CheckOverflow >::Addition( (std::int64_t)lhs, (std::int64_t)rhs, tmp ) &&
tmp <= safeint_internal::safeint_max<T>() &&
tmp >= safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int64_t tmp = 0;
AdditionHelper< std::int64_t, std::int64_t, AdditionState_CastInt64CheckOverflow >::AdditionThrow< E >( (std::int64_t)lhs, (std::int64_t)rhs, tmp );
if( tmp <= safeint_internal::safeint_max<T>() &&
tmp >= safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflowMax>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::uint64_t tmp = (std::uint64_t)lhs + (std::uint64_t)rhs;
if( (std::int64_t)tmp >= lhs )
{
result = (T)(std::int64_t)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::uint64_t tmp = (std::uint64_t)lhs + (std::uint64_t)rhs;
if( (std::int64_t)tmp >= lhs )
{
result = (T)(std::int64_t)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_ManualCheckInt64Uint64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const std::int64_t& lhs, const std::uint64_t& rhs, T& result ) SAFEINT_NOTHROW
{
static_assert( safeint_internal::int_traits< T >::isInt64 && safeint_internal::int_traits< U >::isUint64, "T must be Int64, U Uint64" );
std::uint64_t tmp = (std::uint64_t)lhs + rhs;
if( (std::int64_t)tmp >= lhs )
{
result = (std::int64_t)tmp;
return true;
}
result = 0;
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const std::int64_t& lhs, const std::uint64_t& rhs, T& result ) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits< T >::isInt64 && safeint_internal::int_traits< U >::isUint64, "T must be Int64, U Uint64");
std::uint64_t tmp = (std::uint64_t)lhs + rhs;
if( (std::int64_t)tmp >= lhs )
{
result = (std::int64_t)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class AdditionHelper < T, U, AdditionState_ManualCheck>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
if( (std::uint32_t)( rhs >> 32 ) == 0 )
{
std::uint32_t tmp = (std::uint32_t)rhs + (std::uint32_t)lhs;
if( (std::int32_t)tmp >= lhs && SafeCastHelper< T, std::int32_t, GetCastMethod< T, std::int32_t >::method >::Cast( (std::int32_t)tmp, result ) )
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
if( (std::uint32_t)( rhs >> 32 ) == 0 )
{
std::uint32_t tmp = (std::uint32_t)rhs + (std::uint32_t)lhs;
if( (std::int32_t)tmp >= lhs )
{
SafeCastHelper< T, std::int32_t, GetCastMethod< T, std::int32_t >::method >::template CastThrow< E >( (std::int32_t)tmp, result );
return;
}
}
E::SafeIntOnOverflow();
}
};
enum SubtractionState
{
SubtractionState_BothUnsigned,
SubtractionState_CastIntCheckSafeIntMinMax,
SubtractionState_CastIntCheckMin,
SubtractionState_CastInt64CheckSafeIntMinMax,
SubtractionState_CastInt64CheckMin,
SubtractionState_Uint64Int,
SubtractionState_UintInt64,
SubtractionState_Int64Int,
SubtractionState_IntInt64,
SubtractionState_Int64Uint,
SubtractionState_IntUint64,
SubtractionState_Int64Uint64,
SubtractionState_BothUnsigned2,
SubtractionState_CastIntCheckSafeIntMinMax2,
SubtractionState_CastInt64CheckSafeIntMinMax2,
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
{
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 :
(IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax :
(IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax :
(IntRegion< T,U >::IntZone_Uint64_Int ||
IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int :
(IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt64 :
(IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax :
(IntRegion< T,U >::IntZone_Int32_IntLT64 ||
IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax :
(IntRegion< T,U >::IntZone_Int64_Int ||
IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int :
(IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt64 :
(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)
};
};
template < typename T, typename U > class SubtractionMethod2
{
public:
enum
{
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 :
(IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 :
(IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 :
(IntRegion< T,U >::IntZone_Uint64_Int ||
IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int2 :
(IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt642 :
(IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 :
(IntRegion< T,U >::IntZone_Int32_IntLT64 ||
IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 :
(IntRegion< T,U >::IntZone_Int64_Int ||
IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int2 :
(IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt642 :
(IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 :
(IntRegion< T,U >::IntZone_Int32_UintLT32 ||
IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 :
(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, int method > class SubtractionHelper;
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_BothUnsigned >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
if( rhs <= lhs )
{
result = (T)( lhs - rhs );
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
if( rhs <= lhs )
{
result = (T)( lhs - rhs );
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_BothUnsigned2 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const T& lhs, const U& rhs, U& result ) SAFEINT_NOTHROW
{
if( rhs <= lhs )
{
T tmp = (T)(lhs - rhs);
return SafeCastHelper< U, T, GetCastMethod<U, T>::method>::Cast( tmp, result);
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const T& lhs, const U& rhs, U& result ) SAFEINT_CPP_THROW
{
if( rhs <= lhs )
{
T tmp = (T)(lhs - rhs);
SafeCastHelper< U, T, GetCastMethod<U, T>::method >::template CastThrow<E>( tmp, result);
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastIntCheckSafeIntMinMax >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::int32_t tmp = lhs - rhs;
if( SafeCastHelper< T, std::int32_t, GetCastMethod< T, std::int32_t >::method >::Cast( tmp, result ) )
{
result = (T)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int32_t tmp = lhs - rhs;
SafeCastHelper< T, std::int32_t, GetCastMethod< T, std::int32_t >::method >::template CastThrow< E >( tmp, result );
}
};
template <typename U, typename T> class SubtractionHelper< U, T, SubtractionState_CastIntCheckSafeIntMinMax2 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
{
std::int32_t tmp = lhs - rhs;
return SafeCastHelper< T, std::int32_t, GetCastMethod< T, std::int32_t >::method >::Cast( tmp, result );
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int32_t tmp = lhs - rhs;
SafeCastHelper< T, std::int32_t, GetCastMethod< T, std::int32_t >::method >::template CastThrow< E >( tmp, result );
}
};
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastIntCheckMin >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::int32_t tmp = lhs - rhs;
if( tmp >= (std::int32_t)safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int32_t tmp = lhs - rhs;
if( tmp >= (std::int32_t)safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastInt64CheckSafeIntMinMax >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::int64_t tmp = (std::int64_t)lhs - (std::int64_t)rhs;
return SafeCastHelper< T, std::int64_t, GetCastMethod< T, std::int64_t >::method >::Cast( tmp, result );
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int64_t tmp = (std::int64_t)lhs - (std::int64_t)rhs;
SafeCastHelper< T, std::int64_t, GetCastMethod< T, std::int64_t >::method >::template CastThrow< E >( tmp, result );
}
};
template <typename U, typename T> class SubtractionHelper< U, T, SubtractionState_CastInt64CheckSafeIntMinMax2 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
{
std::int64_t tmp = (std::int64_t)lhs - (std::int64_t)rhs;
return SafeCastHelper< T, std::int64_t, GetCastMethod< T, std::int64_t >::method >::Cast( tmp, result );
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int64_t tmp = (std::int64_t)lhs - (std::int64_t)rhs;
SafeCastHelper< T, std::int64_t, GetCastMethod< T, std::int64_t >::method >::template CastThrow< E >( tmp, result );
}
};
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastInt64CheckMin >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::int64_t tmp = (std::int64_t)lhs - (std::int64_t)rhs;
if( tmp >= (std::int64_t)safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int64_t tmp = (std::int64_t)lhs - (std::int64_t)rhs;
if( tmp >= (std::int64_t)safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Uint64Int >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
if( rhs >= 0 )
{
if( (std::uint64_t)rhs <= lhs )
{
result = (T)( lhs - (std::uint64_t)rhs );
return true;
}
}
else
{
T tmp = lhs;
result = lhs + AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs );
if(result >= tmp)
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
if( rhs >= 0 )
{
if( (std::uint64_t)rhs <= lhs )
{
result = (T)( lhs - (std::uint64_t)rhs );
return;
}
}
else
{
T tmp = lhs;
result = lhs + AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs );
if(result >= tmp)
return;
}
E::SafeIntOnOverflow();
}
};
template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Uint64Int2 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
{
if( rhs < 0 )
{
std::uint64_t tmp = 0;
tmp = lhs + (std::uint64_t)AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( rhs );
if( tmp >= lhs && tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return true;
}
}
else if( (std::uint64_t)rhs > lhs ) {
result = (T)lhs - (T)rhs;
return true;
}
else
{
std::uint64_t tmp = (std::uint64_t)lhs - (std::uint64_t)rhs;
if( tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return true;
}
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
{
if( rhs < 0 )
{
std::uint64_t tmp = 0;
tmp = lhs + (std::uint64_t)AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( rhs );
if( tmp >= lhs && tmp <= (std::uint64_t)safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return;
}
}
else if( (std::uint64_t)rhs > lhs ) {
result = (T)lhs - (T)rhs;
return;
}
else
{
std::uint64_t tmp = (std::uint64_t)lhs - (std::uint64_t)rhs;
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return;
}
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_UintInt64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
if( rhs >= 0 )
{
if( (std::uint64_t)rhs <= lhs )
{
result = (T)( lhs - (T)rhs );
return true;
}
}
else
{
std::uint64_t tmp = lhs + ~(std::uint64_t)( rhs ) + 1;
if(tmp <= safeint_internal::safeint_max<T>())
{
result = (T)tmp;
return true;
}
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
if( rhs >= 0 )
{
if( (std::uint64_t)rhs <= lhs )
{
result = (T)( lhs - (T)rhs );
return;
}
}
else
{
std::uint64_t tmp = lhs + ~(std::uint64_t)( rhs ) + 1;
if(tmp <= safeint_internal::safeint_max<T>())
{
result = (T)tmp;
return;
}
}
E::SafeIntOnOverflow();
}
};
template <typename U, typename T> class SubtractionHelper< U, T, SubtractionState_UintInt642 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
{
if( rhs >= 0 )
{
result = (T)( (std::int64_t)lhs - rhs );
return true;
}
else
{
std::uint64_t tmp = (std::uint64_t)lhs + (std::uint64_t)( -rhs );
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return true;
}
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
{
if( rhs >= 0 )
{
result = (T)( (std::int64_t)lhs - rhs );
return;
}
else
{
std::uint64_t tmp = (std::uint64_t)lhs + (std::uint64_t)( -rhs );
if( tmp <= (std::uint64_t)safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return;
}
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Int >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::int64_t tmp = (std::int64_t)((std::uint64_t)lhs - (std::uint64_t)rhs);
if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || ( rhs >= 0 && tmp > lhs ) ) {
return false;
}
result = (T)tmp;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int64_t tmp = (std::int64_t)((std::uint64_t)lhs - (std::uint64_t)rhs);
if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || ( rhs >= 0 && tmp > lhs ) ) {
E::SafeIntOnOverflow();
}
result = (T)tmp;
}
};
template < typename T, typename U, bool > class subtract_corner_case_max;
template < typename T, typename U> class subtract_corner_case_max < T, U, true>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool isOverflowPositive(const T& rhs, const U& lhs, std::int64_t tmp)
{
return (tmp > safeint_internal::safeint_max<T>() || (rhs < 0 && tmp < lhs));
}
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool isOverflowNegative(const T& rhs, const U& lhs, std::int64_t tmp)
{
return (tmp < safeint_internal::safeint_min<T>() || (rhs >= 0 && tmp > lhs));
}
};
template < typename T, typename U> class subtract_corner_case_max < T, U, false>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool isOverflowPositive(const T& rhs, const U& lhs, std::int64_t tmp)
{
return (rhs < 0 && tmp < lhs);
}
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool isOverflowNegative(const T& rhs, const U& lhs, std::int64_t tmp)
{
return (rhs >= 0 && tmp > lhs);
}
};
template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Int2 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
{
std::int64_t tmp = (std::int64_t)((std::uint64_t)lhs - (std::uint64_t)rhs);
if( lhs >= 0 )
{
if(subtract_corner_case_max< T, U, safeint_internal::int_traits< T >::isLT64Bit >::isOverflowPositive(rhs, lhs, tmp))
{
return false;
}
}
else
{
if(subtract_corner_case_max< T, U, safeint_internal::int_traits< T >::isLT64Bit >::isOverflowNegative(rhs, lhs, tmp))
{
return false;
}
}
result = (T)tmp;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int64_t tmp = (std::int64_t)((std::uint64_t)lhs - (std::uint64_t)rhs);
if( lhs >= 0 )
{
if (subtract_corner_case_max< T, U, safeint_internal::int_traits< T >::isLT64Bit>::isOverflowPositive(rhs, lhs, tmp))
{
E::SafeIntOnOverflow();
}
}
else
{
if (subtract_corner_case_max< T, U, safeint_internal::int_traits< T >::isLT64Bit >::isOverflowNegative(rhs, lhs, tmp))
{
E::SafeIntOnOverflow();
}
}
result = (T)tmp;
}
};
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_IntInt64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::int64_t tmp = (std::int64_t)((std::uint64_t)lhs - (std::uint64_t)rhs);
if( lhs >= 0 )
{
if( rhs >= 0 )
{
if( tmp >= safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return true;
}
}
else
{
if( tmp >= lhs && tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return true;
}
}
}
else
{
if( rhs >= 0 )
{
if( tmp <= lhs && tmp >= safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return true;
}
}
else
{
if( tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return true;
}
}
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int64_t tmp = (std::int64_t)((std::uint64_t)lhs - (std::uint64_t)rhs);
if( lhs >= 0 )
{
if( rhs >= 0 )
{
if( tmp >= safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return;
}
}
else
{
if( tmp >= lhs && tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return;
}
}
}
else
{
if( rhs >= 0 )
{
if( tmp <= lhs && tmp >= safeint_internal::safeint_min<T>() )
{
result = (T)tmp;
return;
}
}
else
{
if( tmp <= safeint_internal::safeint_max<T>() )
{
result = (T)tmp;
return;
}
}
}
E::SafeIntOnOverflow();
}
};
template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_IntInt642 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
{
std::int64_t tmp = (std::int64_t)((std::uint64_t)lhs - (std::uint64_t)rhs);
if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) ||
( rhs > 0 && tmp > lhs ) )
{
return false;
}
result = (T)tmp;
return true;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
{
std::int64_t tmp = (std::int64_t)((std::uint64_t)lhs - (std::uint64_t)rhs);
if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) ||
( rhs > 0 && tmp > lhs ) )
{
E::SafeIntOnOverflow();
}
result = (T)tmp;
}
};
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Uint >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
std::uint64_t tmp = (std::uint64_t)lhs - (std::uint64_t)rhs;
if( (std::int64_t)tmp <= lhs )
{
result = (T)(std::int64_t)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
std::uint64_t tmp = (std::uint64_t)lhs - (std::uint64_t)rhs;
if( (std::int64_t)tmp <= lhs )
{
result = (T)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Uint2 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
{
std::uint64_t tmp = (std::uint64_t)lhs - (std::uint64_t)rhs;
if( (std::int64_t)tmp <= safeint_internal::safeint_max<T>() && (std::int64_t)tmp >= safeint_internal::safeint_min<T>() )
{
result = (T)(std::int64_t)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
{
std::uint64_t tmp = (std::uint64_t)lhs - (std::uint64_t)rhs;
if( (std::int64_t)tmp <= safeint_internal::safeint_max<T>() && (std::int64_t)tmp >= safeint_internal::safeint_min<T>() )
{
result = (T)(std::int64_t)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_IntUint64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
{
const std::uint64_t AbsMinIntT = (std::uint64_t)safeint_internal::safeint_max<T>() + 1;
if( lhs < 0 )
{
if( rhs <= AbsMinIntT - AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( lhs ) )
{
result = (T)( lhs - rhs );
return true;
}
}
else
{
if( rhs <= AbsMinIntT + (std::uint64_t)lhs )
{
result = (T)( lhs - rhs );
return true;
}
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
{
SAFEINT_CONSTEXPR11 std::uint64_t AbsMinIntT = (std::uint64_t)safeint_internal::safeint_max<T>() + 1;
if( lhs < 0 )
{
if( rhs <= AbsMinIntT - AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( lhs ) )
{
result = (T)( lhs - rhs );
return;
}
}
else
{
if( rhs <= AbsMinIntT + (std::uint64_t)lhs )
{
result = (T)( lhs - rhs );
return;
}
}
E::SafeIntOnOverflow();
}
};
template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_IntUint642 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
{
if( lhs >= 0 && (T)lhs >= rhs )
{
result = (T)((U)lhs - (U)rhs);
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
{
if( lhs >= 0 && (T)lhs >= rhs )
{
result = (T)((U)lhs - (U)rhs);
return;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Uint64 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const std::int64_t& lhs, const std::uint64_t& rhs, std::int64_t& result ) SAFEINT_NOTHROW
{
static_assert(safeint_internal::int_traits< T >::isInt64 && safeint_internal::int_traits< U >::isUint64, "T must be Int64, U Uint64");
std::uint64_t tmp = (std::uint64_t)lhs - rhs;
if( (std::int64_t)tmp <= lhs )
{
result = (std::int64_t)tmp;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const std::int64_t& lhs, const std::uint64_t& rhs, T& result ) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits< T >::isInt64 && safeint_internal::int_traits< U >::isUint64, "T must be Int64, U Uint64");
std::uint64_t tmp = (std::uint64_t)lhs - rhs;
if( (std::int64_t)tmp <= lhs )
{
result = (std::int64_t)tmp;
return;
}
E::SafeIntOnOverflow();
}
};
template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Uint642 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Subtract( const std::int64_t& lhs, const std::uint64_t& rhs, T& result ) SAFEINT_NOTHROW
{
static_assert( safeint_internal::int_traits< T >::isUint64 && safeint_internal::int_traits< U >::isInt64, "T must be Uint64, U Int64" );
if( lhs >= 0 && (std::uint64_t)lhs >= rhs )
{
result = (std::uint64_t)lhs - rhs;
return true;
}
return false;
}
template < typename E >
SAFEINT_CONSTEXPR14 static void SubtractThrow( const std::int64_t& lhs, const std::uint64_t& rhs, T& result ) SAFEINT_CPP_THROW
{
static_assert(safeint_internal::int_traits< T >::isUint64 && safeint_internal::int_traits< U >::isInt64, "T must be Uint64, U Int64");
if( lhs >= 0 && (std::uint64_t)lhs >= rhs )
{
result = (std::uint64_t)lhs - rhs;
return;
}
E::SafeIntOnOverflow();
}
};
enum BinaryState
{
BinaryState_OK,
BinaryState_Int8,
BinaryState_Int16,
BinaryState_Int32
};
template < typename T, typename U > class BinaryMethod
{
public:
enum
{
method = ( sizeof( T ) <= sizeof( U ) ||
safeint_internal::type_compare< T, U >::isBothUnsigned ||
!std::numeric_limits< U >::is_signed ) ? BinaryState_OK :
safeint_internal::int_traits< U >::isInt8 ? BinaryState_Int8 :
safeint_internal::int_traits< U >::isInt16 ? BinaryState_Int16
: BinaryState_Int32
};
};
#ifdef SAFEINT_DISABLE_BINARY_ASSERT
#define BinaryAssert(x)
#else
#define BinaryAssert(x) SAFEINT_ASSERT(x)
#endif
template < typename T, typename U, int method > class BinaryAndHelper;
template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_OK >
{
public:
SAFEINT_CONSTEXPR11 static T And( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs & rhs ); }
};
template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int8 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T And( T lhs, U rhs ) SAFEINT_NOTHROW
{
BinaryAssert( ( lhs & rhs ) == ( lhs & (std::uint8_t)rhs ) );
return (T)( lhs & (std::uint8_t)rhs );
}
};
template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int16 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T And( T lhs, U rhs ) SAFEINT_NOTHROW
{
BinaryAssert( ( lhs & rhs ) == ( lhs & (std::uint16_t)rhs ) );
return (T)( lhs & (std::uint16_t)rhs );
}
};
template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int32 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T And( T lhs, U rhs ) SAFEINT_NOTHROW
{
BinaryAssert( ( lhs & rhs ) == ( lhs & (std::uint32_t)rhs ) );
return (T)( lhs & (std::uint32_t)rhs );
}
};
template < typename T, typename U, int method > class BinaryOrHelper;
template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_OK >
{
public:
SAFEINT_CONSTEXPR11 static T Or( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs | rhs ); }
};
template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int8 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T Or( T lhs, U rhs ) SAFEINT_NOTHROW
{
BinaryAssert( ( lhs | rhs ) == ( lhs | (std::uint8_t)rhs ) );
return (T)( lhs | (std::uint8_t)rhs );
}
};
template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int16 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T Or( T lhs, U rhs ) SAFEINT_NOTHROW
{
BinaryAssert( ( lhs | rhs ) == ( lhs | (std::uint16_t)rhs ) );
return (T)( lhs | (std::uint16_t)rhs );
}
};
template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int32 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T Or( T lhs, U rhs ) SAFEINT_NOTHROW
{
BinaryAssert( ( lhs | rhs ) == ( lhs | (std::uint32_t)rhs ) );
return (T)( lhs | (std::uint32_t)rhs );
}
};
template <typename T, typename U, int method > class BinaryXorHelper;
template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_OK >
{
public:
SAFEINT_CONSTEXPR11 static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs ^ rhs ); }
};
template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int8 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW
{
BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (std::uint8_t)rhs ) );
return (T)( lhs ^ (std::uint8_t)rhs );
}
};
template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int16 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW
{
BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (std::uint16_t)rhs ) );
return (T)( lhs ^ (std::uint16_t)rhs );
}
};
template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int32 >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW
{
BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (std::uint32_t)rhs ) );
return (T)( lhs ^ (std::uint32_t)rhs );
}
};
template < typename U, int signed > class bits_not_negative;
template < typename U > class bits_not_negative < U, true >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool value(U bits)
{
return bits >= 0;
}
};
template < typename U > class bits_not_negative < U, false >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool value(U)
{
return true;
}
};
template < typename T, int is_signed > class lhs_is_negative;
template < typename T > class lhs_is_negative < T, true >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool value(T lhs)
{
return lhs < 0;
}
};
template < typename T > class lhs_is_negative < T, false >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool value(T)
{
return false;
}
};
template < typename T, int is_signed > class align_addmask;
template < typename T > class align_addmask < T, true >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T value( T lhs, T align_value )
{
typedef typename std::make_unsigned< T >::type UT;
return (T)( ( (UT)lhs + (UT)align_value ) & ~(UT)align_value );
}
};
template < typename T > class align_addmask < T, false >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static T value( T lhs, T align_value )
{
return (T)( ( lhs + align_value ) & ~align_value );
}
};
enum ShiftState
{
ShiftState_RightShift,
ShiftState_LeftShiftUnsigned,
ShiftState_LeftShiftSigned
};
template < typename T, bool IsLeftShift > class ShiftMethod
{
public:
enum
{
method = !IsLeftShift ? ShiftState_RightShift :
std::numeric_limits< T >::is_signed ? ShiftState_LeftShiftSigned
: ShiftState_LeftShiftUnsigned,
isSignedLeftShift = (method == (int)ShiftState_LeftShiftSigned)
};
};
template < typename T, typename U, bool isSignedLeftShift > class ShiftHelper;
template < typename T, typename U > class ShiftHelper< T, U, false >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool ValidBitcount(T , U bits) SAFEINT_NOTHROW
{
if (bits_not_negative<U, std::numeric_limits< U >::is_signed>::value(bits))
{
if (bits < (int)safeint_internal::int_traits< T >::bitCount)
{
return true;
}
}
return false;
}
};
template < typename T, typename U > class ShiftHelper< T, U, true >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool ValidBitcount(T lhs, U bits) SAFEINT_NOTHROW
{
if (!bits_not_negative<U, std::numeric_limits< U >::is_signed>::value(bits))
return false;
if (bits >= (int)safeint_internal::int_traits< T >::bitCount - 1)
return false;
typedef typename std::make_unsigned< T >::type UT;
return (UT)lhs <= (UT)(safeint_internal::safeint_max< T >() >> bits);
}
};
template < typename T, typename U >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline bool SafeCast( const T From, U& To ) SAFEINT_NOTHROW
{
static_assert(!std::is_enum<U>::value,
"SafeCast destination type must not be an enum. std::numeric_limits "
"is unspecialized for enums and the range check would be incorrect. "
"Cast to the underlying type instead.");
return SafeCastHelper< U, T, GetCastMethod< U, T >::method >::Cast( From, To );
}
template < typename T, typename U >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline bool SafeEquals( const T t, const U u ) SAFEINT_NOTHROW
{
return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( t, u );
}
template < typename T, typename U >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline bool SafeNotEquals( const T t, const U u ) SAFEINT_NOTHROW
{
return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( t, u );
}
template < typename T, typename U >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline bool SafeGreaterThan( const T t, const U u ) SAFEINT_NOTHROW
{
return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( t, u );
}
template < typename T, typename U >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline bool SafeGreaterThanEquals( const T t, const U u ) SAFEINT_NOTHROW
{
return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( u, t );
}
template < typename T, typename U >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline bool SafeLessThan( const T t, const U u ) SAFEINT_NOTHROW
{
return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( u, t );
}
template < typename T, typename U >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline bool SafeLessThanEquals( const T t, const U u ) SAFEINT_NOTHROW
{
return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( t, u );
}
template < typename T, typename U >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline bool SafeModulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
{
return ( ModulusHelper< T, U, ValidComparison< T, U >::method >::Modulus( t, u, result ) == SafeIntNoError );
}
template < typename T, typename U >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14_MULTIPLY inline bool SafeMultiply( T t, U u, T& result ) SAFEINT_NOTHROW
{
return MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::Multiply( t, u, result );
}
template < typename T, typename U >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline bool SafeDivide( T t, U u, T& result ) SAFEINT_NOTHROW
{
return ( DivisionHelper< T, U, DivisionMethod< T, U >::method >::Divide( t, u, result ) == SafeIntNoError );
}
template < typename T, typename U >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline bool SafeAdd( T t, U u, T& result ) SAFEINT_NOTHROW
{
return AdditionHelper< T, U, AdditionMethod< T, U >::method >::Addition( t, u, result );
}
template < typename T, typename U >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline bool SafeSubtract( T t, U u, T& result ) SAFEINT_NOTHROW
{
return SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::Subtract( t, u, result );
}
template < typename T >
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 inline bool SafeNegation(T t, T& result) SAFEINT_NOTHROW
{
return NegationHelper< T, std::numeric_limits<T>::is_signed>::Negative(t, result);
}
template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeInt
{
public:
SAFEINT_CONSTEXPR11 SafeInt() SAFEINT_NOTHROW : m_int(0)
{
static_assert( safeint_internal::numeric_type< T >::isInt, "Integer type required" );
}
SAFEINT_CONSTEXPR11 SafeInt( const T& i ) SAFEINT_NOTHROW : m_int(i)
{
static_assert(safeint_internal::numeric_type< T >::isInt, "Integer type required");
}
SAFEINT_CONSTEXPR11 SafeInt( bool b ) SAFEINT_NOTHROW : m_int((T)(b ? 1 : 0))
{
static_assert(safeint_internal::numeric_type< T >::isInt, "Integer type required");
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt(const SafeInt< U, E >& u) SAFEINT_CPP_THROW : m_int(0)
{
static_assert(safeint_internal::numeric_type< T >::isInt, "Integer type required");
m_int = (T)SafeInt< T, E >( (U)u );
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt( const U& i ) SAFEINT_CPP_THROW : m_int(0)
{
static_assert(safeint_internal::numeric_type< T >::isInt, "Integer type required");
SafeCastHelper< T, U, GetCastMethod< T, U >::method >::template CastThrow< E >( i, m_int );
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator =( const U& rhs ) SAFEINT_CPP_THROW
{
m_int = SafeInt< T, E >( rhs );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator =( const SafeInt< U, E >& rhs ) SAFEINT_CPP_THROW
{
SafeCastHelper< T, U, GetCastMethod< T, U >::method >::template CastThrow< E >( rhs.Ref(), m_int );
return *this;
}
SAFEINT_CONSTEXPR11 operator bool() const SAFEINT_NOTHROW
{
return !!m_int;
}
SAFEINT_CONSTEXPR14 operator char() const SAFEINT_CPP_THROW
{
char val = 0;
SafeCastHelper< char, T, GetCastMethod< char, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator signed char() const SAFEINT_CPP_THROW
{
signed char val = 0;
SafeCastHelper< signed char, T, GetCastMethod< signed char, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator unsigned char() const SAFEINT_CPP_THROW
{
unsigned char val = 0;
SafeCastHelper< unsigned char, T, GetCastMethod< unsigned char, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator short() const SAFEINT_CPP_THROW
{
short val = 0;
SafeCastHelper< short, T, GetCastMethod< short, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator unsigned short() const SAFEINT_CPP_THROW
{
unsigned short val = 0;
SafeCastHelper< unsigned short, T, GetCastMethod< unsigned short, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator int() const SAFEINT_CPP_THROW
{
int val = 0;
SafeCastHelper< int, T, GetCastMethod< int, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator unsigned int() const SAFEINT_CPP_THROW
{
unsigned int val = 0;
SafeCastHelper< unsigned int, T, GetCastMethod< unsigned int, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator long() const SAFEINT_CPP_THROW
{
long val = 0;
SafeCastHelper< long, T, GetCastMethod< long, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator unsigned long() const SAFEINT_CPP_THROW
{
unsigned long val = 0;
SafeCastHelper< unsigned long, T, GetCastMethod< unsigned long, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator long long() const SAFEINT_CPP_THROW
{
long long val = 0;
SafeCastHelper< long long, T, GetCastMethod< long long, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator unsigned long long() const SAFEINT_CPP_THROW
{
unsigned long long val = 0;
SafeCastHelper< unsigned long long, T, GetCastMethod< unsigned long long, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator wchar_t() const SAFEINT_CPP_THROW
{
wchar_t val = 0;
SafeCastHelper< wchar_t, T, GetCastMethod< wchar_t, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
#ifdef SIZE_T_CAST_NEEDED
SAFEINT_CONSTEXPR14 operator size_t() const SAFEINT_CPP_THROW
{
size_t val = 0;
SafeCastHelper< size_t, T, GetCastMethod< size_t, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
#endif
SAFEINT_CONSTEXPR14 operator float() const SAFEINT_CPP_THROW
{
float val = 0.0;
SafeCastHelper< float, T, GetCastMethod< float, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator double() const SAFEINT_CPP_THROW
{
double val = 0.0;
SafeCastHelper< double, T, GetCastMethod< double, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
SAFEINT_CONSTEXPR14 operator long double() const SAFEINT_CPP_THROW
{
long double val = static_cast<long double>(0.0);
SafeCastHelper< long double, T, GetCastMethod< long double, T >::method >::template CastThrow< E >( m_int, val );
return val;
}
T* Ptr() SAFEINT_NOTHROW { return &m_int; }
const T* Ptr() const SAFEINT_NOTHROW { return &m_int; }
T* data_ptr() SAFEINT_NOTHROW { return &m_int; }
const T* data_ptr() const SAFEINT_NOTHROW { return &m_int; }
SAFEINT_CONSTEXPR14 const T& Ref() const SAFEINT_NOTHROW { return m_int; }
#if !defined SAFEINT_DISABLE_ADDRESS_OPERATOR
T* operator &() SAFEINT_NOTHROW { return &m_int; }
const T* operator &() const SAFEINT_NOTHROW { return &m_int; }
#endif
SAFEINT_CONSTEXPR11 bool operator !() const SAFEINT_NOTHROW { return (!m_int) ? true : false; }
SAFEINT_CONSTEXPR11 const SafeInt< T, E >& operator +() const SAFEINT_NOTHROW { return *this; }
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator -() const SAFEINT_CPP_THROW
{
return SafeInt<T, E>(NegationHelper<T, std::numeric_limits< T >::is_signed>::template NegativeThrow<E>(m_int));
}
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator ++() SAFEINT_CPP_THROW
{
if( m_int != safeint_internal::safeint_max<T>() )
{
++m_int;
return *this;
}
E::SafeIntOnOverflow();
}
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator --() SAFEINT_CPP_THROW
{
if( m_int != safeint_internal::safeint_min<T>() )
{
--m_int;
return *this;
}
E::SafeIntOnOverflow();
}
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator ++( int ) SAFEINT_CPP_THROW {
if( m_int != safeint_internal::safeint_max<T>() )
{
SafeInt< T, E > tmp( m_int );
m_int++;
return tmp;
}
E::SafeIntOnOverflow();
}
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator --( int ) SAFEINT_CPP_THROW {
if( m_int != safeint_internal::safeint_min<T>() )
{
SafeInt< T, E > tmp( m_int );
m_int--;
return tmp;
}
E::SafeIntOnOverflow();
}
SAFEINT_CONSTEXPR11 SafeInt< T, E > operator ~() const SAFEINT_NOTHROW { return SafeInt< T, E >( (T)~m_int ); }
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator %( U rhs ) const SAFEINT_CPP_THROW
{
T result = 0;
ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, rhs, result );
return SafeInt< T, E >( result );
}
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator %( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW
{
T result = 0;
ModulusHelper< T, T, ValidComparison< T, T >::method >::template ModulusThrow< E >( m_int, rhs, result );
return SafeInt< T, E >( result );
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator %=( U rhs ) SAFEINT_CPP_THROW
{
ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, rhs, m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator %=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, (U)rhs, m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14_MULTIPLY SafeInt< T, E > operator *( U rhs ) const SAFEINT_CPP_THROW
{
T ret( 0 );
MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs, ret );
return SafeInt< T, E >( ret );
}
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator *( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW
{
T ret( 0 );
MultiplicationHelper< T, T, MultiplicationMethod< T, T >::method >::template MultiplyThrow< E >( m_int, (T)rhs, ret );
return SafeInt< T, E >( ret );
}
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator *=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
{
MultiplicationHelper< T, T, MultiplicationMethod< T, T >::method >::template MultiplyThrow< E >( m_int, (T)rhs, m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14_MULTIPLY SafeInt< T, E >& operator *=( U rhs ) SAFEINT_CPP_THROW
{
MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs, m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14_MULTIPLY SafeInt< T, E >& operator *=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs.Ref(), m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator /( U rhs ) const SAFEINT_CPP_THROW
{
T ret( 0 );
DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, rhs, ret );
return SafeInt< T, E >( ret );
}
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator /( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW
{
T ret( 0 );
DivisionHelper< T, T, DivisionMethod< T, T >::method >::template DivideThrow< E >( m_int, (T)rhs, ret );
return SafeInt< T, E >( ret );
}
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator /=( SafeInt< T, E > i ) SAFEINT_CPP_THROW
{
DivisionHelper< T, T, DivisionMethod< T, T >::method >::template DivideThrow< E >( m_int, (T)i, m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator /=( U i ) SAFEINT_CPP_THROW
{
DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, i, m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator /=( SafeInt< U, E > i )
{
DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, (U)i, m_int );
return *this;
}
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator +( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW
{
T ret( 0 );
AdditionHelper< T, T, AdditionMethod< T, T >::method >::template AdditionThrow< E >( m_int, (T)rhs, ret );
return SafeInt< T, E >( ret );
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator +( U rhs ) const SAFEINT_CPP_THROW
{
T ret( 0 );
AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, rhs, ret );
return SafeInt< T, E >( ret );
}
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator +=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
{
AdditionHelper< T, T, AdditionMethod< T, T >::method >::template AdditionThrow< E >( m_int, (T)rhs, m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator +=( U rhs ) SAFEINT_CPP_THROW
{
AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, rhs, m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator +=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, (U)rhs, m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator -( U rhs ) const SAFEINT_CPP_THROW
{
T ret( 0 );
SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, rhs, ret );
return SafeInt< T, E >( ret );
}
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator -(SafeInt< T, E > rhs) const SAFEINT_CPP_THROW
{
T ret( 0 );
SubtractionHelper< T, T, SubtractionMethod< T, T >::method >::template SubtractThrow< E >( m_int, (T)rhs, ret );
return SafeInt< T, E >( ret );
}
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator -=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
{
SubtractionHelper< T, T, SubtractionMethod< T, T >::method >::template SubtractThrow< E >( m_int, (T)rhs, m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator -=( U rhs ) SAFEINT_CPP_THROW
{
SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, rhs, m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator -=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, (U)rhs, m_int );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator <<( U bits ) const SAFEINT_CPP_THROW
{
if (ShiftHelper< T, U, ShiftMethod< T, true >::isSignedLeftShift >::ValidBitcount(m_int, bits))
{
return SafeInt< T, E >((T)(m_int << bits));
}
E::SafeIntOnOverflow();
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator <<( SafeInt< U, E > bits ) const SAFEINT_CPP_THROW
{
if (ShiftHelper< T, U, ShiftMethod< T, true >::isSignedLeftShift >::ValidBitcount(m_int, bits))
{
return SafeInt< T, E >((T)(m_int << (U)bits));
}
E::SafeIntOnOverflow();
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator <<=( U bits ) SAFEINT_CPP_THROW
{
if (ShiftHelper< T, U, ShiftMethod< T, true >::isSignedLeftShift >::ValidBitcount(m_int, bits))
{
m_int <<= bits;
return *this;
}
E::SafeIntOnOverflow();
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator <<=( SafeInt< U, E > bits ) SAFEINT_CPP_THROW
{
if (ShiftHelper< T, U, ShiftMethod< T, true >::isSignedLeftShift >::ValidBitcount(m_int, bits))
{
m_int <<= (U)bits;
return *this;
}
E::SafeIntOnOverflow();
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator >>( U bits ) const SAFEINT_CPP_THROW
{
if (ShiftHelper< T, U, ShiftMethod< T, false >::isSignedLeftShift >::ValidBitcount(m_int, bits))
{
return SafeInt< T, E >((T)(m_int >> bits));
}
E::SafeIntOnOverflow();
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator >>( SafeInt< U, E > bits ) const SAFEINT_CPP_THROW
{
if (ShiftHelper< T, U, ShiftMethod< T, false >::isSignedLeftShift >::ValidBitcount(m_int, bits))
{
return SafeInt< T, E >((T)(m_int >> (U)bits));
}
E::SafeIntOnOverflow();
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator >>=( U bits ) SAFEINT_CPP_THROW
{
if (ShiftHelper< T, U, ShiftMethod< T, false >::isSignedLeftShift >::ValidBitcount(m_int, bits))
{
m_int >>= bits;
return *this;
}
E::SafeIntOnOverflow();
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator >>=( SafeInt< U, E > bits ) SAFEINT_CPP_THROW
{
if (ShiftHelper< T, U, ShiftMethod< T, false >::isSignedLeftShift >::ValidBitcount(m_int, bits))
{
m_int >>= (U)bits;
return *this;
}
E::SafeIntOnOverflow();
}
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator &( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW
{
return SafeInt< T, E >( m_int & (T)rhs );
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator &( U rhs ) const SAFEINT_NOTHROW
{
return SafeInt< T, E >( BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, rhs ) );
}
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator &=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
m_int &= (T)rhs;
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator &=( U rhs ) SAFEINT_NOTHROW
{
m_int = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, rhs );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator &=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW
{
m_int = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, (U)rhs );
return *this;
}
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator ^( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW
{
return SafeInt< T, E >( (T)( m_int ^ (T)rhs ) );
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator ^( U rhs ) const SAFEINT_NOTHROW
{
return SafeInt< T, E >( BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, rhs ) );
}
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator ^=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
m_int ^= (T)rhs;
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator ^=( U rhs ) SAFEINT_NOTHROW
{
m_int = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, rhs );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator ^=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW
{
m_int = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, (U)rhs );
return *this;
}
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator |( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW
{
return SafeInt< T, E >( (T)( m_int | (T)rhs ) );
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator |( U rhs ) const SAFEINT_NOTHROW
{
return SafeInt< T, E >( BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, rhs ) );
}
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator |=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
m_int |= (T)rhs;
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator |=( U rhs ) SAFEINT_NOTHROW
{
m_int = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, rhs );
return *this;
}
template < typename U >
SAFEINT_CONSTEXPR14 SafeInt< T, E >& operator |=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW
{
m_int = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, (U)rhs );
return *this;
}
SafeInt< T, E > Min( SafeInt< T, E > test, const T floor = safeint_internal::safeint_min<T>() ) const SAFEINT_NOTHROW
{
T tmp = test < m_int ? (T)test : m_int;
return tmp < floor ? floor : tmp;
}
SafeInt< T, E > Max( SafeInt< T, E > test, const T upper = safeint_internal::safeint_max<T>() ) const SAFEINT_NOTHROW
{
T tmp = test > m_int ? (T)test : m_int;
return tmp > upper ? upper : tmp;
}
void Swap( SafeInt< T, E >& with ) SAFEINT_NOTHROW
{
T temp( m_int );
m_int = with.m_int;
with.m_int = temp;
}
static SafeInt< T, E > SafeAtoI( const char* input ) SAFEINT_CPP_THROW
{
return SafeTtoI( input );
}
static SafeInt< T, E > SafeWtoI( const wchar_t* input )
{
return SafeTtoI( input );
}
enum alignBits
{
align2 = 1,
align4 = 2,
align8 = 3,
align16 = 4,
align32 = 5,
align64 = 6,
align128 = 7,
align256 = 8
};
template < alignBits bits >
const SafeInt< T, E >& Align() SAFEINT_CPP_THROW
{
static_assert( bits >= 0, "Cannot align on a negative bit count" );
static_assert(
std::numeric_limits< T >::is_signed
? bits < (int)safeint_internal::int_traits< T >::bitCount - 1
: bits < (int)safeint_internal::int_traits< T >::bitCount,
"Alignment bit count is too large for type T" );
if( m_int == 0 )
return *this;
if( lhs_is_negative< T, std::numeric_limits< T >::is_signed >::value( m_int ) )
E::SafeIntOnOverflow();
const T AlignValue = ( (T)1 << bits ) - 1;
m_int = align_addmask< T, std::numeric_limits< T >::is_signed >::value( m_int, AlignValue );
if( m_int <= 0 )
E::SafeIntOnOverflow();
return *this;
}
const SafeInt< T, E >& Align2() { return Align< align2 >(); }
const SafeInt< T, E >& Align4() { return Align< align4 >(); }
const SafeInt< T, E >& Align8() { return Align< align8 >(); }
const SafeInt< T, E >& Align16() { return Align< align16 >(); }
const SafeInt< T, E >& Align32() { return Align< align32 >(); }
const SafeInt< T, E >& Align64() { return Align< align64 >(); }
private:
template < typename U >
static SafeInt< T, E > SafeTtoI( U* input ) SAFEINT_CPP_THROW
{
U* tmp = input;
SafeInt< T, E > s;
bool negative = false;
if( input == nullptr || input[0] == 0 )
E::SafeIntOnOverflow();
switch( *tmp )
{
case '-':
tmp++;
negative = true;
break;
case '+':
tmp++;
break;
}
while( *tmp != 0 )
{
if( *tmp < '0' || *tmp > '9' )
break;
if( (T)s != 0 )
s *= (T)10;
if( !negative )
s += (T)( *tmp - '0' );
else
s -= (T)( *tmp - '0' );
tmp++;
}
return s;
}
T m_int;
};
template <typename P>
SAFEINT_CONSTEXPR11 SafeInt<ptrdiff_t, SafeIntDefaultExceptionHandler> SafePtrDiff(const P* p1, const P* p2) SAFEINT_CPP_THROW
{
return ( p1 - p2 );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator <( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, lhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator <( SafeInt<T, E> lhs, U rhs ) SAFEINT_NOTHROW
{
return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( rhs, (T)lhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator <( SafeInt< U, E > lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, (U)lhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator >( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( lhs, (T)rhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator >( SafeInt<T, E> lhs, U rhs ) SAFEINT_NOTHROW
{
return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, rhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator >( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
{
return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, (U)rhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator >=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, lhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator >=( SafeInt<T, E> lhs, U rhs ) SAFEINT_NOTHROW
{
return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( rhs, (T)lhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator >=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
{
return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( (U)rhs, (T)lhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator <=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( lhs, (T)rhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator <=( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW
{
return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, rhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator <=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
{
return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, (U)rhs );
}
template < typename T, typename E >
SAFEINT_CONSTEXPR11 bool operator ==( bool lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
return lhs == ( (T)rhs == 0 ? false : true );
}
template < typename T, typename E >
SAFEINT_CONSTEXPR11 bool operator ==( SafeInt< T, E > lhs, bool rhs ) SAFEINT_NOTHROW
{
return rhs == ( (T)lhs == 0 ? false : true );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator ==( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals((T)rhs, lhs);
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator ==( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW
{
return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, rhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator ==( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
{
return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, (U)rhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator !=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)rhs, lhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator !=( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW
{
return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, rhs );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 bool operator !=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
{
return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( lhs, rhs );
}
template < typename T, typename E >
SAFEINT_CONSTEXPR11 bool operator !=( bool lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
return ( (T)rhs == 0 ? false : true ) != lhs;
}
template < typename T, typename E >
SAFEINT_CONSTEXPR11 bool operator !=( SafeInt< T, E > lhs, bool rhs ) SAFEINT_NOTHROW
{
return ( (T)lhs == 0 ? false : true ) != rhs;
}
template < typename T, typename U, typename E, int method > class ModulusSimpleCaseHelper;
template < typename T, typename E, int method > class ModulusSignedCaseHelper;
template < typename T, typename E > class ModulusSignedCaseHelper < T, E, true >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool SignedCase( SafeInt< T, E > rhs, SafeInt< T, E >& result ) SAFEINT_NOTHROW
{
if( (T)rhs == (T)-1 )
{
result = 0;
return true;
}
return false;
}
};
template < typename T, typename E > class ModulusSignedCaseHelper < T, E, false >
{
public:
SAFEINT_CONSTEXPR11 static bool SignedCase( SafeInt< T, E > , SafeInt< T, E >& ) SAFEINT_NOTHROW
{
return false;
}
};
template < typename T, typename U, typename E >
class ModulusSimpleCaseHelper < T, U, E, true >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool ModulusSimpleCase( U lhs, SafeInt< T, E > rhs, SafeInt< T, E >& result ) SAFEINT_CPP_THROW
{
if( rhs != 0 )
{
if( ModulusSignedCaseHelper< T, E, std::numeric_limits< T >::is_signed >::SignedCase( rhs, result ) )
return true;
result = (T)( lhs % (T)rhs );
return true;
}
E::SafeIntOnDivZero();
}
};
template< typename T, typename U, typename E >
class ModulusSimpleCaseHelper < T, U, E, false >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 static bool ModulusSimpleCase( U , SafeInt< T, E > , SafeInt< T, E >& ) SAFEINT_NOTHROW
{
return false;
}
};
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator %( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
{
SafeInt< T, E > result;
if( ModulusSimpleCaseHelper< T, U, E, (sizeof(T) == sizeof(U)) && ((bool)std::numeric_limits< T >::is_signed == (bool)std::numeric_limits< U >::is_signed) >::ModulusSimpleCase( lhs, rhs, result ) )
return result;
result = (SafeInt< U, E >(lhs) % (T)rhs);
return result;
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14_MULTIPLY SafeInt< T, E > operator *( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
{
T ret( 0 );
MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( (T)rhs, lhs, ret );
return SafeInt< T, E >(ret);
}
template < typename T, typename U, typename E, int method > class DivisionNegativeCornerCaseHelper;
template < typename T, typename U, bool > class division_negative_negateU;
template < typename T, typename U > class division_negative_negateU< T, U, true>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static U div(T rhs, U lhs) { return lhs / (U)(~(std::uint32_t)(T)rhs + 1); }
};
template < typename T, typename U > class division_negative_negateU< T, U, false>
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static U div(T rhs, U lhs) { return lhs / (U)(~(std::uint64_t)(T)rhs + 1); }
};
template < typename T, typename U, typename E > class DivisionNegativeCornerCaseHelper< T, U, E, true >
{
public:
SAFE_INT_NODISCARD static bool NegativeCornerCase( U lhs, SafeInt< T, E > rhs, SafeInt<T, E>& result ) SAFEINT_CPP_THROW
{
U tmp = division_negative_negateU< T, U, sizeof(T) == 4>::div(rhs, lhs);
if( tmp <= (U)safeint_internal::safeint_max<T>() )
{
result = SafeInt< T, E >( (T)(~(std::uint64_t)tmp + 1) );
return true;
}
T maxT = safeint_internal::safeint_max<T>();
if( tmp == (U)maxT + 1 )
{
T minT = safeint_internal::safeint_min<T>();
result = SafeInt< T, E >( minT );
return true;
}
E::SafeIntOnOverflow();
}
};
template < typename T, typename U, typename E > class DivisionNegativeCornerCaseHelper< T, U, E, false >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 static bool NegativeCornerCase( U , SafeInt< T, E > , SafeInt<T, E>& ) SAFEINT_NOTHROW
{
return false;
}
};
template < typename T, typename U, typename E, int method > class DivisionCornerCaseHelper;
template < typename T, typename U, typename E > class DivisionCornerCaseHelper < T, U, E, true >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool DivisionCornerCase1( U lhs, SafeInt< T, E > rhs, SafeInt<T, E>& result ) SAFEINT_CPP_THROW
{
if( (T)rhs > 0 )
{
result = SafeInt< T, E >( lhs/(T)rhs );
return true;
}
if( (T)rhs != 0 )
{
if( DivisionNegativeCornerCaseHelper< T, U, E, sizeof( U ) >= 4 && sizeof( T ) <= sizeof( U ) >::NegativeCornerCase( lhs, rhs, result ) )
return true;
result = SafeInt< T, E >(lhs/(T)rhs);
return true;
}
E::SafeIntOnDivZero();
}
};
template < typename T, typename U, typename E > class DivisionCornerCaseHelper < T, U, E, false >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 static bool DivisionCornerCase1( U , SafeInt< T, E > , SafeInt<T, E>& ) SAFEINT_NOTHROW
{
return false;
}
};
template < typename T, typename U, typename E, int method > class DivisionCornerCaseHelper2;
template < typename T, typename U, bool > class div_negate_min;
template < typename T, typename U > class div_negate_min < T, U , true >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Value(T& ret)
{
ret = (T)(-(T)safeint_internal::safeint_min<U>());
return true;
}
};
template < typename T, typename U > class div_negate_min < T, U, false >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool Value(T& )
{
return false;
}
};
template < typename T, typename U, typename E > class DivisionCornerCaseHelper2 < T, U, E, true >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR14 static bool DivisionCornerCase2( U lhs, SafeInt< T, E > rhs, SafeInt<T, E>& result ) SAFEINT_CPP_THROW
{
if( lhs == safeint_internal::safeint_min<U>() && (T)rhs == -1 )
{
T tmp = 0;
if (div_negate_min< T, U, sizeof(U) < sizeof(T) > ::Value(tmp))
result = tmp;
else
E::SafeIntOnOverflow();
return true;
}
return false;
}
};
template < typename T, typename U, typename E > class DivisionCornerCaseHelper2 < T, U, E, false >
{
public:
SAFE_INT_NODISCARD SAFEINT_CONSTEXPR11 static bool DivisionCornerCase2( U , SafeInt< T, E > , SafeInt<T, E>& ) SAFEINT_NOTHROW
{
return false;
}
};
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator /( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
{
SafeInt< T, E > result;
if( DivisionCornerCaseHelper< T, U, E, (int)DivisionMethod< U, T >::method == (int)DivisionState_UnsignedSigned >::DivisionCornerCase1( lhs, rhs, result ) )
return result;
if( DivisionCornerCaseHelper2< T, U, E, safeint_internal::type_compare< T, U >::isBothSigned >::DivisionCornerCase2( lhs, rhs, result ) )
return result;
U ret = 0;
DivisionHelper< U, T, DivisionMethod< U, T >::method >::template DivideThrow< E >( lhs, (T)rhs, ret );
return SafeInt< T, E >( ret );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator +( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
{
T ret( 0 );
AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( (T)rhs, lhs, ret );
return SafeInt< T, E >( ret );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 SafeInt< T, E > operator -( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
{
T ret( 0 );
SubtractionHelper< U, T, SubtractionMethod2< U, T >::method >::template SubtractThrow< E >( lhs, rhs.Ref(), ret );
return SafeInt< T, E >( ret );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 T& operator +=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
T ret( 0 );
AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( lhs, (U)rhs, ret );
lhs = ret;
return lhs;
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 T& operator -=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
T ret( 0 );
SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( lhs, (U)rhs, ret );
lhs = ret;
return lhs;
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 T& operator *=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
T ret( 0 );
MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( lhs, (U)rhs, ret );
lhs = ret;
return lhs;
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 T& operator /=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
T ret( 0 );
DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( lhs, (U)rhs, ret );
lhs = ret;
return lhs;
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 T& operator %=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
T ret( 0 );
ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( lhs, (U)rhs, ret );
lhs = ret;
return lhs;
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 T& operator &=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
{
lhs = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( lhs, (U)rhs );
return lhs;
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 T& operator ^=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
{
lhs = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( lhs, (U)rhs );
return lhs;
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 T& operator |=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
{
lhs = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( lhs, (U)rhs );
return lhs;
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 T& operator <<=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
lhs = (T)( SafeInt< T, E >( lhs ) << (U)rhs );
return lhs;
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 T& operator >>=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
lhs = (T)( SafeInt< T, E >( lhs ) >> (U)rhs );
return lhs;
}
template < typename T, typename U, typename E >
T*& operator +=( T*& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
SafeInt< size_t, E > ptr_val = reinterpret_cast< size_t >( lhs );
lhs = reinterpret_cast< T* >( (size_t)( ptr_val + (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) );
return lhs;
}
template < typename T, typename U, typename E >
T*& operator -=( T*& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
{
SafeInt< size_t, E > ptr_val = reinterpret_cast< size_t >( lhs );
lhs = reinterpret_cast< T* >( (size_t)( ptr_val - (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) );
return lhs;
}
template < typename T, typename U, typename E >
T*& operator *=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
{
static_assert( sizeof(T) == 0, "Unsupported operator" );
return (lhs = nullptr);
}
template < typename T, typename U, typename E >
T*& operator /=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
{
static_assert(sizeof(T) == 0, "Unsupported operator");
return (lhs = nullptr);
}
template < typename T, typename U, typename E >
T*& operator %=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
{
static_assert(sizeof(T) == 0, "Unsupported operator");
return (lhs = nullptr);
}
template < typename T, typename U, typename E >
T*& operator &=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
{
static_assert(sizeof(T) == 0, "Unsupported operator");
return (lhs = nullptr);
}
template < typename T, typename U, typename E >
T*& operator ^=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
{
static_assert(sizeof(T) == 0, "Unsupported operator");
return (lhs = nullptr);
}
template < typename T, typename U, typename E >
T*& operator |=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
{
static_assert(sizeof(T) == 0, "Unsupported operator");
return (lhs = nullptr);
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 T*& operator <<=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
{
static_assert(sizeof(T) == 0, "Unsupported operator");
return (lhs = nullptr);
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 T*& operator >>=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
{
static_assert(sizeof(T) == 0, "Unsupported operator");
return (lhs = nullptr);
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 SafeInt< U, E > operator <<( U lhs, SafeInt< T, E > bits ) SAFEINT_CPP_THROW
{
if (ShiftHelper< U, T, ShiftMethod< U, true >::isSignedLeftShift >::ValidBitcount(lhs, bits))
{
return SafeInt< U, E >((U)(lhs << (T)bits));
}
E::SafeIntOnOverflow();
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR14 SafeInt< U, E > operator >>( U lhs, SafeInt< T, E > bits ) SAFEINT_CPP_THROW
{
if (ShiftHelper< U, T, ShiftMethod< U, false >::isSignedLeftShift >::ValidBitcount(lhs, bits))
{
return SafeInt< U, E >((U)(lhs >> (T)bits));
}
E::SafeIntOnOverflow();
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 SafeInt< T, E > operator &( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
return SafeInt< T, E >( BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( (T)rhs, lhs ) );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 SafeInt< T, E > operator ^( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
return SafeInt< T, E >(BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( (T)rhs, lhs ) );
}
template < typename T, typename U, typename E >
SAFEINT_CONSTEXPR11 SafeInt< T, E > operator |( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
{
return SafeInt< T, E >( BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( (T)rhs, lhs ) );
}
#endif