Click here to Skip to main content
15,881,715 members
Articles / Desktop Programming / MFC

CHttpClient - A Helper Class Using WinInet

Rate me:
Please Sign up or sign in to vote.
4.96/5 (59 votes)
10 Aug 20073 min read 485K   24.8K   163  
A C++ class which helps you to interact with a HTTP web server.
/*---------------------------------------------------------------

THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Copyright (C) 2003.  Microsoft Corporation.  All rights reserved.

SafeInt.hpp

This header implements an integer handling class designed to catch
unsafe integer operations

This header compiles properly at warning level 4.

Please read the leading comments before using the class.

Version 1.0.3
---------------------------------------------------------------*/
#ifndef SAFEINT_HPP
#define SAFEINT_HPP

#include <assert.h>

/*
*  The SafeInt class is designed to have as low an overhead as possible
*  while still ensuring that all integer operations are conducted safely.
*  Nearly every operator has been overloaded, with a very few exceptions.
*
*  A usability-safety trade-off has been made to help ensure safety. This 
*  requires that every operation return either a SafeInt or a bool. If we 
*  allowed an operator to return a base integer type T, then the following 
*  can happen:
*  
*  char i = SafeInt<char>(32) * 2 + SafeInt<char>(16) * 4;
*
*  The * operators take precedence, get overloaded, return a char, and then 
*  you have:
*
*  char i = (char)64 + (char)64; //overflow!
*  
*  This situation would mean that safety would depend on usage, which isn't
*  acceptable. The problem that this leaves us with is that you'd like to be able 
*  to do something like:
*
*  void* ptr = malloc(SafeInt<unsigned short>(23) * SafeInt<unsigned short>(HowMany));
*
*  and have it be a safe operation. The way out of this is to use the following type of
*  construct:
*
*   SafeInt<int> s = 1, s1 = 2;
*  	int	m = (s | s1).Value();
*
*  A little clunky, and less programmer-friendly than would be ideal, but it is safe.
*
*  One key operator that is missing is an implicit cast. The reason for
*  this is that if there is an implicit cast operator, then we end up with
*  an ambiguous compile-time precedence. Because of this amiguity, there
*  are two methods that are provided:
*
*  SafeInt::Value() - returns the value of the object as an integer
*  SafeInt::Ptr()   - returns the address of the internal integer
*  Note - the '&' (address of) operator has been overloaded and returns
*         the address of the internal integer.
*
*  The SafeInt class should be used in any circumstances where ensuring
*  integrity of the calculations is more important than performance. See Performance
*  Notes below for additional information. 
*
*  Many of the conditionals will optimize out or be inlined for a release
*  build (especially with /Ox), but it does have significantly more overhead, 
*  especially for signed numbers. If you do not _require_ negative numbers, use 
*  unsigned integer types - certain types of problems cannot occur, and this class
*  performs most efficiently.
*
*  Here's an example of when the class should ideally be used -
*
*  void* AllocateMemForStructs(int StructSize, int HowMany)
*  {
*     SafeInt<unsigned long> s(StructSize);
*
*     s *= HowMany;
*
*     return malloc(s.Value());
*
*  }
*
*  Here's when it should NOT be used:
*
*  void foo()
*  {
*    int i;
*
*    for(i = 0; i < 0xffff; i++)
*      ....
*  }
*
*  Error handling - a SafeInt class will throw exceptions if something
*  objectionable happens. The exceptions are SafeIntException classes,
*  which contain one signed long as a code (for compatability with Windows
*  errors). The values that may be assigned currently are:
*
*  ERROR_ARITHMETIC_OVERFLOW
*  EXCEPTION_INT_DIVIDE_BY_ZERO
*
*  Typical usage might be:
*
*  bool foo()
*  {
*    SafeInt<unsigned long> s; //note that s == 0 unless set
*
*    try{
*      s *= 23;
*      ....
*    }
*    catch(SafeIntException err)
*    {
*       //handle errors here
*    }
*  }
*
*  Performance:
*
*  Due to the highly nested nature of this class, you can expect relatively poor
*  performance in unoptimized code. In tests of optimized code vs. correct inline checks
*  in native code, this class has been found to take approximately 8% more CPU time,
*  most of which is due to exception handling. Solutions:
*
*  1) Compile optimized code - /Ox is best, /O2 also performs well. Interestingly, /O1
*     (optimize for size) does not work as well. 
*  2) If that 8% hit is really a serious problem, walk through the code and inline the
*     exact same checks as the class uses.
*  3) Some operations are more difficult than others - avoid using signed integers, and if
*     possible keep them all the same size. 64-bit integers are also expensive. Mixing 
*     different integer sizes and types may prove expensive. Be aware that literals are
*     actually ints. For best performance, cast them to the type desired.
*
*
*  Binary Operators
*  
*  All of the binary operators have certain assumptions built into the class design. 
*  This is to ensure correctness. Notes on each class of operator follow:
*  
*  Arithmetic Operators (*,/,+,-,%)
*  There are three possible variants:
*  SafeInt<T> op SafeInt<T>
*  SafeInt<T> op U
*  U op SafeInt<T>
*  
*  The SafeInt<T> op SafeInt<U> variant is explicitly not supported, and if you try to do 
*  this the compiler with throw the following error:
*  
*  error C2593: 'operator *' is ambiguous
*  
*  This is because the arithmetic operators are required to return a SafeInt of some type. 
*  The compiler cannot know whether you'd prefer to get a type T or a type U returned. If 
*  you need to do this, you need to extract the value contained within one of the two using 
*  the SafeInt::Value() method. For example:
*  
*  SafeInt<T> t, result;
*  SafeInt<U> u;
*  
*  result = t * u.Value();
*  
*  Comparison Operators
*  Because each of these operators return type bool, mixing SafeInts of differing types is 
*  allowed.
*  
*  Shift Operators
*  Shift operators always return the type on the left hand side of the operator. Mixed type 
*  operations are allowed because the return type is always known.
*  
*  Boolean Operators
*  Like comparison operators, these overloads always return type bool, and mixed-type SafeInts 
*  are allowed. Additionally, specific overloads exist for type bool on both sides of the 
*  operator.
*  
*  Binary Operators
*  Mixed-type operations are discouraged, however some provision has been made in order to 
*  enable things like:
*  
*  SafeInt<char> c = 2;
*  
*  if(c & 0x02)
*    ...
*  
*  The "0x02" is actually an int, and it needs to work. The rule is that if the non-SafeInt type 
*  can be cast to the type of the SafeInt, and back to the original type without losing any 
*  significant bits then the operation is allowed.
*  
*  
*  Documented issues:
*
*  This header compiles correctly at /W4 using VC++ 7.1 (Version 13.10.3077). 
*  It is strongly recommended that any code doing integer manipulation be compiled at /W4 
*  - there are a number of warnings which pertain to integer manipulation enabled that are 
*  not enabled at /W3 (default for VC++)
*
*  Perf note - postfix operators are slightly more costly than prefix operators.
*  Unless you're actually assigning it to something, ++SafeInt is less expensive than SafeInt++
*
*  The comparison operator behavior in this class varies from the ANSI definition, which is 
*  arguably broken. As an example, consider the following:
*  
*  unsigned int l = 0xffffffff;
*  char c = -1;
*  
*  if(c == l)
*    printf("Why is -1 equal to 4 billion???\n");
*  
*  The problem here is that c gets cast to an int, now has a value of 0xffffffff, and then gets 
*  cast again to an unsigned int, losing the true value. This behavior is despite the fact that
*  an _int64 exists, and the following code will yield a different (and intuitively correct)
*  answer:
*  
*  if((_int64)c == (_int64)l))
*    printf("Why is -1 equal to 4 billion???\n");
*  else
*    printf("Why doesn't the compiler upcast to 64-bits when needed?\n");
*  
*  Note that combinations with smaller integers won't display the problem - if you 
*  changed "unsigned int" above to "unsigned short", you'd get the right answer.
*
*  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
*  
*  
*  Revision history:
*
*  Oct 12, 2003 - Created
*  Author - David LeBlanc - dleblanc@microsoft.com
*
*  Oct 27, 2003 - fixed numerous items pointed out by michmarc and bdawson
*  Dec 28, 2003 - 1.0
*                 added support for mixed-type operations
*                 thanks to vikramh
*                 also fixed broken _int64 multiplication section
*                 added extended support for mixed-type operations where possible
*  Jan 28, 2004 - 1.0.1
*                 changed WCHAR to wchar_t
*                 fixed a construct in two mixed-type assignment overloads that was 
*                 not compiling on some compilers
*                 Also changed name of private method to comply with standards on 
*                 reserved names
*                 Thanks to Niels Dekker for the input
*  Feb 12, 2004 - 1.0.2
*                 Minor changes to remove dependency on Windows headers
*                 Consistently used _int16, _int32 and _int64 to ensure
*                 portability
*  May 10, 2003 - 1.0.3
*                 Corrected bug in one case of GreaterThan
*                 
*/

#pragma warning(push)
//this avoids warnings from the unary '-' operator being applied to unsigned numbers
//the overload itself resolves to nothing for the unsigned case
#pragma warning(disable:4146)
// conditional expression is constant - these are used intentionally
#pragma warning(disable:4127)

//use these if the compiler does not support _intXX
#ifdef NEEDS_INT_DEFINED
#define _int16 short
#define _int32 long
#define _int64 long long
#endif

/* catch these to handle errors
** Currently implemented code values:
** ERROR_ARITHMETIC_OVERFLOW
** EXCEPTION_INT_DIVIDE_BY_ZERO
*/

#ifndef ERROR_ARITHMETIC_OVERFLOW
#define ERROR_ARITHMETIC_OVERFLOW 534L
#endif

#ifndef EXCEPTION_INT_DIVIDE_BY_ZERO
#define EXCEPTION_INT_DIVIDE_BY_ZERO ((unsigned _int32)0xC0000094L)
#endif

class SafeIntException
{
public:
	SafeIntException(){m_code = 0;}
	SafeIntException(_int32 code)
	{
		m_code = code;
	}
	_int32 m_code;
};

template<typename T> class SafeInt
{
public:
	SafeInt()
	{
		m_int = 0;
	}

	//Having a constructor for every type of int 
	//avoids having the compiler evade our checks when doing implicit casts - 
	//e.g., SafeInt<char> s = 0x7fffffff;
	SafeInt(T i)
	{
		//always safe
		m_int = i;
	}

	//provide explicit boolean converter
	SafeInt(bool b)
	{
		m_int = b ? 1 : 0;
	}

	template <typename U> SafeInt(SafeInt<U> u)
	{
		*this = SafeInt<T>(u.Value());
	}

	template <typename U> SafeInt(U i)
	{
		//use signed-unsigned test on U
		if(SafeInt<U>::IsSigned())
		{
			//U is signed
			//whether T is signed or unsigned, must test range if sizeof T is smaller 
			//than sizeof U
			//if sizeof(T) >= sizeof(U) this optimizes out, only test for negative
			//for completely safe cases, optimizes to NOOP
			if(sizeof(T) < sizeof(U))
			{
				//test size
				if(i > (U)SafeInt<T>::MaxInt() || i < (U)SafeInt<T>::MinInt())
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
			}
			else //test +/- for sizeof(T) >= sizeof(U) and T unsigned
			if(!IsSigned())
			{
				if(i < 0)
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
			}
		}
		else
		{
			//U is unsigned
			//if sizeof T <= sizeof U AND T is signed,
			//test upper bound because MaxInt(unsigned) > MaxInt(signed)
			//OR
			//if sizeof T < sizeof U and T is unsigned
			if((IsSigned() && sizeof(T) <= sizeof(U)) ||
			(!IsSigned() && sizeof(T) < sizeof(U)) )
			{
				if(i > (U)MaxInt())
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
			}	
		}

		m_int = (T)i;
	}

	~SafeInt(){};

	//helpful methods
	//these compile down to something as efficient as macros and allow run-time testing 
	//of type by the developer

	template <typename U> static bool IsSigned(SafeInt<U>)
	{
		return( (U)-1 < 0 );
	}

	template <typename U> static bool IsSigned(U)
	{
		return( (U)-1 < 0 );
	}

	static bool IsSigned()
	{
		return( (T)-1 < 0 );
	}

	static unsigned char BitCount(){return (sizeof(T)*8);}
	template <typename U> static unsigned char BitCount(U){return (sizeof(U)*8);}

	static bool Is64Bit(){return sizeof(T) == 8;}
	static bool Is32Bit(){return sizeof(T) == 4;}
	static bool Is16Bit(){return sizeof(T) == 2;}
	static bool Is8Bit(){return sizeof(T) == 1;}

	template <typename U> static bool Is64Bit(U){return sizeof(U) == 8;}
	template <typename U> static bool Is32Bit(U){return sizeof(U) == 4;}
	template <typename U> static bool Is16Bit(U){return sizeof(U) == 2;}
	template <typename U> static bool Is8Bit(U){return sizeof(U) == 1;}

	//both of the following should optimize away
	static T MaxInt()
	{
		if(IsSigned())
		{
			return (T)~((T)1 << (BitCount()-1));
		}
		//else
		return (T)(~(T)0);
	}

	static T MinInt()
	{
		if(IsSigned())
		{
			return (T)((T)1 << (BitCount()-1));
		}
		else
		{
			return ((T)0);
		}
	}

	//now start overloading operators
	//assignment operator
	//constructors exist for all int types and will ensure safety

	template <typename U> inline SafeInt<T>& operator =(U rhs)
	{
		//use constructor to test size
		//constructor is optimized to do minimal checking based
		//on whether T can contain U
		*this = SafeInt<T>(rhs);
		return *this;
	}

	inline SafeInt<T>& operator =(T rhs)
	{
		m_int = rhs;
		return *this;
	}

	template <typename U> inline SafeInt<T>& operator =(SafeInt<U> rhs)
	{
		*this = SafeInt<T>(rhs.Value());
		return *this;
	}

	inline SafeInt<T>& operator =(SafeInt<T> rhs)
	{
		m_int = rhs.m_int;
		return *this;
	}

	//casting operator not implemented
	//because it causes ambiguous compilation

	//Use the methods below to gain access to the data
	T Value() const {return m_int;}
	//and if you need a pointer to the data
	//this could be dangerous, but allows you to correctly pass
	//instances of this class to APIs that take a pointer to an integer
	//also see overloaded address-of operator below
	T* Ptr(){return &m_int;}
	const T* Ptr() const {return &m_int;}

	//or if SafeInt<T>::Ptr() is inconvenient, use the overload
	// operator & 
	//This allows you to do unsafe things!
	//It is meant to allow you to more easily
	//pass a SafeInt into things like ReadFile
	T* operator &(){return &m_int;}
	const T* operator &() const {return &m_int;}

	//unary operators
	bool operator !() const {return (!m_int) ? true : false;}
	
	//operator + (unary) 
	//note - normally, the '+' and '-' operators will upcast to a signed int
	//for T < 32 bits. This class changes behavior to preserve type
	SafeInt<T> operator +(void) const { return *this; };

	//unary  - 
		
	SafeInt<T> operator -() const
	{
		if(IsSigned())
		{
			//corner case
			if(m_int == MinInt())
				throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

			//cast improves perf in the case of small ints
			return SafeInt<T>((T)-m_int);
		}
		//no-op for unsigned - generates warning 4146 at warning levels 2 and above
		return SafeInt<T>((T)-m_int);
	}

	//prefix increment operator
	SafeInt<T>& operator ++()
	{
		if(m_int == MaxInt())
		{
			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> 
	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())
		{
			if(sizeof(T) >= sizeof(U))
				return SafeInt<T>((T)((T)lhs.Value()/(T)rhs));

			return SafeInt<T>((T)((U)lhs.Value()/(U)rhs));
		}
		
		//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 - rhs always fits into T
				return SafeInt<T>((T)(lhs.Value()/(T)rhs));
			}

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

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

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

				//corner case
				if(lhs.Value() == SafeInt<T>::MinInt() &&
					rhs == (U)SafeInt<T>::MaxInt() + 1)
				{
					return SafeInt<T>((T)-1);
				}

				//finally, rhs fits into T - just cast
				return SafeInt<T>((T)(lhs.Value()/(T)rhs));
			}

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

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

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

	template <typename U> 
	static SafeInt<T> MixedSizeAddition(SafeInt<T> lhs, U rhs)
	{
		if(SafeInt<T>::IsSigned() == SafeInt<U>::IsSigned())
		{
			//easy case - just upcast U to T
			if(sizeof(T) >= sizeof(U))
			{
				return SafeInt<T>(addition(lhs.Value(), (T)rhs));
			}

			//otherwise, U > T
			//where possible, do the upcast inline
			//this avoids range checks inside the addition call
			//and additional range checks on assignment
			if(sizeof(U) == 2)
			{
				//an int can hold any possible range of _int16 + char
				//do bounds checking in constructor
				if(IsSigned())
					return SafeInt<T>((_int32)lhs.Value() + (_int32)rhs);
				//else unsigned

				return SafeInt<T>((unsigned _int32)lhs.Value() + (unsigned _int32)rhs);
			}

			if(sizeof(U) == 4)
			{
				//it is possibly overkill to go to 64-bit, but other alternatives
				//involve more conditionals. This is likely cheaper overall
				if(IsSigned())
					return SafeInt<T>((_int64)lhs.Value() + (_int64)rhs);

				return SafeInt<T>((unsigned _int64)lhs.Value() + (unsigned _int64)rhs);
			}

			//else U is an _int64
			//this will have to be done the expensive way
			{
				return SafeInt<T>(SafeInt<U>(lhs.Value()) + rhs); //more checking here
			}
		}

		//else mixed sign
		//first consider the case of signed T, unsigned U
		if(SafeInt<T>::IsSigned())
		{
			if(sizeof(T) > sizeof(U))
			{
				//piece of cake, U fits in T
				return SafeInt<T>(addition(lhs.Value(), (T)rhs));
			}

			//else sizeof(T) <= sizeof(U)
			if(sizeof(U) < 4)
			{
				//upcast to int, which is what the compiler normally does
				//catch overflows in the constructor
				return SafeInt<T>((_int32)lhs.Value() + (_int32)rhs);
			}

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

			//else U is unsigned 64-bit
			//this will have to be done the expensive way
			//this particular part of the problem is especially
			//difficult - the result has to fit correctly into a signed int[8|16|32]
			//lhs input could be negative
			//rhs input greater than an _int64 MAX_INT could be legal
			if(sizeof(T) < 4)
			{
				//test if rhs is even possibly legal
				if((unsigned _int64)rhs > (unsigned _int64)SafeInt<unsigned _int16>::MaxInt())
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

				//stuff them all into an int, return
				return SafeInt<T>((_int32)lhs.Value() + (_int32)rhs);
			}
			else
			if(sizeof(T) == 4)
			{
				//you can't possibly add more than 0xFFFFFFFF
				//to a signed int and have it work, so
				if((unsigned _int64)rhs > (unsigned _int64)SafeInt<unsigned _int32>::MaxInt())
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

				//now that we know that rhs fits into an unsigned _int32
				//result must fit into an _int64
				return SafeInt<T>((_int64)lhs.Value() + (_int64)rhs);
			}
			else
			{
				//T == signed _int64
				if(lhs.Value() >= 0)
				{
					//they both need to fit into an _int64
					//given that lhs is positive, rhs must be <= _int64 MaxInt
					if((unsigned _int64)rhs > (unsigned _int64)SafeInt<_int64>::MaxInt())
						throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
					
					return SafeInt<T>(addition((T)lhs.Value(), (T)rhs));
				}

				//else rhs could range all the way up to a unsigned _int64 MAX_INT
				//rearrange as rhs - (-lhs)
				//this still works even if lhs == _int64 MIN_INT
				return SafeInt<T>(rhs - (unsigned _int64)(-(lhs.Value())));
			}
		}

		//now we have the case of unsigned T, signed U
		//we just solved this problem above - since A+B == B+A
		//code is largely duplicated, but there are optimizations
		//remember that U could be negative

		if(sizeof(T) < 4 && sizeof(U) < 4)
		{
			//upcast to int, which is what the compiler normally does
			//catch overflows in the constructor
			return SafeInt<T>((_int32)lhs.Value() + (_int32)rhs);
		}

		if(sizeof(T) < 8 && sizeof(U) < 8)
		{
			//either T or U are 32-bit
			//all possible combinations fit into an _int64
			return SafeInt<T>((_int64)lhs.Value() + (_int64)rhs);
		}

		if(sizeof(U) == 8 && sizeof(T) < 8)
		{
			//all possible values of T fit into an _int64
			SafeInt<U> u(rhs);
			u += (_int64)lhs.Value();
			return SafeInt<T>(u.Value());
		}

		//else T is unsigned 64-bit
		//this will have to be done the expensive way
		//rhs input could be negative
		if(rhs >= 0)
		{
			//all possible values of rhs can fit into an unsigned _int64
			return SafeInt<T>(addition(lhs.Value(), (T)rhs));
		}

		//rhs is negative
		if((T)(-rhs) > lhs.Value()) //this will never work
			throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

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

	template <typename U> 
	static SafeInt<T> MixedSizeSubtraction(SafeInt<T> lhs, U rhs)
	{
		if(SafeInt<T>::IsSigned() == SafeInt<U>::IsSigned())
		{
			//easy case - just upcast U to T
			if(sizeof(T) >= sizeof(U))
				return SafeInt<T>(subtraction(lhs.Value(), (T)rhs));

			//otherwise, U > T
			if(sizeof(U) == 2)
			{
				//an int can hold any possible range of _int16 - char
				//do bounds checking in constructor
				if(IsSigned())
					return SafeInt<T>((_int32)lhs.Value() - (_int32)rhs);
				//else unsigned

				return SafeInt<T>((unsigned _int32)lhs.Value() - (unsigned _int32)rhs);
			}

			if(sizeof(U) == 4)
			{
				//it is possibly overkill to go to 64-bit, but other alternatives
				//involve more conditionals. This is likely cheaper overall
				if(IsSigned())
					return SafeInt<T>((_int64)lhs.Value() - (_int64)rhs);

				return SafeInt<T>((unsigned _int64)lhs.Value() - (unsigned _int64)rhs);
			}

			//else U is a signed or unsigned _int64
			//this will have to be done the expensive way
			{
				return SafeInt<T>(SafeInt<U>(lhs.Value()) - rhs); //more checking here
			}
		}

		//else mixed sign
		//first consider the case of signed T, unsigned U
		if(IsSigned())
		{
			if(sizeof(T) > sizeof(U))
			{
				//piece of cake, U fits in T
				return SafeInt<T>(subtraction(lhs.Value(), (T)rhs));
			}

			//else sizeof(T) <= sizeof(U)
			if(sizeof(U) < 4)
			{
				//upcast to int, which is what the compiler normally does
				//catch overflows in the constructor
				return SafeInt<T>((_int32)lhs.Value() - (_int32)rhs);
			}

			if(sizeof(U) == 4)
			{
				//upcast to _int64, which is what the compiler should do
				return SafeInt<T>((_int64)lhs.Value() - (_int64)rhs);
			}

			//else U is unsigned 64-bit
			//this will have to be done the expensive way
			//this particular part of the problem is especially
			//difficult - the result has to fit correctly into a signed int[8|16|32]
			//lhs input could be negative, rhs input is always positive
			if(sizeof(T) < 4)
			{
				//test if rhs is even possibly legal
				if(rhs > (U)SafeInt<unsigned _int16>::MaxInt())
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

				//stuff them all into an int, return
				return SafeInt<T>((_int32)lhs.Value() - (_int32)rhs);
			}
			else
			if(sizeof(T) == 4)
			{
				//you can't possibly subtract more than 0xFFFFFFFF
				//from a signed int and have it work, so
				if(rhs > (U)SafeInt<unsigned _int32>::MaxInt())
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

				return SafeInt<T>((_int64)lhs.Value() - (_int64)rhs);
			}
			else
			{
				//T = signed _int64
				//U = unsigned _int64

				//need the size of the range between lhs.MinInt and lhs
				//this is the maximum value that can be subtracted from lhs
				//we're actually going to take advantage of rollover
				if(rhs > (U)(lhs.Value() - SafeInt<T>::MinInt()))
					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

				//else it has to work
				return SafeInt<T>((T)(lhs.Value() - rhs));
			}
		}

		//now we have the case of unsigned T, signed U
		
		//easily deals with 1/4 of the problem space
		if(sizeof(T) < 4 && sizeof(U) < 4)
		{
			//stuff them all into an int, return
			return SafeInt<T>((_int32)lhs.Value() - (_int32)rhs);
		}
		else
		if(sizeof(T) < 8 && sizeof(U) < 8)
		{
			//handles another 5 of 16 cases
			return SafeInt<T>((_int64)lhs.Value() - (_int64)rhs);
		}

		//case of T = unsigned _int64
		//handles 4 more cases
		if(sizeof(T) == 8)
		{
			//has to work - rhs has to fit into a T
			if(rhs >= 0)
				return SafeInt<T>(subtraction(lhs.Value(), (T)rhs));

			//rhs negative - turn into an addition
			//take care to do an intermediate cast because the
			//unary negation operator returns an int
			//corner case of MinInt still works
			return SafeInt<T>(addition(lhs.Value(), (T)((U)-rhs)));
		}

		//sizeof T < 8, sizeof U == 8
		//maximum possible range for rhs is lhs - MinInt(T)
		//because sizeof T smaller than _int64, upcast
		if(rhs > (U)((_int64)lhs.Value() - (_int64)lhs.MinInt()))
			throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

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

	template <typename U> 
	static SafeInt<T> MixedSizeMultiply(SafeInt<T> lhs, U rhs)
	{
		//what is U?
		//if T is unsigned, and sizeof(T) >= sizeof(U)
		//T can hold all values of U for rhs > 0
		//if T is unsigned and sizeof(T) < sizeof(U)
		//declare an unsigned SafeInt of same size as U

		//if T is signed and sizeof(T) > sizeof(U)
		//T can hold all values of U
		//if T is signed and sizeof(T) <= sizeof(U)
		//declare a signed SafeInt of same size as U

		if(SafeInt<T>::IsSigned() == SafeInt<U>::IsSigned())
		{
			//simple case - same signedness and U always fits in T
			if(sizeof(T) >= sizeof(U))
			{
				return SafeInt<T>(multiply(lhs.Value(), (T)rhs));
			}

			//simple case - same signedness and U bigger than T
			//looks like a lot of code, but is compile-time constants
			//must handle signed and unsigned in different cases - unless sizeof(U) == 8

			if(sizeof(U) == 8)
			{
				SafeInt<U> u(rhs);
				u *= lhs.m_int;
				return SafeInt<T>(u.Value());
			}

			if(SafeInt<T>::IsSigned())
			{
				if(sizeof(U) < 4)
				{
					//the result must always fit into an int
					return SafeInt<T>((_int32)((_int32)lhs.m_int * (_int32)rhs));
				}

				//result must fit into an _int64
				return SafeInt<T>((_int64)((_int64)lhs.m_int * (_int64)rhs));
			}

			//else unsigned
			if(sizeof(U) < 4)
			{
				//the result must always fit into an int
				return SafeInt<T>((unsigned _int32)((unsigned _int32)lhs.m_int * (unsigned _int32)rhs));
			}

			//result must fit into an _int64
			return SafeInt<T>((unsigned _int64)((unsigned _int64)lhs.m_int * (unsigned _int64)rhs));
		}

		//mixed sign - consider T is signed, U unsigned
		if(SafeInt<T>::IsSigned() && !SafeInt<U>::IsSigned())
		{
			//if T > U, we're OK
			if(sizeof(T) > sizeof(U))
			{
				return SafeInt<T>(multiply(lhs.Value(), (T)rhs));
			}

			//else sizeof(T) <= sizeof(U) - upcast T to signed U
			//otherwise, we have to make an signed next size up from U
			if(sizeof(U) < 4)
			{
				//T is a signed char or _int16, U is unsigned _int16 or char
				//this must also always fit into an int
				return SafeInt<T>((_int32)((_int32)lhs.m_int * (_int32)rhs));
			}
			else if(sizeof(U) == 4)
			{
				//T is signed int or smaller, U is unsigned int
				//result must fit into an _int64
				return SafeInt<T>((_int64)((_int64)lhs.m_int * (_int64)rhs));
			}
			else
			{
				//U is unsigned 64-bit

				//now if rhs > MaxInt(T), overflow unless lhs == 0
				//or the corner case
				if(rhs > (U)SafeInt<T>::MaxInt())
				{
					//corner case -1 * (MaxInt + 1) = MinInt
					//do lhs comparison first, since is cheaper than 64-bit test
					if(lhs.Value() == -1 && ((U)SafeInt<T>::MaxInt()+1) == rhs)
						return SafeInt<T>(SafeInt<T>::MinInt());

					if(lhs.Value() == 0)
						return SafeInt<T>(0);

					throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
				}

				//now rhs must fit into T
				return SafeInt<T>(multiply(lhs.Value(), (T)rhs));
			}
		}

		//now mixed sign where T is unsigned, U signed
			
		//negative numbers are always bad
		//test here to avoid having to test in constructors below
		//also allows some simplifying assumptions
		if(rhs < 0)
			throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

		if(sizeof(T) >= sizeof(U))
		{
			return SafeInt<T>(multiply(lhs.Value(), (T)rhs));
		}

		//U > T
		//else there is no corner case, but we do have to check overflow
		if(sizeof(U) < 4)
		{
			//both U and T can be contained in an unsigned int
			return SafeInt<T>((unsigned _int32)((unsigned _int32)lhs.m_int * (unsigned _int32)rhs));
		}
		else if(sizeof(U) == 4)
		{
			//now go up to 64-bit
			return SafeInt<T>((unsigned _int64)((unsigned _int64)lhs.m_int * (unsigned _int64)rhs));
		}
		else
		{
			//U = signed _int64, T = unsigned [char|_int16|int]
			SafeInt<U> u(rhs);
			u *= lhs.Value();

			//now bounds check
			if(u.Value() > (U)SafeInt<T>::MaxInt())
				throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);

			//it has to be safe, since rhs is non-negative
			return SafeInt<T>((T)u.Value());
		}
	}
	
	//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()));
}

//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 &
template <typename T, typename U>
SafeInt<T> operator &(U lhs, SafeInt<T> rhs)
{
	//if U can fit into T without truncating, force U to T
	return SafeInt<T>(SafeInt<T>(lhs) & rhs.Value());
}

//bitwise XOR
template <typename T, typename U>
SafeInt<T> operator ^(U lhs, SafeInt<T> rhs)
{
	return SafeInt<T>(SafeInt<T>(lhs) ^ rhs.Value());
}

//bitwise OR
template <typename T, typename U>
SafeInt<T> operator |(U lhs, SafeInt<T> rhs)
{
	return SafeInt<T>(SafeInt<T>(lhs) | rhs.Value());
}

//logical operators
//logical OR
template <typename T>
bool operator ||(bool lhs, SafeInt<T> rhs) 
{
	return lhs || rhs.Value();
}

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

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

//logical AND
template <typename T>
bool operator &&(bool lhs, SafeInt<T> rhs) 
{
	return lhs && rhs.Value();
}

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

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

#pragma warning(pop)


#endif //SAFEINT_HPP

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer
Korea (Republic of) Korea (Republic of)
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions