📄 safeint.hpp
字号:
throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
}
++m_int;
return *this;
}
//prefix decrement operator
SafeInt<T>& operator --()
{
if(m_int == MinInt())
{
throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
}
--m_int;
return *this;
}
//postfix increment operator
SafeInt<T> operator ++(int) //dummy arg to comply with spec
{
if(m_int == MaxInt())
{
throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
}
SafeInt<T> tmp = m_int;
m_int++;
return tmp;
}
//postfix decrement operator
SafeInt<T> operator --(int) //dummy arg to comply with spec
{
if(m_int == MinInt())
{
throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
}
SafeInt<T> tmp = m_int;
m_int--;
return tmp;
}
//one's complement
//note - this operator will normally change size to an int
//cast in return improves perf and maintains type
SafeInt<T> operator ~() const {return SafeInt<T>((T)~m_int);}
//binary operators
//
// arithmetic binary operators
// % modulus
// * multiplication
// / division
// + addition
// - subtraction
//
// For each of the arithmetic operators, you will need to
// use them as follows:
//
// SafeInt<char> c = 2;
// SafeInt<int> i = 3;
//
// SafeInt<int> i2 = i op c.Value();
// OR
// SafeInt<char> i2 = i.Value() op c;
//
// The base problem is that if the lhs and rhs inputs are different SafeInt types
// it is not possible in this implementation to determine what type of SafeInt
// should be returned. You have to let the class know which of the two inputs
// need to be the return type by forcing the other value to the base integer type.
// The case of:
//
// SafeInt<T> i, j, k;
// i = j op k;
//
// works just fine and no unboxing is needed because the return type is not ambiguous.
//modulus
//modulus has some convenient properties -
//first, the magnitude of the return can never be
//larger than the lhs operand, and it must be the same sign
//as well. It does, however, suffer from the same promotion
//problems as comparisons, division and other operations
template <typename U>
SafeInt<T> operator %(U rhs)
{
return MixedSizeModulus(*this, rhs);
}
SafeInt<T> operator %(SafeInt<T> rhs)
{
if(rhs.Value() == 0)
throw SafeIntException(EXCEPTION_INT_DIVIDE_BY_ZERO);
//this is always safe
return SafeInt<T>((T)(m_int % rhs.Value()));
}
//modulus assignment
template <typename U>
SafeInt<T>& operator %=(U rhs)
{
*this = MixedSizeModulus(*this, rhs);
return *this;
}
template <typename U>
SafeInt<T>& operator %=(SafeInt<U> rhs)
{
*this = MixedSizeModulus(*this, rhs.Value());
return *this;
}
//multiplication
template <typename U>
SafeInt<T> operator *(U rhs)
{
return MixedSizeMultiply(*this, rhs);
}
SafeInt<T> operator *(SafeInt<T> rhs)
{
return SafeInt<T>(multiply(m_int, rhs.Value()));
}
//multiplication assignment
SafeInt<T>& operator *=(SafeInt<T> rhs)
{
m_int = multiply(rhs.m_int, m_int);
return *this;
}
template <typename U>
SafeInt<T>& operator *=(U rhs)
{
*this = MixedSizeMultiply(*this, rhs);
return *this;
}
template <typename U>
SafeInt<T>& operator *=(SafeInt<U> rhs)
{
*this = MixedSizeMultiply(*this, rhs.Value());
return *this;
}
//division
template <typename U>
SafeInt<T> operator /(U rhs)
{
return MixedSizeDivision(*this, rhs);
}
SafeInt<T> operator /(SafeInt<T> rhs)
{
return MixedSizeDivision(*this, rhs.Value());
}
//division assignment
SafeInt<T>& operator /=(SafeInt<T> i)
{
*this = MixedSizeDivision(*this, i.Value());
return *this;
}
template <typename U> SafeInt<T>& operator /=(U i)
{
*this = MixedSizeDivision(*this, i);
return *this;
}
template <typename U> SafeInt<T>& operator /=(SafeInt<U> i)
{
*this = MixedSizeDivision(*this, i.Value());
return *this;
}
//for addition and subtraction
//addition
inline SafeInt<T> operator +(SafeInt<T> rhs)
{
return SafeInt<T>(addition(m_int, rhs.Value()));
}
template <typename U>
inline SafeInt<T> operator +(U rhs)
{
return MixedSizeAddition(*this, rhs);
}
//addition assignment
SafeInt<T>& operator +=(SafeInt<T> rhs)
{
m_int = addition(m_int, rhs.m_int);
return *this;
}
template <typename U>
SafeInt<T>& operator +=(U rhs)
{
*this = MixedSizeAddition(*this, rhs);
return *this;
}
template <typename U>
SafeInt<T>& operator +=(SafeInt<U> rhs)
{
*this = MixedSizeAddition(*this, rhs.Value());
return *this;
}
//subtraction
template <typename U>
SafeInt<T> operator -(U rhs)
{
return MixedSizeSubtraction(*this, rhs);
}
SafeInt<T> operator -(SafeInt<T> rhs)
{
return SafeInt<T>(subtraction(m_int, rhs.m_int));
}
//subtraction assignment
SafeInt<T>& operator -=(SafeInt<T> rhs)
{
m_int = subtraction(m_int, rhs.m_int);
return *this;
}
template <typename U>
SafeInt<T>& operator -=(U rhs)
{
*this = MixedSizeSubtraction(*this, rhs);
return *this;
}
template <typename U>
SafeInt<T>& operator -=(SafeInt<U> rhs)
{
*this = MixedSizeSubtraction(*this, rhs.Value());
return *this;
}
//comparison operators
//additional overloads defined outside the class at the bottom of
//the header to allow for cases where the SafeInt is the rhs value
// less than
template <typename U>
bool operator <(U rhs)
{
return LessThan(m_int, rhs);
}
bool operator <(SafeInt<T> rhs)
{
return m_int < rhs.m_int;
}
//greater than or eq.
template <typename U>
bool operator >=(U rhs){return !(*this < rhs);}
bool operator >=(SafeInt<T> rhs)
{
return m_int >= rhs.Value();
}
// greater than
template <typename U>
bool operator >(U rhs)
{
return SafeInt<T>::GreaterThan(m_int, rhs);
}
bool operator >(SafeInt<T> rhs)
{
return m_int > rhs.m_int;
}
//less than or eq.
template <typename U>
bool operator <=(U rhs){return !(*this > rhs);}
//same type - easy path
bool operator <=(SafeInt<T> rhs)
{
return m_int <= rhs.Value();
}
//equality
template <typename U>
bool operator ==(U rhs){return Equals(m_int, rhs);}
//need an explicit override for type bool
bool operator ==(bool rhs)
{
return (m_int == 0 ? false : true) == rhs;
}
bool operator ==(SafeInt<T> rhs){return m_int == rhs.Value();}
//!= operators
template <typename U>
bool operator !=(U rhs){return !Equals(m_int, rhs);}
bool operator !=(bool b)
{
return (m_int == 0 ? false : true) != b;
}
bool operator !=(SafeInt<T> rhs){return m_int != rhs.Value();}
//shift operators
//Note - shift operators ALWAYS return the same type as the lhs
//specific version for SafeInt<T> not needed -
//code path is exactly the same as for SafeInt<U> as rhs
//left shift
//Also, shifting > bitcount is undefined - trap in debug
template <typename U>
SafeInt<T> operator <<(U bits)
{
if(IsSigned(bits))
assert(bits >= 0);
assert(bits < BitCount());
return SafeInt<T>((T)(m_int << bits));
}
template <typename U>
SafeInt<T> operator <<(SafeInt<U> bits)
{
if(IsSigned(bits))
assert(bits >= 0);
assert(bits < BitCount());
return SafeInt<T>((T)(m_int << bits.Value()));
}
//left shift assignment
template <typename U>
SafeInt<T>& operator <<=(U bits)
{
if(IsSigned(bits))
assert(bits >= 0);
assert(bits < BitCount());
m_int <<= bits;
return *this;
}
template <typename U>
SafeInt<T>& operator <<=(SafeInt<U> bits)
{
if(IsSigned(bits))
assert(bits.Value() >= 0);
assert(bits.Value() < BitCount());
m_int <<= bits.Value();
return *this;
}
//right shift
template <typename U>
SafeInt<T> operator >>(U bits)
{
if(IsSigned(bits))
assert(bits >= 0);
assert(bits < BitCount());
return SafeInt<T>((T)(m_int >> bits));
}
template <typename U>
SafeInt<T> operator >>(SafeInt<U> bits)
{
if(IsSigned(bits))
assert(bits >= 0);
assert(bits < BitCount());
return SafeInt<T>((T)(m_int >> bits.Value()));
}
//right shift assignment
template <typename U>
SafeInt<T>& operator >>=(U bits)
{
if(IsSigned(bits))
assert(bits >= 0);
assert(bits < BitCount());
m_int >>= bits;
return *this;
}
template <typename U>
SafeInt<T>& operator >>=(SafeInt<U> bits)
{
if(IsSigned(bits))
assert(bits.Value() >= 0);
assert(bits.Value() < BitCount());
m_int >>= bits.Value();
return *this;
}
//bitwise operators
//this only makes sense if we're dealing with the same type and size
//demand a type T, or something that fits into a type T
//bitwise &
SafeInt<T> operator &(SafeInt<T> rhs)
{
return SafeInt<T>((T)(m_int & rhs.m_int));
}
template <typename U>
SafeInt<T> operator &(U rhs)
{
//if U can fit into T without truncating, force U to T
if(sizeof(U) <= sizeof(T))
return SafeInt<T>(m_int & (T)rhs);
//might still be safe
//cast rhs down to a T, then back up to U
//check to see if it is equal to the original value
//this allows things like
//SafeInt<char>(2) & 4 (literal is an int) to work
if( (U)((T)rhs) == rhs)
return SafeInt<T>(m_int & (T)rhs);
throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
}
//bitwise & assignment
SafeInt<T>& operator &=(SafeInt<T> rhs)
{
m_int &= rhs.m_int;
return *this;
}
template <typename U>
SafeInt<T>& operator &=(U rhs)
{
*this = *this & rhs;
return *this;
}
template <typename U>
SafeInt<T>& operator &=(SafeInt<U> rhs)
{
*this = *this & rhs.Value();
return *this;
}
//XOR
SafeInt<T> operator ^(SafeInt<T> rhs)
{
return SafeInt<T>((T)(m_int ^ rhs.m_int));
}
template <typename U>
SafeInt<T> operator ^(U rhs)
{
//if U can fit into T without truncating, force U to T
if(sizeof(U) <= sizeof(T))
return SafeInt<T>(m_int ^ (T)rhs);
if( (U)((T)rhs) == rhs)
return SafeInt<T>(m_int ^ (T)rhs);
throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
}
//XOR assignment
SafeInt<T>& operator ^=(SafeInt<T> i)
{
m_int ^= i.m_int;
return *this;
}
template <typename U>
SafeInt<T>& operator ^=(U rhs)
{
*this = *this ^ rhs;
return *this;
}
template <typename U>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -