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

📄 safeint.hpp

📁 自定义HttpClient类
💻 HPP
📖 第 1 页 / 共 5 页
字号:
		}
	}
	
	//Note - the standard is arguably broken in the case of some integer
	//conversion operations
	//For example, signed char a = -1 = 0xff
	//             unsigned int b = 0xffffffff
	//if you then test if a < b, a value-preserving cast
	//is made, and you're essentially testing
	// (unsigned int)a < b == false
	//
	// I do not think this makes sense - if you perform
	// a cast to an _int64, which can clearly preserve both value and signedness
	// then you get a different and intuitively correct answer
	// IMHO, -1 should be less than 4 billion
	// If you prefer to retain the ANSI standard behavior
	// insert #define ANSI_CONVERSIONS into your source
	// Behavior differences occur in the following cases:
	// 8, 16, and 32-bit signed int, unsigned 32-bit int
	// any signed int, unsigned 64-bit int
	// Note - the signed int must be negative to show the problem

	template <typename U>
	static bool LessThan(T lhs, U rhs)
	{
#ifdef ANSI_CONVERSIONS
		return lhs < rhs;
#else
		return (SafeInt<U>(rhs) > lhs);
#endif
	}

	template <typename U>
	static bool GreaterThan(T lhs, U rhs)
	{
#ifdef ANSI_CONVERSIONS
		return lhs > rhs;
#else
		if(SafeInt<T>::IsSigned(lhs) == SafeInt<T>::IsSigned(rhs))
		{
			if(sizeof(T) > sizeof(U))
                return (T)lhs > (T)rhs;

			return (U)lhs > (U)rhs;
		}
		
		//all remaining cases are mixed sign
		if((sizeof(T) < 4 && sizeof(U) < 4) ||
		    (SafeInt<T>::IsSigned(lhs) && sizeof(T) == 4 && sizeof(U) < 4) ||
			(SafeInt<T>::IsSigned(rhs) && sizeof(U) == 4 && sizeof(T) < 4))
		{
			//all of these fit into an int
			return (_int32)lhs > (_int32)rhs;
		}

		if((SafeInt<T>::IsSigned(rhs) && sizeof(U) == 8 && sizeof(T) < 8) ||
		   (SafeInt<T>::IsSigned(lhs) && sizeof(T) == 8 && sizeof(U) < 8))
		{
			//these cases all fit into an _int64
			return (_int64)lhs > (_int64)rhs;
		}

		//for all remaining cases unsigned value is 64-bit

		//corner cases - signed value is negative
		if(SafeInt<T>::IsSigned(lhs) && lhs < 0) 
		{
			//if lhs < 0, rhs unsigned
			return false;
		}
			
		//2nd corner case
		if(SafeInt<T>::IsSigned(rhs) && rhs < 0)
		{
			//rhs < 0, lhs unsigned
			return true;
		}

		//now the signed value is positive, and must fit into a 64-bit unsigned
		return (unsigned _int64)lhs > (unsigned _int64)rhs;
#endif
	}

	template <typename U>
	static bool Equals(T lhs, U rhs)
	{
#ifdef ANSI_CONVERSIONS
		return lhs == rhs;
#else
		if(SafeInt<T>::IsSigned(lhs) == SafeInt<T>::IsSigned(rhs))
		{
			if(sizeof(T) > sizeof(U))
                return (T)lhs == (T)rhs;

			return (U)lhs == (U)rhs;
		}
		
		//all remaining cases are mixed sign
		if((sizeof(T) < 4 && sizeof(U) < 4) ||
		    (SafeInt<T>::IsSigned(lhs) && sizeof(T) == 4 && sizeof(U) < 4) ||
			(SafeInt<T>::IsSigned(rhs) && sizeof(U) == 4 && sizeof(T) < 4))
		{
			//all of these fit into an int
			return (_int32)lhs == (_int32)rhs;
		}

		if((SafeInt<T>::IsSigned(rhs) && sizeof(U) == 8 && sizeof(T) < 8) ||
		   (SafeInt<T>::IsSigned(lhs) && sizeof(T) == 8 && sizeof(U) < 8))
		{
			//these cases all fit into an _int64
			return (_int64)lhs == (_int64)rhs;
		}

		//for all remaining cases unsigned value is 64-bit
		if((SafeInt<T>::IsSigned(lhs) && lhs < 0) ||
			(SafeInt<T>::IsSigned(rhs) && rhs < 0))
		{
			//corner case - signed value is negative
			//cannot possibly be equal to the unsigned value
			return false;
		}

		//now the signed value is positive, and must fit into a 64-bit unsigned
		return (unsigned _int64)lhs == (unsigned _int64)rhs;
#endif
	}

	//this is almost certainly not the best optimized version of atoi,
	//but it does not display a typical bug where it isn't possible to set MinInt
	//and it won't allow you to overflow your integer
	//This is here because it is useful, and it is an example of what
	//can be done easily with SafeInt
	template <typename U>
	static SafeInt<T> SafeTtoI(U* input)
	{
		U* tmp  = input;
		SafeInt<T> s;
		bool negative = false;
		
		if(input == NULL || input[0] == 0)
			throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

		switch(*tmp)
		{
		case '-':
			tmp++;
			negative = true;
			break;
		case '+':
			tmp++;
			break;
		}

		while(*tmp != 0)
		{
			if(*tmp < '0' || *tmp > '9')
				break;
			
			if(s.Value() != 0)
				s *= (T)10;

			if(!negative)
				s += (T)(*tmp - '0');
			else
                s -= (T)(*tmp - '0');

			tmp++;
		}

		return s;
	}

	//internal helper functions

	//explanation - consider 2 8-bit ints:
	//  00001010
	// ^10001000
	// =10000010
	// if result is < 0, high bit is set
	//so we now have an efficient test to see if two integers
	//are the same sign or opposite signs

	static bool IsMixedSign(T lhs, T rhs)
	{
		return ((lhs ^ rhs) < 0);
	}

	T m_int;
};

//externally defined functions for the case of U op SafeInt<T>
template <typename T, typename U>
bool operator <(U lhs, SafeInt<T> rhs)
{
	return rhs > lhs;
}

template <typename T, typename U>
bool operator <(SafeInt<U> lhs, SafeInt<T> rhs)
{
	return lhs < rhs.Value();
}

//greater than
template <typename T, typename U>
bool operator >(U lhs, SafeInt<T> rhs)
{
	return rhs < lhs;
}

template <typename T, typename U>
bool operator >(SafeInt<T> lhs, SafeInt<U> rhs)
{
	return lhs > rhs.Value();
}


//greater than or equal
template <typename T, typename U>
bool operator >=(U lhs, SafeInt<T> rhs)
{
	return rhs < lhs;
}

template <typename T, typename U>
bool operator >=(SafeInt<T> lhs, SafeInt<U> rhs)
{
	return lhs >= rhs.Value();
}

//less than or equal
template <typename T, typename U>
bool operator <=(U lhs, SafeInt<T> rhs)
{
	return rhs > lhs;
}

template <typename T, typename U>
bool operator <=(SafeInt<T> lhs, SafeInt<U> rhs)
{
	return lhs <= rhs.Value();
}

//equality
//explicit overload for bool
template <typename T>
bool operator ==(bool lhs, SafeInt<T> rhs)
{
	return lhs == (rhs.Value() == 0 ? false : true);
}

template <typename T, typename U>
bool operator ==(U lhs, SafeInt<T> rhs)
{
	return rhs == lhs;
}

template <typename T, typename U>
bool operator ==(SafeInt<T> lhs, SafeInt<U> rhs)
{
	return lhs == rhs.Value();
}

//not equals
template <typename T, typename U>
bool operator !=(U lhs, SafeInt<T> rhs)
{
	return rhs != lhs;
}

template <typename T>
bool operator !=(bool lhs, SafeInt<T> rhs)
{
	return (rhs.Value() == 0 ? false : true) != lhs;
}

template <typename T, typename U>
bool operator !=(SafeInt<T> lhs, SafeInt<U> rhs)
{
	return lhs != rhs.Value();
}

//modulus
template <typename T, typename U>
SafeInt<T> operator %(U lhs, SafeInt<T> rhs)
{
	//value of return depends on sign of lhs
	//this one may not be safe - bounds check in constructor
	//if lhs is negative and rhs is unsigned, this will throw an exception

	//fast-track the simple case
	if(sizeof(T) == sizeof(U) &&
		SafeInt<T>::IsSigned() == SafeInt<U>::IsSigned())
	{
		if(rhs == 0)
			throw SafeIntException(EXCEPTION_INT_DIVIDE_BY_ZERO);

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

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

//multiplication
template <typename T, typename U> 
SafeInt<T> operator *(U lhs, SafeInt<T> rhs)
{
	return rhs * lhs;
}

//division
template <typename T, typename U> SafeInt<T> operator /(U lhs, SafeInt<T> rhs)
{
	//no easy way out - cannot make lhs into a SafeInt, then convert
	//or cases of lhs unsigned, rhs < 0 become illegal which is wrong
	//first test corner cases

	if(rhs.Value() == 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<U>::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
	//though there could be an overflow - do not cast result to T
	if(SafeInt<U>::IsSigned() == SafeInt<T>::IsSigned())
	{
		return SafeInt<T>(lhs/rhs.Value());
	}
	
	//now we have mixed sign case, which can lead to problems
	//first consider T signed, U unsigned

	if(SafeInt<T>::IsSigned())
	{
		if(sizeof(U) < sizeof(T))
		{
			//simply upcast to T - lhs always fits into T
			return SafeInt<T>(((T)lhs)/rhs.Value());
		}

		if(sizeof(U) < 4 && sizeof(T) < 4)
		{
			//even if U is bigger, upcast to int
			return SafeInt<T>((_int32)lhs/(_int32)rhs.Value());
		}

		//now U is either 32 or 64-bit, T same size or smaller
		if(sizeof(U) == 4)
		{
			//upcast to 64-bit
			return SafeInt<T>((_int64)lhs/(_int64)rhs.Value());
		}

		//U is unsigned _int64
		//now it matters whether rhs < 0
		if(rhs.Value() < 0)
		{
			U tmp = lhs/((U)-rhs.Value());
			if(tmp == (U)SafeInt<T>::MaxInt()+1)
				return SafeInt<T>(SafeInt<T>::MinInt());

			//else tmp is too big, or can be negated
			return SafeInt<T>(-(SafeInt<T>(tmp)));
		}

		//rhs >= 0
		//T now has to fit into U
		return SafeInt<T>((U)lhs/(U)rhs.Value());
	}

	//now lhs is signed, rhs unsigned - return must be unsigned
	if(lhs < 0)
		throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

	if(sizeof(T) >= sizeof(U))
	{
		//all U fits into T
		return SafeInt<T>((T)lhs/rhs.Value());
	}
		
	//now sizeof(U) > sizeof(T) and rhs >= 0
	//all T fits into U
	return SafeInt<T>(lhs/(U)rhs.Value());
}

//addition
template <typename T, typename U>
SafeInt<T> operator +(U lhs, SafeInt<T> rhs)
{
	return rhs + lhs;
}

//subtraction
template <typename T, typename U>
SafeInt<T> operator -(U lhs, SafeInt<T> rhs)
{
	if(rhs.IsSigned())
	{
		if(SafeInt<U>::IsSigned())
		{
			//both are signed
			if(sizeof(T) >= sizeof(U))
				return SafeInt<T>(lhs) - rhs;
			//else
			return SafeInt<T>(SafeInt<U>(lhs) - rhs.Value());
		}

		//lhs is unsigned, rhs is signed
		if(sizeof(T) > sizeof(U))
			return SafeInt<T>(lhs) - rhs;

		//U is >= T - not all values of U fit into T
		if(sizeof(U) < 4)
		{
			//upcast to int
			return SafeInt<T>((_int32)lhs - (_int32)rhs.Value());
		}

		if(sizeof(U) == 4)
		{
			//upcast to _int64
			return SafeInt<T>((_int64)lhs - (_int64)rhs.Value());
		}

		if(sizeof(U) == 8)
		{
			//lhs - unsigned _int64
			//rhs - signed int - any size

			if(sizeof(T) < 8)
			{
				//if this is true, the result can never fit into T
				if(lhs > ((U)2 * (U)SafeInt<T>::MaxInt()))
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

				//everything has to be able to fit into an _int64
				return SafeInt<T>((_int64)lhs - (_int64)rhs.Value());
			}

			//now rhs is _int64

			//if rhs is > 0, upcast to U
			if(rhs.Value() >= 0)
				return SafeInt<T>(SafeInt<U>(lhs) - rhs.Value());

			//if rhs < 0, treat as addition
			//unboxing everything maintains correctness, even if rhs = MinInt
			return SafeInt<T>(SafeInt<U>(lhs) + SafeInt<U>((U)((T)-rhs.Value())) );
		}
	}

	//T is unsigned
	//this means that if lhs < 0, result is an error
	if(SafeInt<T>::IsSigned(lhs) && lhs < 0)
		throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

	//whether T is signed or not, it is non-negative
	//if U fits in T, no problem
	if(sizeof(T) >= sizeof(U))
	{
		return SafeInt<T>(lhs) - rhs;
	}

	//sizeof(T) < sizeof(U)
	//T fits in U, whether U is signed or unsigned
	return SafeInt<T>(SafeInt<U>(lhs) - rhs.Value());
}

//shift operators
//NOTE - shift operators always return the type of the lhs argument

//left shift
template <typename T, typename U>
SafeInt<U> operator <<(U lhs, SafeInt<T> bits)
{
	if(bits.IsSigned())
        assert(bits.Value() >= 0);

	assert(bits.Value() < SafeInt<U>::BitCount());

	return SafeInt<U>((U)(lhs << bits.Value()));
}

//right shift
template <typename T, typename U>
SafeInt<U> operator >>(U lhs, SafeInt<T> bits)
{
	if(bits.IsSigned())
        assert(bits.Value() >= 0);

	assert(bits.Value() < SafeInt<U>::BitCount());

	return SafeInt<U>((U)(lhs >> bits.Value()));
}

//bi

⌨️ 快捷键说明

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