Patrick Kelley 8fd444092b initial
2025-05-07 15:35:15 -04:00

700 lines
19 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#if !defined __GNUC__
// relative include path contains '..', specific to this file
#pragma warning( disable: 4464 )
#else
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
#if !defined __clang__ && defined __GNUC__ && __cplusplus >= 201402L
// The gcc compiler isn't smart enough to sort out that the constexpr exception functions
// are never hit, so create a null exception handler. Nothing in this file is tested at runtime in any case.
class SafeIntGccCompileOnly
{
public:
constexpr static void SafeIntOnOverflow()
{
}
constexpr static void SafeIntOnDivZero()
{
}
};
#define SafeIntDefaultExceptionHandler SafeIntGccCompileOnly
#endif
#include "../SafeInt.hpp"
namespace TestConstExpr
{
template <typename T, typename U>
SAFEINT_CONSTEXPR11 bool LessThanTest()
{
return
(U)2 < SafeInt<T>(3) &&
SafeInt<T>(4) < (U)5 &&
SafeInt<T>(6) < SafeInt<U>(7);
}
template <typename T, typename U>
SAFEINT_CONSTEXPR11 bool GreaterThanTest()
{
return
(U)2 > SafeInt<T>(3) &&
SafeInt<T>(4) > (U)5 &&
SafeInt<T>(6) > SafeInt<U>(7);
}
template <typename T, typename U>
SAFEINT_CONSTEXPR11 bool LessThanEqualTest()
{
return
(U)2 <= SafeInt<T>(3) &&
SafeInt<T>(4) <= (U)5 &&
SafeInt<T>(6) <= SafeInt<U>(7);
}
template <typename T, typename U>
SAFEINT_CONSTEXPR11 bool GreaterThanEqualTest()
{
return
(U)2 >= SafeInt<T>(3) &&
SafeInt<T>(4) >= (U)5 &&
SafeInt<T>(6) >= SafeInt<U>(7);
}
template <typename T, typename U>
SAFEINT_CONSTEXPR11 bool EqualTest()
{
return
(U)2 == SafeInt<T>(3) &&
SafeInt<T>(4) == (U)5 &&
SafeInt<T>(6) == SafeInt<U>(7) &&
true == SafeInt<T>(1) &&
false == SafeInt<T>(0);
}
template <typename T, typename U>
SAFEINT_CONSTEXPR11 bool NotEqualTest()
{
return
(U)2 != SafeInt<T>(3) &&
SafeInt<T>(4) != (U)5 &&
SafeInt<T>(6) != SafeInt<U>(7) &&
true != SafeInt<T>(1) &&
false != SafeInt<T>(0);
}
template <typename T, typename U>
void ComparisonTestTU()
{
static bool b1 = LessThanTest<T, U>();
static bool b2 = LessThanEqualTest<T, U>();
static bool b3 = GreaterThanTest<T, U>();
static bool b4 = GreaterThanEqualTest<T, U>();
static bool b5 = EqualTest<T, U>();
static bool b6 = NotEqualTest<T, U>();
}
template <typename T> void ComparisonTestT()
{
ComparisonTestTU<T, char>();
ComparisonTestTU<T, signed char>();
ComparisonTestTU<T, unsigned char>();
ComparisonTestTU<T, signed short>();
ComparisonTestTU<T, unsigned short>();
ComparisonTestTU<T, signed int>();
ComparisonTestTU<T, unsigned int>();
ComparisonTestTU<T, signed long>();
ComparisonTestTU<T, unsigned long>();
ComparisonTestTU<T, signed long long>();
ComparisonTestTU<T, unsigned long long>();
}
template <typename T>
SAFEINT_CONSTEXPR11 T ConstConstructor()
{
// Constructors, also add in the useless unary + operator
return SafeInt<T>() + SafeInt<T>(1) + SafeInt<T>(false) + (+SafeInt<T>(3));
}
template <typename T>
SAFEINT_CONSTEXPR11 bool ConstBool()
{
return (bool)SafeInt<T>(2) && !SafeInt<T>(0);
}
template <typename T>
void ConstTestT()
{
static const T t = ConstConstructor<T>();
static const bool b = ConstBool<T>();
}
template <typename T>
SAFEINT_CONSTEXPR11 SafeInt<T> ConstSafeInt()
{
return SafeInt<T>(1);
}
template <typename T>
void ConstCastTestT()
{
static const bool b = ConstSafeInt<T>();
static const wchar_t w = ConstSafeInt<T>();
static const char c = ConstSafeInt<T>();
static const signed char sc = ConstSafeInt<T>();
static const unsigned char uc = ConstSafeInt<T>();
static const signed short s = ConstSafeInt<T>();
static const unsigned short us = ConstSafeInt<T>();
static const signed int i = ConstSafeInt<T>();
static const unsigned int ui = ConstSafeInt<T>();
static const signed long l = ConstSafeInt<T>();
static const unsigned long ul = ConstSafeInt<T>();
static const signed long long ll = ConstSafeInt<T>();
static const unsigned long long ull = ConstSafeInt<T>();
static const size_t st = ConstSafeInt<T>();
static const ptrdiff_t pt = ConstSafeInt<T>();
// Also catch the useless unary + operator
static const int pl = +ConstSafeInt<T>();
}
#if CPLUSPLUS_STD == CPLUSPLUS_14
template <typename T, typename U>
SAFEINT_CONSTEXPR14 T DivOperator()
{
// Have to explicitly force this operator
// to be used
T lhs = 3;
SafeInt<U> s(2);
T& r = operator /=(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 T AddOperator()
{
// Have to explicitly force this operator
// to be used
T lhs = 3;
SafeInt<U> s(2);
T& r = operator +=(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 T SubOperator()
{
// Have to explicitly force this operator
// to be used
T lhs = 3;
SafeInt<U> s(2);
T& r = operator -=(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 T LShiftOperator()
{
// Have to explicitly force this operator
// to be used
// T& operator <<=(T& lhs, SafeInt< U, E > rhs)
T lhs = 3;
SafeInt<U> s(2);
T& r = operator <<=(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 U LShiftOperator2()
{
// Have to explicitly force this operator
// to be used
U lhs = 3;
SafeInt<T> s(2);
SafeInt<U> r = operator <<(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 T RShiftOperator()
{
// Have to explicitly force this operator
// to be used
T lhs = 3;
SafeInt<U> s(1);
T& r = operator >>=(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 U RShiftOperator2()
{
// Have to explicitly force this operator
// to be used
U lhs = 3;
SafeInt<T> s(1);
SafeInt<U> r = operator >>(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 T AndOperator()
{
// Have to explicitly force this operator
// to be used
T lhs = 3;
SafeInt<U> s(1);
T& r = operator &=(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 U AndOperator2()
{
// Have to explicitly force this operator
// to be used
U lhs = 3;
SafeInt<T> s(1);
SafeInt<T> r = operator &(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 T XorOperator()
{
// Have to explicitly force this operator
// to be used
T lhs = 3;
SafeInt<U> s(1);
T& r = operator ^=(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 U XorOperator2()
{
// Have to explicitly force this operator
// to be used
U lhs = 3;
SafeInt<T> s(1);
SafeInt<T> r = operator ^(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 T OrOperator()
{
// Have to explicitly force this operator
// to be used
T lhs = 3;
SafeInt<U> s(1);
T& r = operator |=(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 U OrOperator2()
{
// Have to explicitly force this operator
// to be used
U lhs = 3;
SafeInt<T> s(1);
SafeInt<T> r = operator |(lhs, s);
return r;
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 bool SafeCastTest()
{
U to = 0;
return SafeCast((T)3, to);
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 bool SafeModulusTest()
{
U u = 2;
T result = 0;
return SafeModulus((T)3, u, result);
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 bool SafeMultiplyTest()
{
U u = 2;
T result = 0;
return SafeMultiply((T)3, u, result);
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 bool SafeDivideTest()
{
U u = 2;
T result = 0;
return SafeDivide((T)3, u, result);
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 bool SafeAddTest()
{
U u = 2;
T result = 0;
return SafeAdd((T)3, u, result);
}
template <typename T, typename U>
void StaticAssertTU()
{
// Constructors
static_assert(SafeInt<T>(SafeInt<U>(1)), "SafeInt U constr");
static_assert(SafeInt<T>((U)1), "U constr");
// Assignment operators
static_assert((SafeInt<T>() = (U)1), "Assignment U");
static_assert((SafeInt<T>() = (T)1), "Assignment T");
static_assert((SafeInt<T>() = SafeInt<U>(1)), "Assignment SafeInt U");
// Next one happens when T == U, so already included
// static_assert((SafeInt<T>() = SafeInt<T>(1)), "Assignment SafeInt T");
// Test the casting operators
static_assert((U)(SafeInt<T>((T)1)), "Casting");
// Modulus
static_assert(SafeInt<T>((T)3) % (U)2, "Modulus");
static_assert(SafeInt<T>((T)3) % SafeInt<T>(2), "Modulus");
static_assert((SafeInt<T>((T)3) %= (U)2), "Modulus");
static_assert((SafeInt<T>((T)3) %= SafeInt<U>(2)), "Modulus");
static_assert((U)3 % SafeInt<T>(2), "Modulus");
static_assert((T)3 % SafeInt<U>(2), "Modulus");
// Multiplication
// Multiplication must either use intrinsics OR constexpr, but not both because the intrinsics aren't marked constexpr
#if !SAFEINT_USE_INTRINSICS
static_assert(SafeInt<T>((T)3) * (U)2, "Multiplication");
static_assert(SafeInt<T>((T)3) * SafeInt<T>(2), "Multiplication");
static_assert((SafeInt<T>((T)3) *= (U)2), "Multiplication");
static_assert((SafeInt<T>((T)3) *= SafeInt<U>(2)), "Multiplication");
static_assert((U)3 * SafeInt<T>(2), "Multiplication");
static_assert(((T)3 * SafeInt<U>(2)), "Multiplication");
#endif
// Division
static_assert(SafeInt<T>((T)3) / (U)2, "Division");
static_assert(SafeInt<T>((T)3) / SafeInt<T>(2), "Division");
static_assert((SafeInt<T>((T)3) /= (U)2), "Division");
#if SAFEINT_COMPILER != GCC_COMPILER
// gcc is not happy with this one
static_assert((SafeInt<T>((T)3) /= SafeInt<U>(2)), "Division");
static_assert((U)3 / SafeInt<T>(2), "Division");
#endif
static_assert(DivOperator<T,U>(), "Division");
// Addition
static_assert(SafeInt<T>((T)3) + (U)2, "Addition");
static_assert(SafeInt<T>((T)3) + SafeInt<T>(2), "Addition");
static_assert((SafeInt<T>((T)3) += (U)2), "Addition");
static_assert((SafeInt<T>((T)3) += SafeInt<U>(2)), "Addition");
static_assert((U)3 + SafeInt<T>(2), "Addition");
static_assert(AddOperator<T, U>(), "Addition");
// Subtraction
static_assert(SafeInt<T>((T)3) - (U)2, "Subtraction");
static_assert(SafeInt<T>((T)3) - SafeInt<T>(2), "Subtraction");
static_assert((SafeInt<T>((T)3) -= (U)2), "Subtraction");
static_assert((SafeInt<T>((T)3) -= SafeInt<U>(2)), "Subtraction");
static_assert((U)3 - SafeInt<T>(2), "Subtraction");
static_assert(SubOperator<T, U>(), "Subtraction");
// Shift
// Left
static_assert(SafeInt<T>((T)3) << (U)2, "Shift");
static_assert(SafeInt<T>((T)3) << SafeInt<U>(2), "Shift");
static_assert((SafeInt<T>((T)3) <<= (U)2), "Shift");
static_assert((SafeInt<T>((T)3) <<= SafeInt<U>(2)), "Shift");
static_assert(LShiftOperator<T, U>(), "Shift");
static_assert(LShiftOperator2<T, U>(), "Shift");
// Right
static_assert(SafeInt<T>((T)3) >> (U)1, "Shift");
static_assert(SafeInt<T>((T)3) >> SafeInt<U>(1), "Shift");
static_assert((SafeInt<T>((T)3) >>= (U)1), "Shift");
static_assert((SafeInt<T>((T)3) >>= SafeInt<U>(1)), "Shift");
static_assert(RShiftOperator<T, U>(), "Shift");
static_assert(RShiftOperator2<T, U>(), "Shift");
// Binary And
static_assert(SafeInt<T>((T)3) & SafeInt<T>(1), "And");
static_assert(SafeInt<T>((T)3) & (U)1, "And");
static_assert((SafeInt<T>((T)3) &= (U)(1)), "And");
static_assert((SafeInt<T>((T)3) &= SafeInt<U>(1)), "And");
static_assert(AndOperator<T, U>(), "And");
static_assert(AndOperator2<T, U>(), "And");
// Binary Xor
static_assert(SafeInt<T>((T)3) ^ SafeInt<T>(1), "Xor");
static_assert(SafeInt<T>((T)3) ^ (U)1, "Xor");
static_assert((SafeInt<T>((T)3) ^= (U)(1)), "Xor");
static_assert((SafeInt<T>((T)3) ^= SafeInt<U>(1)), "Xor");
static_assert(XorOperator<T, U>(), "Xor");
static_assert(XorOperator2<T, U>(), "Xor");
// Binary Or
static_assert(SafeInt<T>((T)3) | SafeInt<T>(1), "Or");
static_assert(SafeInt<T>((T)3) | (U)1, "Or");
static_assert((SafeInt<T>((T)3) |= (U)(1)), "Or");
static_assert((SafeInt<T>((T)3) |= SafeInt<U>(1)), "Or");
static_assert(OrOperator<T, U>(), "Or");
static_assert(OrOperator2<T, U>(), "Or");
// Comparisons
// Less than
static_assert(SafeInt<T>((T)2) < (U)3, "LT");
static_assert((T)2 < SafeInt<U>((U)3), "LT");
static_assert(SafeInt<T>((T)2) < SafeInt<U>((U)3), "LT");
// Less than or equal
static_assert(SafeInt<T>((T)2) <= (U)3, "LTE");
static_assert((T)2 <= SafeInt<U>((U)3), "LTE");
static_assert(SafeInt<T>((T)2) <= SafeInt<U>((U)3), "LTE");
// Greater than
static_assert(SafeInt<T>((T)4) > (U)3, "GT");
static_assert((T)4 > SafeInt<U>((U)3), "GT");
static_assert(SafeInt<T>((T)4) > SafeInt<U>((U)3), "GT");
// Less than or equal
static_assert(SafeInt<T>((T)4) >= (U)3, "GTE");
static_assert((T)4 >= SafeInt<U>((U)3), "GTE");
static_assert((SafeInt<T>((T)4) >= SafeInt<U>((U)3)), "GTE");
// Equals
static_assert(SafeInt<T>((T)3) == (U)3, "EQ");
static_assert((T)3 == SafeInt<U>((U)3), "EQ");
static_assert(SafeInt<T>((T)3) == SafeInt<U>((U)3), "EQ");
// Not equal
static_assert(SafeInt<T>((T)4) != (U)3, "NEQ");
static_assert((T)4 != SafeInt<U>((U)3), "NEQ");
static_assert(SafeInt<T>((T)4) != SafeInt<U>((U)3), "NEQ");
// Now need coverage for these:
static_assert(SafeCastTest<T,U>(), "SafeCast");
static_assert(SafeEquals((T)2, (U)2), "SafeEquals");
static_assert(SafeNotEquals((T)3, (U)2), "SafeNotEquals");
static_assert(SafeGreaterThan((T)3, (U)2), "SafeGreaterThan");
static_assert(SafeGreaterThanEquals((T)3, (U)2), "SafeGreaterThanEquals");
static_assert(SafeLessThan((T)1, (U)2), "SafeLessThan");
static_assert(SafeLessThanEquals((T)1, (U)2), "SafeLessThanEquals");
static_assert(SafeModulusTest<T, U>(), "SafeModulus");
#if !SAFEINT_USE_INTRINSICS
static_assert(SafeMultiplyTest<T, U>(), "SafeMultiply");
#endif
static_assert(SafeDivideTest<T, U>(), "SafeDivide");
static_assert(SafeAddTest<T, U>(), "SafeAdd");
}
template <typename T>
void StaticAssertTest()
{
static_assert(SafeInt<T>() == 0, "Default constr");
static_assert(SafeInt<T>((T)1), "T constr");
static_assert(SafeInt<T>(true), "bool constr");
// Floating point will not work due to presence of fpclassify
// static_assert(SafeInt<T>((float)1.0), "float constr");
StaticAssertTU<T, char>();
StaticAssertTU<T, signed char>();
StaticAssertTU<T, unsigned char>();
StaticAssertTU<T, signed short>();
StaticAssertTU<T, unsigned short>();
StaticAssertTU<T, signed int>();
StaticAssertTU<T, unsigned int>();
StaticAssertTU<T, signed long>();
StaticAssertTU<T, unsigned long>();
StaticAssertTU<T, signed long long>();
StaticAssertTU<T, unsigned long long>();
// Special case casting
static_assert((bool)(SafeInt<T>((T)1)), "Casting");
static_assert((wchar_t)(SafeInt<T>((T)1)), "Casting");
static_assert((float)(SafeInt<T>((T)1)), "Casting");
static_assert((double)(SafeInt<T>((T)1)), "Casting");
static_assert((long double)(SafeInt<T>((T)1)), "Casting");
// Unary operations
static_assert(!SafeInt<T>((T)0), "operator !");
static_assert(++SafeInt<T>((T)1), "operator ++");
static_assert(SafeInt<T>((T)1)++, "operator ++");
static_assert(--SafeInt<T>((T)2), "operator --");
static_assert(SafeInt<T>((T)2)--, "operator --");
static_assert(~SafeInt<T>((T)0), "operator ~");
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 T ConstMultiplyTU()
{
return (SafeInt<T>(2) * (U)1) + (U(4) * SafeInt<T>(3)) + (SafeInt<T>(6) * SafeInt<T>(5));
}
template <typename T>
void ConstMultiplyT()
{
static const T c = ConstMultiplyTU< T, char >();
static const T sc = ConstMultiplyTU< T, signed char >();
static const T uc = ConstMultiplyTU< T, unsigned char >();
static const T ss = ConstMultiplyTU< T, signed short >();
static const T us = ConstMultiplyTU< T, unsigned short >();
static const T si = ConstMultiplyTU< T, signed int >();
static const T ui = ConstMultiplyTU< T, unsigned int >();
static const T sl = ConstMultiplyTU< T, signed long >();
static const T ul = ConstMultiplyTU< T, unsigned long >();
static const T sll = ConstMultiplyTU< T, signed long long >();
static const T ull = ConstMultiplyTU< T, unsigned long long >();
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 T ConstSubtractTU()
{
return (SafeInt<T>(2) - (U)1) + (U(4) - SafeInt<T>(3)) + (SafeInt<T>(6) - SafeInt<T>(5));
}
template <typename T>
void ConstSubtractT()
{
static const T c = ConstSubtractTU< T, char >();
static const T sc = ConstSubtractTU< T, signed char >();
static const T uc = ConstSubtractTU< T, unsigned char >();
static const T ss = ConstSubtractTU< T, signed short >();
static const T us = ConstSubtractTU< T, unsigned short >();
static const T si = ConstSubtractTU< T, signed int >();
static const T ui = ConstSubtractTU< T, unsigned int >();
static const T sl = ConstSubtractTU< T, signed long >();
static const T ul = ConstSubtractTU< T, unsigned long >();
static const T sll = ConstSubtractTU< T, signed long long >();
static const T ull = ConstSubtractTU< T, unsigned long long >();
}
template <typename T, typename U>
SAFEINT_CONSTEXPR14 T ConstAddTU()
{
return (SafeInt<T>(1) + (U)2) + (U(3) + SafeInt<T>(4)) + (SafeInt<T>(5) + SafeInt<T>(6));
}
template <typename T>
void ConstAddT()
{
static const T c = ConstAddTU< T, char >();
static const T sc = ConstAddTU< T, signed char >();
static const T uc = ConstAddTU< T, unsigned char >();
static const T ss = ConstAddTU< T, signed short >();
static const T us = ConstAddTU< T, unsigned short >();
static const T si = ConstAddTU< T, signed int >();
static const T ui = ConstAddTU< T, unsigned int >();
static const T sl = ConstAddTU< T, signed long >();
static const T ul = ConstAddTU< T, unsigned long >();
static const T sll = ConstAddTU< T, signed long long >();
static const T ull = ConstAddTU< T, unsigned long long >();
}
template <typename T>
SAFEINT_CONSTEXPR14 T PrefixInc(T i)
{
return ++SafeInt<T>(i);
}
template <typename T>
SAFEINT_CONSTEXPR14 T PostfixInc(T i)
{
return SafeInt<T>(i)++;
}
template <typename T>
SAFEINT_CONSTEXPR14 void SignedOnly()
{
static_assert(-SafeInt<T>((T)1), "operator -");
}
void TestSignedOnly()
{
SignedOnly<signed char>();
SignedOnly<signed short>();
SignedOnly<signed int>();
SignedOnly<signed long>();
SignedOnly<signed long long>();
}
#endif // CPLUSPLUS_14
template <typename T>
void ConstExprTestT()
{
ConstTestT<T>();
ComparisonTestT<T>();
ConstCastTestT<T>();
#if CPLUSPLUS_STD == CPLUSPLUS_14
StaticAssertTest<T>();
TestSignedOnly();
ConstAddT<T>();
ConstSubtractT<T>();
ConstMultiplyT<T>();
#endif
}
void ConstExprTest()
{
ConstExprTestT<char>();
ConstExprTestT<signed char>();
ConstExprTestT<unsigned char>();
ConstExprTestT<signed short>();
ConstExprTestT<unsigned short>();
ConstExprTestT<signed int>();
ConstExprTestT<unsigned int>();
ConstExprTestT<signed long>();
ConstExprTestT<unsigned long>();
ConstExprTestT<signed long long>();
ConstExprTestT<unsigned long long>();
// Catch the SafePtrDiff function, since it is marked. Can't think of a scenario for this being constexpr, though.
const char* p1 = (char*)1;
const char* p2 = nullptr;
static const SafeInt<ptrdiff_t> pt = SafePtrDiff(p1, p2);
if (pt > 0)
return;
}
}
void ConstExpr()
{
TestConstExpr::ConstExprTest();
}