⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 safeint.hpp

📁 自定义HttpClient类
💻 HPP
📖 第 1 页 / 共 5 页
字号:
	SafeInt<T>& operator ^=(SafeInt<U> rhs)
	{
		*this = *this ^ rhs.Value();
		return *this;
	}

	//bitwise OR
	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);

	}

	//bitwise OR 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> 
	SafeInt<T>& operator |=(SafeInt<U> rhs)
	{
		*this = *this | rhs.Value();
		return *this;
	}

	//logical operators
	//logical operators are like comparison operators
	//because the return value is the same regardless of 
	//what type is on the RHS or the LHS

	//and as it turns out, we need some overloads
	//bool constructor has a little overhead
	//possible combinations:
	// SafeInt<T>, SafeInt<T> - internal
	// SafeInt<T>, U          - internal
	// SafeInt<T>, bool       - internal
	// bool, SafeInt<T>       - external
	// U, SafeInt<T>          - external
	// SafeInt<U>, SafeInt<T> - external

	//logical OR
	bool operator ||(SafeInt<T> rhs)
	{
		return m_int || rhs.Value();
	}

	template <typename U>
	bool operator ||(U rhs)
	{
		return m_int || rhs;
	}

	bool operator ||(bool rhs) 
	{
		return m_int || rhs;
	}

	//logical &&
	bool operator &&(SafeInt<T> rhs)
	{
		return m_int && rhs.Value();
	}

	template <typename U>
	bool operator &&(U rhs)
	{
		return m_int && rhs;
	}

	bool operator &&(bool rhs) 
	{
		return m_int && rhs;
	}

	//miscellaneous helper functions
	SafeInt<T> Min(SafeInt<T> test, SafeInt<T> floor = SafeInt<T>::MinInt()) const
	{
		T tmp = test.Value() < m_int ? test.Value() : m_int;
		return tmp < floor ? floor : tmp;
	}

	SafeInt<T> Max(SafeInt<T> test, SafeInt<T> upper = SafeInt<T>::MaxInt()) const 
	{
		T tmp = test.Value() > m_int ? test.Value() : m_int;
		return tmp > upper ? upper : tmp;
	}

	void Swap( SafeInt<T>& with )
	{
		T temp( m_int );
		m_int = with.m_int;
		with.m_int = temp;
	}

	static SafeInt<T> SafeAtoI(const char* input)
	{
		return SafeTtoI(input);
	}

	static SafeInt<T> SafeWtoI(const wchar_t* input)
	{
		return SafeTtoI(input);
	}

private:
	//note - this looks complex, but most of the conditionals 
	//are constant and optimize away
	//for example, a signed 64-bit check collapses to:
/*
	if(lhs == 0 || rhs == 0)
		return 0;

	if(MaxInt()/+lhs < +rhs)
	{
		//overflow
		throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
	}
	//ok
	return lhs * rhs;

	Which ought to inline nicely
*/
	static T multiply(T lhs, T rhs)
	{
		if(Is64Bit())
		{
			//fast track this one - and avoid DIV_0 below
			if(lhs == 0 || rhs == 0)
				return 0;

			//we're 64 bit - slow, but the only way to do it
			if(IsSigned())
			{
				if(!IsMixedSign(lhs, rhs))
				{
					//both positive or both negative
					//result will be positive, check for lhs * rhs > MaxInt
					if(lhs > 0)
					{
						//both positive
						if(MaxInt()/lhs < rhs)
						{
							//overflow
							throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
						}
					}
					else
					{
						//both negative

						//comparison gets tricky unless we force it to positive
						//EXCEPT that -MinInt is undefined - can't be done
						//And MinInt always has a greater magnitude than MaxInt
						if(lhs == MinInt() || rhs == MinInt())
						{
							//overflow
							throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
						}

						if(MaxInt()/(-lhs) < (-rhs) )
						{
							//overflow
							throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
						}
					}
				}
				else
				{
					//mixed sign - this case is difficult
					//test case is lhs * rhs < MinInt => overflow
					//if lhs < 0 (implies rhs > 0), 
					//lhs < MinInt/rhs is the correct test
					//else if lhs > 0 
					//rhs < MinInt/lhs is the correct test
					//avoid dividing MinInt by a negative number, 
					//because MinInt/-1 is a corner case

					if(lhs < 0)
					{
						if(lhs < MinInt()/rhs)
						{
							//overflow
							throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
						}
					}
					else
					{
						if(rhs < MinInt()/lhs)
						{
							//overflow
							throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
						}
					}
				}

				//ok
				return lhs * rhs;
			}
			else
			{
				//unsigned, easy case
				if(MaxInt()/lhs < rhs)
				{
					//overflow
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
				}
				//ok
				return lhs * rhs;
			}
		}
		else if(Is32Bit())
		{
			//we're 32-bit
			if(IsSigned())
			{
				signed _int64 tmp = (signed _int64)lhs * (signed _int64)rhs;

				//upper 33 bits must be the same
				//most common case is likely that both are positive - test first
				if( (tmp & 0xffffffff80000000LL) == 0 || 
					(tmp & 0xffffffff80000000LL) == 0xffffffff80000000LL)
				{
					//this is OK
					return (T)tmp;
				}

				//overflow
				throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
				
			}
			else
			{
				unsigned _int64 tmp = (unsigned _int64)lhs * (unsigned _int64)rhs;
				if (tmp & 0xffffffff00000000ULL) //overflow
				{
					//overflow
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
				}
				return (T)tmp;
			}
		}
		else if(Is16Bit())
		{
			//16-bit
			if(IsSigned())
			{
				signed _int32 tmp = (signed _int32)lhs * (signed _int32)rhs;
				//upper 17 bits must be the same
				//most common case is likely that both are positive - test first
				if( (tmp & 0xffff8000) == 0 || (tmp & 0xffff8000) == 0xffff8000)
				{
					//this is OK
					return (T)tmp;
				}

				//overflow
				throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
			}
			else
			{
				unsigned _int32 tmp = (unsigned _int32)lhs * (unsigned _int32)rhs;
				if (tmp & 0xffff0000) //overflow
				{
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
				}
				return (T)tmp;
			}
		}
		else //8-bit
		{
			assert(Is8Bit());

			if(IsSigned())
			{
				signed _int16 tmp = (signed _int16)lhs * (signed _int16)rhs;
				//upper 9 bits must be the same
				//most common case is likely that both are positive - test first
				if( (tmp & 0xff80) == 0 || (tmp & 0xff80) == 0xff80)
				{
					//this is OK
					return (T)tmp;
				}

				//overflow
				throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
			}
			else
			{
				unsigned _int16 tmp = ((unsigned _int16)lhs) * ((unsigned _int16)rhs);

				if (tmp & 0xff00) //overflow
				{
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
				}
				return (T)tmp;
			}
		}
	}

	static inline T addition(T lhs, T rhs)
	{
		if(IsSigned())
		{
			//test for +/- combo
			if(!IsMixedSign(lhs, rhs)) 
			{
				//either two negatives, or 2 positives
				if(rhs < 0)
				{
					//two negatives
					if(lhs < (T)(MinInt() - rhs)) //remember rhs < 0
					{
						throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
					}
					//ok
				}
				else
				{
					//two positives
					if((T)(MaxInt() - lhs) < rhs)
					{
						throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
					}
					//OK
				}
			}
			//else overflow not possible
			return lhs + rhs;
		}
		else //unsigned
		{
			if((T)(MaxInt() - lhs) < rhs)
			{
				throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
				
			}
			return (lhs + rhs);
		}
	}

	static T subtraction(T lhs, T rhs)
	{
		if(IsSigned())
		{
			if(IsMixedSign(lhs, rhs)) //test for +/- combo
			{
				//mixed positive and negative
				//two cases - +X - -Y => X + Y - check for overflow against MaxInt()
				//            -X - +Y - check for overflow against MinInt()

				if(lhs >= 0) //first case
				{
					//test is X - -Y > MaxInt()
					//equivalent to X > MaxInt() - |Y|
					//Y == MinInt() creates special case
					//Even 0 - MinInt() can't be done
					//note that the special case collapses into the general case, due to the fact
					//MaxInt() - MinInt() == -1, and lhs is non-negative
					if(lhs > (T)(MaxInt() + rhs)) //remember that rhs is negative
					{
						throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
					}
					//fall through to return value
				}
				else
				{
					//second case
					//test is -X - Y < MinInt()
					//or      -X < MinInt() + Y
					//we do not have the same issues because abs(MinInt()) > MaxInt()
					if(lhs < (T)(MinInt() + rhs))
					{
						throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
					}
					//fall through to return value
				}
			}
			// else 
			//both negative, or both positive
			//no possible overflow
			return (lhs - rhs);
		}
		else
		{
			//easy unsigned case
			if(lhs < rhs)
			{
				throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
			}
			return (lhs - rhs);
		}
	}

	template <typename U>
	static SafeInt<T> MixedSizeModulus(SafeInt<T> lhs, U rhs)
	{
		//this is a simpler case than other arithmetic operations
		//first, sign of return must be same as sign of lhs
		//next, magnitude of return can never be larger than lhs

		//always test this:
		if(rhs == 0)
			throw SafeIntException(EXCEPTION_INT_DIVIDE_BY_ZERO);

		//problem cases are:
		//either T or U 32 or 64-bit unsigned, other is signed
		//signed value must be negative to create problem

		//first problem case
		//T unsigned 32-bit, U signed
		if(sizeof(T) == 4 && !SafeInt<T>::IsSigned() && 
				sizeof(U) <= 4 && SafeInt<U>::IsSigned()) 
		{
			if(rhs < 0)
				return SafeInt<T>((_int64)lhs.Value() % (_int64)rhs);
		}

		//second problem case
		//T signed <=32-bit, U unsigned 32-bit
		if(sizeof(U) == 4 && !SafeInt<U>::IsSigned() && 
				sizeof(T) <= 4 && SafeInt<T>::IsSigned())
		{
			if(lhs.Value() < 0)
				return SafeInt<T>((_int64)lhs.Value() % (_int64)rhs);
		}

		//third problem case
		//T unsigned 64-bit, U signed
		if(sizeof(T) == 8 && !SafeInt<T>::IsSigned() && 
			SafeInt<U>::IsSigned())
		{
			if(rhs < 0)
			{
				//return must be positive
				return SafeInt<T>((T)lhs.Value() % (T)(-rhs));
			}

			//else it must be safe to cast U to T
			return SafeInt<T>((T)lhs.Value() % (T)rhs);
		}

		//fourth problem case
		//T signed, U unsigned 64-bit
		if(sizeof(U) == 8 && !SafeInt<U>::IsSigned() && 
			SafeInt<T>::IsSigned())
		{
			if(lhs.Value() < 0)
			{
				//first cast -lhs to U - must fit
				//modulus operation returns type U, must fit into T (2nd cast to T)
				//negation forces to int, re-cast to T
				return SafeInt<T>((T)-(T)( ((U)(-lhs.Value())) % (U)rhs));
			}

			return SafeInt<T>((U)lhs.Value() % rhs);
		}

		//else no problem
		return SafeInt<T>(lhs.Value() % rhs);
	}

	template <typename U>
	static SafeInt<T> MixedSizeDivision(SafeInt<T> lhs, U rhs)
	{
		//first test corner cases

		if(rhs == 0)
			throw SafeIntException(EXCEPTION_INT_DIVIDE_BY_ZERO);

		//only if both are signed, check corner case
		if(SafeInt<U>::IsSigned() && SafeInt<T>::IsSigned())
		{
			//corner case where lhs = MinInt and rhs = -1
			if(lhs == SafeInt<T>::MinInt() && rhs == -1)
				throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
		}

		//it is safe to divide lhs by an arbitrary larger number
		//unless T is unsigned and U is signed

		//if both have the same sign, there is no problem
		if(SafeInt<U>::IsSigned() == SafeInt<T>::IsSigned())
		{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -