1 /***
2 *safeint.h - SafeInt class and free-standing functions used to prevent arithmetic overflows
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose:
7 *
8 * The SafeInt class is designed to have as low an overhead as possible
9 * while still ensuring that all integer operations are conducted safely.
10 * Nearly every operator has been overloaded, with a very few exceptions.
11 *
12 * A usability-safety trade-off has been made to help ensure safety. This
13 * requires that every operation return either a SafeInt or a bool. If we
14 * allowed an operator to return a base integer type T, then the following
15 * can happen:
16 *
17 * char i = SafeInt<char>(32) * 2 + SafeInt<char>(16) * 4;
18 *
19 * The * operators take precedence, get overloaded, return a char, and then
20 * you have:
21 *
22 * char i = (char)64 + (char)64; //overflow!
23 *
24 * This situation would mean that safety would depend on usage, which isn't
25 * acceptable.
26 *
27 * One key operator that is missing is an implicit cast to type T. The reason for
28 * this is that if there is an implicit cast operator, then we end up with
29 * an ambiguous compile-time precedence. Because of this amiguity, there
30 * are two methods that are provided:
31 *
32 * Casting operators for every native integer type
33 *
34 * SafeInt::Ptr() - returns the address of the internal integer
35 *
36 * The SafeInt class should be used in any circumstances where ensuring
37 * integrity of the calculations is more important than performance. See Performance
38 * Notes below for additional information.
39 *
40 * Many of the conditionals will optimize out or be inlined for a release
41 * build (especially with /Ox), but it does have significantly more overhead,
42 * especially for signed numbers. If you do not _require_ negative numbers, use
43 * unsigned integer types - certain types of problems cannot occur, and this class
44 * performs most efficiently.
45 *
46 * Here's an example of when the class should ideally be used -
47 *
48 * void* AllocateMemForStructs(int StructSize, int HowMany)
49 * {
50 * SafeInt<unsigned long> s(StructSize);
51 *
52 * s *= HowMany;
53 *
54 * return malloc(s);
55 *
56 * }
57 *
58 * Here's when it should NOT be used:
59 *
60 * void foo()
61 * {
62 * int i;
63 *
64 * for(i = 0; i < 0xffff; i++)
65 * ....
66 * }
67 *
68 * Error handling - a SafeInt class will throw exceptions if something
69 * objectionable happens. The exceptions are SafeIntException classes,
70 * which contain an enum as a code.
71 *
72 * Typical usage might be:
73 *
74 * bool foo()
75 * {
76 * SafeInt<unsigned long> s; //note that s == 0 unless set
77 *
78 * try{
79 * s *= 23;
80 * ....
81 * }
82 * catch(SafeIntException err)
83 * {
84 * //handle errors here
85 * }
86 * }
87 *
88 * SafeInt accepts an error policy as an optional template parameter.
89 * We provide two error policy along with SafeInt: SafeIntErrorPolicy_SafeIntException, which
90 * throws SafeIntException in case of error, and SafeIntErrorPolicy_InvalidParameter, which
91 * calls _invalid_parameter to terminate the program.
92 *
93 * You can replace the error policy class with any class you like. This is accomplished by:
94 * 1) Create a class that has the following interface:
95 *
96 * struct YourSafeIntErrorPolicy
97 * {
98 * static __declspec(noreturn) void __stdcall SafeIntOnOverflow()
99 * {
100 * throw YourException( YourSafeIntArithmeticOverflowError );
101 * // or do something else which will terminate the program
102 * }
103 *
104 * static __declspec(noreturn) void __stdcall SafeIntOnDivZero()
105 * {
106 * throw YourException( YourSafeIntDivideByZeroError );
107 * // or do something else which will terminate the program
108 * }
109 * };
110 *
111 * Note that you don't have to throw C++ exceptions, you can throw Win32 exceptions, or do
112 * anything you like, just don't return from the call back into the code.
113 *
114 * 2) Either explicitly declare SafeInts like so:
115 * SafeInt< int, YourSafeIntErrorPolicy > si;
116 * or, before including SafeInt:
117 * #define _SAFEINT_DEFAULT_ERROR_POLICY ::YourSafeIntErrorPolicy
118 *
119 * Performance:
120 *
121 * Due to the highly nested nature of this class, you can expect relatively poor
122 * performance in unoptimized code. In tests of optimized code vs. correct inline checks
123 * in native code, this class has been found to take approximately 8% more CPU time (this varies),
124 * most of which is due to exception handling.
125 *
126 * Binary Operators:
127 *
128 * All of the binary operators have certain assumptions built into the class design.
129 * This is to ensure correctness. Notes on each class of operator follow:
130 *
131 * Arithmetic Operators (*,/,+,-,%)
132 * There are three possible variants:
133 * SafeInt< T, E > op SafeInt< T, E >
134 * SafeInt< T, E > op U
135 * U op SafeInt< T, E >
136 *
137 * The SafeInt< T, E > op SafeInt< U, E > variant is explicitly not supported, and if you try to do
138 * this the compiler with throw the following error:
139 *
140 * error C2593: 'operator *' is ambiguous
141 *
142 * This is because the arithmetic operators are required to return a SafeInt of some type.
143 * The compiler cannot know whether you'd prefer to get a type T or a type U returned. If
144 * you need to do this, you need to extract the value contained within one of the two using
145 * the casting operator. For example:
146 *
147 * SafeInt< T, E > t, result;
148 * SafeInt< U, E > u;
149 *
150 * result = t * (U)u;
151 *
152 * Comparison Operators:
153 *
154 * Because each of these operators return type bool, mixing SafeInts of differing types is
155 * allowed.
156 *
157 * Shift Operators:
158 *
159 * Shift operators always return the type on the left hand side of the operator. Mixed type
160 * operations are allowed because the return type is always known.
161 *
162 * Boolean Operators:
163 *
164 * Like comparison operators, these overloads always return type bool, and mixed-type SafeInts
165 * are allowed. Additionally, specific overloads exist for type bool on both sides of the
166 * operator.
167 *
168 * Binary Operators:
169 *
170 * Mixed-type operations are discouraged, however some provision has been made in order to
171 * enable things like:
172 *
173 * SafeInt<char> c = 2;
174 *
175 * if(c & 0x02)
176 * ...
177 *
178 * The "0x02" is actually an int, and it needs to work.
179 * In the case of binary operations on integers smaller than 32-bit, or of mixed type, corner
180 * cases do exist where you could get unexpected results. In any case where SafeInt returns a different
181 * result than the underlying operator, it will call _ASSERTE(). You should examine your code and cast things
182 * properly so that you are not programming with side effects.
183 *
184 * Comparison Operators and ANSI Conversions:
185 *
186 * The comparison operator behavior in this class varies from the ANSI definition.
187 * As an example, consider the following:
188 *
189 * unsigned int l = 0xffffffff;
190 * char c = -1;
191 *
192 * if(c == l)
193 * printf("Why is -1 equal to 4 billion???\n");
194 *
195 * The problem here is that c gets cast to an int, now has a value of 0xffffffff, and then gets
196 * cast again to an unsigned int, losing the true value. This behavior is despite the fact that
197 * an __int64 exists, and the following code will yield a different (and intuitively correct)
198 * answer:
199 *
200 * if((__int64)c == (__int64)l))
201 * printf("Why is -1 equal to 4 billion???\n");
202 * else
203 * printf("Why doesn't the compiler upcast to 64-bits when needed?\n");
204 *
205 * Note that combinations with smaller integers won't display the problem - if you
206 * changed "unsigned int" above to "unsigned short", you'd get the right answer.
207 *
208 * If you prefer to retain the ANSI standard behavior insert, before including safeint.h:
209 *
210 * #define _SAFEINT_ANSI_CONVERSIONS 1
211 *
212 * into your source. Behavior differences occur in the following cases:
213 * 8, 16, and 32-bit signed int, unsigned 32-bit int
214 * any signed int, unsigned 64-bit int
215 * Note - the signed int must be negative to show the problem
216 *
217 ****/
218
219 #pragma once
220
221 #if !defined(RC_INVOKED)
222
223 #include <corecrt.h>
224 #include <crtdbg.h>
225
226 // Disable warnings hit under /Wall:
227 // C4514: unreferenced inline function has been removed (/Wall)
228 // C4710: function not inlined (/Wall)
229 #pragma warning(push)
230 #pragma warning(disable: 4514)
231 #pragma warning(disable: 4710)
232
233 #if !defined (_SAFEINT_DEFAULT_ERROR_POLICY)
234 #define _SAFEINT_DEFAULT_ERROR_POLICY SafeIntErrorPolicy_SafeIntException
235 #endif /* !defined (_SAFEINT_DEFAULT_ERROR_POLICY) */
236
237 #if !defined (_SAFEINT_SHIFT_ASSERT)
238 #define _SAFEINT_SHIFT_ASSERT(x) _ASSERTE(x)
239 #endif /* !defined (_SAFEINT_SHIFT_ASSERT) */
240
241 #if !defined (_SAFEINT_BINARY_ASSERT)
242 #define _SAFEINT_BINARY_ASSERT(x) _ASSERTE(x)
243 #endif /* !defined (_SAFEINT_BINARY_ASSERT) */
244
245 #if !defined (_SAFEINT_EXCEPTION_ASSERT)
246 #define _SAFEINT_EXCEPTION_ASSERT()
247 #endif /* !defined (_SAFEINT_EXCEPTION_ASSERT) */
248
249 // by default, SafeInt will accept negation of an unsigned int;
250 // if you wish to disable it or assert, you can define the following
251 // macro to be a static assert or a runtime assert
252 #if !defined (_SAFEINT_UNSIGNED_NEGATION_BEHAVIOR)
253 #define _SAFEINT_UNSIGNED_NEGATION_BEHAVIOR()
254 #endif /* !defined (_SAFEINT_UNSIGNED_NEGATION_BEHAVIOR) */
255
256 // See above "Comparison Operators and ANSI Conversions" for an explanation
257 // of _SAFEINT_USE_ANSI_CONVERSIONS
258 #if !defined (_SAFEINT_USE_ANSI_CONVERSIONS)
259 #define _SAFEINT_USE_ANSI_CONVERSIONS 0
260 #endif /* !defined (_SAFEINT_USE_ANSI_CONVERSIONS) */
261
262 #pragma pack(push, _CRT_PACKING)
263
264 namespace msl
265 {
266
267 namespace utilities
268 {
269
270 enum SafeIntError
271 {
272 SafeIntNoError = 0,
273 SafeIntArithmeticOverflow,
274 SafeIntDivideByZero
275 };
276
277 } // namespace utilities
278
279 } // namespace msl
280
281 #include "safeint_internal.h"
282
283 namespace msl
284 {
285
286 namespace utilities
287 {
288
289 class SafeIntException
290 {
291 public:
SafeIntException()292 SafeIntException() { m_code = SafeIntNoError; }
SafeIntException(SafeIntError code)293 SafeIntException( SafeIntError code )
294 {
295 m_code = code;
296 }
297 SafeIntError m_code;
298 };
299
300 struct SafeIntErrorPolicy_SafeIntException
301 {
SafeIntOnOverflowSafeIntErrorPolicy_SafeIntException302 static __declspec(noreturn) void SafeIntOnOverflow()
303 {
304 _SAFEINT_EXCEPTION_ASSERT();
305 throw SafeIntException( SafeIntArithmeticOverflow );
306 }
307
SafeIntOnDivZeroSafeIntErrorPolicy_SafeIntException308 static __declspec(noreturn) void SafeIntOnDivZero()
309 {
310 _SAFEINT_EXCEPTION_ASSERT();
311 throw SafeIntException( SafeIntDivideByZero );
312 }
313 };
314
315 struct SafeIntErrorPolicy_InvalidParameter
316 {
SafeIntOnOverflowSafeIntErrorPolicy_InvalidParameter317 static __declspec(noreturn) void SafeIntOnOverflow()
318 {
319 _SAFEINT_EXCEPTION_ASSERT();
320 _CRT_SECURE_INVALID_PARAMETER("SafeInt Arithmetic Overflow");
321 }
322
SafeIntOnDivZeroSafeIntErrorPolicy_InvalidParameter323 static __declspec(noreturn) void SafeIntOnDivZero()
324 {
325 _SAFEINT_EXCEPTION_ASSERT();
326 _CRT_SECURE_INVALID_PARAMETER("SafeInt Divide By Zero");
327 }
328 };
329
330 // Free-standing functions that can be used where you only need to check one operation
331 // non-class helper function so that you can check for a cast's validity
332 // and handle errors how you like
333
334 template < typename T, typename U >
SafeCast(const T From,U & To)335 inline bool SafeCast( const T From, U& To ) throw()
336 {
337 return (details::SafeCastHelper< U, T,
338 details::SafeIntErrorPolicy_NoThrow >::Cast( From, To ) == SafeIntNoError);
339 }
340
341 template < typename T, typename U >
SafeEquals(const T t,const U u)342 inline bool SafeEquals( const T t, const U u ) throw()
343 {
344 return details::EqualityTest< T, U >::IsEquals( t, u );
345 }
346
347 template < typename T, typename U >
SafeNotEquals(const T t,const U u)348 inline bool SafeNotEquals( const T t, const U u ) throw()
349 {
350 return !details::EqualityTest< T, U >::IsEquals( t, u );
351 }
352
353 template < typename T, typename U >
SafeGreaterThan(const T t,const U u)354 inline bool SafeGreaterThan( const T t, const U u ) throw()
355 {
356 return details::GreaterThanTest< T, U >::GreaterThan( t, u );
357 }
358
359 template < typename T, typename U >
SafeGreaterThanEquals(const T t,const U u)360 inline bool SafeGreaterThanEquals( const T t, const U u ) throw()
361 {
362 return !details::GreaterThanTest< U, T >::GreaterThan( u, t );
363 }
364
365 template < typename T, typename U >
SafeLessThan(const T t,const U u)366 inline bool SafeLessThan( const T t, const U u ) throw()
367 {
368 return details::GreaterThanTest< U, T >::GreaterThan( u, t );
369 }
370
371 template < typename T, typename U >
SafeLessThanEquals(const T t,const U u)372 inline bool SafeLessThanEquals( const T t, const U u ) throw()
373 {
374 return !details::GreaterThanTest< T, U >::GreaterThan( t, u );
375 }
376
377 template < typename T, typename U >
SafeModulus(const T & t,const U & u,T & result)378 inline bool SafeModulus( const T& t, const U& u, T& result ) throw()
379 {
380 return ( details::ModulusHelper< T, U, details::SafeIntErrorPolicy_NoThrow >::Modulus( t, u, result ) == SafeIntNoError );
381 }
382
383 template < typename T, typename U >
SafeMultiply(T t,U u,T & result)384 inline bool SafeMultiply( T t, U u, T& result ) throw()
385 {
386 return ( details::MultiplicationHelper< T, U,
387 details::SafeIntErrorPolicy_NoThrow >::Multiply( t, u, result ) == SafeIntNoError );
388 }
389
390 template < typename T, typename U >
SafeDivide(T t,U u,T & result)391 inline bool SafeDivide( T t, U u, T& result ) throw()
392 {
393 return ( details::DivisionHelper< T, U,
394 details::SafeIntErrorPolicy_NoThrow >::Divide( t, u, result ) == SafeIntNoError );
395 }
396
397 template < typename T, typename U >
SafeAdd(T t,U u,T & result)398 inline bool SafeAdd( T t, U u, T& result ) throw()
399 {
400 return ( details::AdditionHelper< T, U,
401 details::SafeIntErrorPolicy_NoThrow >::Addition( t, u, result ) == SafeIntNoError );
402 }
403
404 template < typename T, typename U >
SafeSubtract(T t,U u,T & result)405 inline bool SafeSubtract( T t, U u, T& result ) throw()
406 {
407 return ( details::SubtractionHelper< T, U,
408 details::SafeIntErrorPolicy_NoThrow >::Subtract( t, u, result ) == SafeIntNoError );
409 }
410
411 // SafeInt class
412 template < typename T, typename E = _SAFEINT_DEFAULT_ERROR_POLICY >
413 class SafeInt
414 {
415 public:
SafeInt()416 SafeInt() throw()
417 {
418 static_assert( details::NumericType< T >::isInt , "SafeInt<T>: T needs to be an integer type" );
419 m_int = 0;
420 }
421
422 // Having a constructor for every type of int
423 // avoids having the compiler evade our checks when doing implicit casts -
424 // e.g., SafeInt<char> s = 0x7fffffff;
throw()425 SafeInt( const T& i ) throw()
426 {
427 static_assert( details::NumericType< T >::isInt , "SafeInt<T>: T needs to be an integer type" );
428 //always safe
429 m_int = i;
430 }
431
432 // provide explicit boolean converter
throw()433 SafeInt( bool b ) throw()
434 {
435 static_assert( details::NumericType< T >::isInt , "SafeInt<T>: T needs to be an integer type" );
436 m_int = b ? 1 : 0;
437 }
438
439 template < typename U >
SafeInt(const SafeInt<U,E> & u)440 SafeInt(const SafeInt< U, E >& u)
441 {
442 static_assert( details::NumericType< T >::isInt , "SafeInt<T>: T needs to be an integer type" );
443 *this = SafeInt< T, E >( (U)u );
444 }
445
446 template < typename U >
SafeInt(const U & i)447 SafeInt( const U& i )
448 {
449 static_assert( details::NumericType< T >::isInt , "SafeInt<T>: T needs to be an integer type" );
450 // SafeCast will throw exceptions if i won't fit in type T
451 details::SafeCastHelper< T, U, E >::Cast( i, m_int );
452 }
453
454 // now start overloading operators
455 // assignment operator
456 // constructors exist for all int types and will ensure safety
457
458 template < typename U >
459 SafeInt< T, E >& operator =( const U& rhs )
460 {
461 // use constructor to test size
462 // constructor is optimized to do minimal checking based
463 // on whether T can contain U
464 // note - do not change this
465 *this = SafeInt< T, E >( rhs );
466 return *this;
467 }
468
throw()469 SafeInt< T, E >& operator =( const T& rhs ) throw()
470 {
471 m_int = rhs;
472 return *this;
473 }
474
475 template < typename U >
476 SafeInt< T, E >& operator =( const SafeInt< U, E >& rhs )
477 {
478 details::SafeCastHelper< T, U, E >::Cast( rhs.Ref(), m_int );
479 return *this;
480 }
481
throw()482 SafeInt< T, E >& operator =( const SafeInt< T, E >& rhs ) throw()
483 {
484 m_int = rhs.m_int;
485 return *this;
486 }
487
488 // Casting operators
489
throw()490 operator bool() const throw()
491 {
492 return !!m_int;
493 }
494
495 operator char() const
496 {
497 char val;
498 details::SafeCastHelper< char, T, E >::Cast( m_int, val );
499 return val;
500 }
501
502 operator signed char() const
503 {
504 signed char val;
505 details::SafeCastHelper< signed char, T, E >::Cast( m_int, val );
506 return val;
507 }
508
509 operator unsigned char() const
510 {
511 unsigned char val;
512 details::SafeCastHelper< unsigned char, T, E >::Cast( m_int, val );
513 return val;
514 }
515
__int16()516 operator __int16() const
517 {
518 __int16 val;
519 details::SafeCastHelper< __int16, T, E >::Cast( m_int, val );
520 return val;
521 }
522
__int16()523 operator unsigned __int16() const
524 {
525 unsigned __int16 val;
526 details::SafeCastHelper< unsigned __int16, T, E >::Cast( m_int, val );
527 return val;
528 }
529
__int32()530 operator __int32() const
531 {
532 __int32 val;
533 details::SafeCastHelper< __int32, T, E >::Cast( m_int, val );
534 return val;
535 }
536
__int32()537 operator unsigned __int32() const
538 {
539 unsigned __int32 val;
540 details::SafeCastHelper< unsigned __int32, T, E >::Cast( m_int, val );
541 return val;
542 }
543
544 // The compiler knows that int == __int32
545 // but not that long == __int32
546 operator long() const
547 {
548 long val;
549 details::SafeCastHelper< long, T, E >::Cast( m_int, val );
550 return val;
551 }
552
553 operator unsigned long() const
554 {
555 unsigned long val;
556 details::SafeCastHelper< unsigned long, T, E >::Cast( m_int, val );
557 return val;
558 }
559
__int64()560 operator __int64() const
561 {
562 __int64 val;
563 details::SafeCastHelper< __int64, T, E >::Cast( m_int, val );
564 return val;
565 }
566
__int64()567 operator unsigned __int64() const
568 {
569 unsigned __int64 val;
570 details::SafeCastHelper< unsigned __int64, T, E >::Cast( m_int, val );
571 return val;
572 }
573
574 #ifdef _NATIVE_WCHAR_T_DEFINED
wchar_t()575 operator wchar_t() const
576 {
577 unsigned __int16 val;
578 details::SafeCastHelper< unsigned __int16, T, E >::Cast( m_int, val );
579 return val;
580 }
581 #endif /* _NATIVE_WCHAR_T_DEFINED */
582
583 // If you need a pointer to the data
584 // this could be dangerous, but allows you to correctly pass
585 // instances of this class to APIs that take a pointer to an integer
586 // also see overloaded address-of operator below
Ptr()587 T* Ptr() throw() { return &m_int; }
Ptr()588 const T* Ptr() const throw() { return &m_int; }
Ref()589 const T& Ref() const throw() { return m_int; }
590
591 // Unary operators
592 bool operator !() const throw() { return (!m_int) ? true : false; }
593
594 // operator + (unary)
595 // note - normally, the '+' and '-' operators will upcast to a signed int
596 // for T < 32 bits. This class changes behavior to preserve type
597 const SafeInt< T, E >& operator +() const throw() { return *this; };
598
599 //unary -
600 SafeInt< T, E > operator -() const
601 {
602 // Note - unsigned still performs the bitwise manipulation
603 // will warn at level 2 or higher if the value is 32-bit or larger
604 T tmp;
605 details::NegationHelper< T, E, details::IntTraits< T >::isSigned >::Negative( m_int, tmp );
606 return SafeInt< T, E >( tmp );
607 }
608
609 // prefix increment operator
610 SafeInt< T, E >& operator ++()
611 {
612 if( m_int != details::IntTraits< T >::maxInt )
613 {
614 ++m_int;
615 return *this;
616 }
617 E::SafeIntOnOverflow();
618 }
619
620 // prefix decrement operator
621 SafeInt< T, E >& operator --()
622 {
623 if( m_int != details::IntTraits< T >::minInt )
624 {
625 --m_int;
626 return *this;
627 }
628 E::SafeIntOnOverflow();
629 }
630
631 // note that postfix operators have inherently worse perf
632 // characteristics
633
634 // postfix increment operator
635 SafeInt< T, E > operator ++( int ) // dummy arg to comply with spec
636 {
637 if( m_int != details::IntTraits< T >::maxInt )
638 {
639 SafeInt< T, E > tmp( m_int );
640
641 m_int++;
642 return tmp;
643 }
644 E::SafeIntOnOverflow();
645 }
646
647 // postfix decrement operator
648 SafeInt< T, E > operator --( int ) // dummy arg to comply with spec
649 {
650 if( m_int != details::IntTraits< T >::minInt )
651 {
652 SafeInt< T, E > tmp( m_int );
653 m_int--;
654 return tmp;
655 }
656 E::SafeIntOnOverflow();
657 }
658
659 // One's complement
660 // Note - this operator will normally change size to an int
661 // cast in return improves perf and maintains type
662 SafeInt< T, E > operator ~() const throw() { return SafeInt< T, E >( (T)~m_int ); }
663
664 // Binary operators
665 //
666 // arithmetic binary operators
667 // % modulus
668 // * multiplication
669 // / division
670 // + addition
671 // - subtraction
672 //
673 // For each of the arithmetic operators, you will need to
674 // use them as follows:
675 //
676 // SafeInt<char> c = 2;
677 // SafeInt<int> i = 3;
678 //
679 // SafeInt<int> i2 = i op (char)c;
680 // OR
681 // SafeInt<char> i2 = (int)i op c;
682 //
683 // The base problem is that if the lhs and rhs inputs are different SafeInt types
684 // it is not possible in this implementation to determine what type of SafeInt
685 // should be returned. You have to let the class know which of the two inputs
686 // need to be the return type by forcing the other value to the base integer type.
687 //
688 // Note - as per feedback from Scott Meyers, I'm exploring how to get around this.
689 // 3.0 update - I'm still thinking about this. It can be done with template metaprogramming,
690 // but it is tricky, and there's a perf vs. correctness tradeoff where the right answer
691 // is situational.
692 //
693 // The case of:
694 //
695 // SafeInt< T, E > i, j, k;
696 // i = j op k;
697 //
698 // works just fine and no unboxing is needed because the return type is not ambiguous.
699
700 // Modulus
701 // Modulus has some convenient properties -
702 // first, the magnitude of the return can never be
703 // larger than the lhs operand, and it must be the same sign
704 // as well. It does, however, suffer from the same promotion
705 // problems as comparisons, division and other operations
706 template < typename U >
707 SafeInt< T, E > operator %( U rhs ) const
708 {
709 T result;
710 details::ModulusHelper< T, U, E >::Modulus( m_int, rhs, result );
711 return SafeInt< T, E >( result );
712 }
713
714 SafeInt< T, E > operator %( SafeInt< T, E > rhs ) const
715 {
716 T result;
717 details::ModulusHelper< T, T, E >::Modulus( m_int, rhs, result );
718 return SafeInt< T, E >( result );
719 }
720
721 // Modulus assignment
722 template < typename U >
723 SafeInt< T, E >& operator %=( U rhs )
724 {
725 details::ModulusHelper< T, U, E >::Modulus( m_int, rhs, m_int );
726 return *this;
727 }
728
729 template < typename U >
730 SafeInt< T, E >& operator %=( SafeInt< U, E > rhs )
731 {
732 details::ModulusHelper< T, U, E >::Modulus( m_int, (U)rhs, m_int );
733 return *this;
734 }
735
736 // Multiplication
737 template < typename U >
738 SafeInt< T, E > operator *( U rhs ) const
739 {
740 T ret( 0 );
741 details::MultiplicationHelper< T, U, E >::Multiply( m_int, rhs, ret );
742 return SafeInt< T, E >( ret );
743 }
744
745 SafeInt< T, E > operator *( SafeInt< T, E > rhs ) const
746 {
747 T ret( 0 );
748 details::MultiplicationHelper< T, T, E >::Multiply( m_int, (T)rhs, ret );
749 return SafeInt< T, E >( ret );
750 }
751
752 // Multiplication assignment
753 SafeInt< T, E >& operator *=( SafeInt< T, E > rhs )
754 {
755 details::MultiplicationHelper< T, T, E >::Multiply( m_int, (T)rhs, m_int );
756 return *this;
757 }
758
759 template < typename U >
760 SafeInt< T, E >& operator *=( U rhs )
761 {
762 details::MultiplicationHelper< T, U, E >::Multiply( m_int, rhs, m_int );
763 return *this;
764 }
765
766 template < typename U >
767 SafeInt< T, E >& operator *=( SafeInt< U, E > rhs )
768 {
769 details::MultiplicationHelper< T, U, E >::Multiply( m_int, rhs.Ref(), m_int );
770 return *this;
771 }
772
773 // Division
774 template < typename U >
775 SafeInt< T, E > operator /( U rhs ) const
776 {
777 T ret( 0 );
778 details::DivisionHelper< T, U, E >::Divide( m_int, rhs, ret );
779 return SafeInt< T, E >( ret );
780 }
781
782 SafeInt< T, E > operator /( SafeInt< T, E > rhs ) const
783 {
784 T ret( 0 );
785 details::DivisionHelper< T, T, E >::Divide( m_int, (T)rhs, ret );
786 return SafeInt< T, E >( ret );
787 }
788
789 // Division assignment
790 SafeInt< T, E >& operator /=( SafeInt< T, E > i )
791 {
792 details::DivisionHelper< T, T, E >::Divide( m_int, (T)i, m_int );
793 return *this;
794 }
795
796 template < typename U > SafeInt< T, E >& operator /=( U i )
797 {
798 details::DivisionHelper< T, U, E >::Divide( m_int, i, m_int );
799 return *this;
800 }
801
802 template < typename U > SafeInt< T, E >& operator /=( SafeInt< U, E > i )
803 {
804 details::DivisionHelper< T, U, E >::Divide( m_int, (U)i, m_int );
805 return *this;
806 }
807
808 // For addition and subtraction
809
810 // Addition
811 SafeInt< T, E > operator +( SafeInt< T, E > rhs ) const
812 {
813 T ret( 0 );
814 details::AdditionHelper< T, T, E >::Addition( m_int, (T)rhs, ret );
815 return SafeInt< T, E >( ret );
816 }
817
818 template < typename U >
819 SafeInt< T, E > operator +( U rhs ) const
820 {
821 T ret( 0 );
822 details::AdditionHelper< T, U, E >::Addition( m_int, rhs, ret );
823 return SafeInt< T, E >( ret );
824 }
825
826 //addition assignment
827 SafeInt< T, E >& operator +=( SafeInt< T, E > rhs )
828 {
829 details::AdditionHelper< T, T, E >::Addition( m_int, (T)rhs, m_int );
830 return *this;
831 }
832
833 template < typename U >
834 SafeInt< T, E >& operator +=( U rhs )
835 {
836 details::AdditionHelper< T, U, E >::Addition( m_int, rhs, m_int );
837 return *this;
838 }
839
840 template < typename U >
841 SafeInt< T, E >& operator +=( SafeInt< U, E > rhs )
842 {
843 details::AdditionHelper< T, U, E >::Addition( m_int, (U)rhs, m_int );
844 return *this;
845 }
846
847 // Subtraction
848 template < typename U >
849 SafeInt< T, E > operator -( U rhs ) const
850 {
851 T ret( 0 );
852 details::SubtractionHelper< T, U, E >::Subtract( m_int, rhs, ret );
853 return SafeInt< T, E >( ret );
854 }
855
856 SafeInt< T, E > operator -(SafeInt< T, E > rhs) const
857 {
858 T ret( 0 );
859 details::SubtractionHelper< T, T, E >::Subtract( m_int, (T)rhs, ret );
860 return SafeInt< T, E >( ret );
861 }
862
863 // Subtraction assignment
864 SafeInt< T, E >& operator -=( SafeInt< T, E > rhs )
865 {
866 details::SubtractionHelper< T, T, E >::Subtract( m_int, (T)rhs, m_int );
867 return *this;
868 }
869
870 template < typename U >
871 SafeInt< T, E >& operator -=( U rhs )
872 {
873 details::SubtractionHelper< T, U, E >::Subtract( m_int, rhs, m_int );
874 return *this;
875 }
876
877 template < typename U >
878 SafeInt< T, E >& operator -=( SafeInt< U, E > rhs )
879 {
880 details::SubtractionHelper< T, U, E >::Subtract( m_int, (U)rhs, m_int );
881 return *this;
882 }
883
884 // Comparison operators
885 // Additional overloads defined outside the class
886 // to allow for cases where the SafeInt is the rhs value
887
888 // Less than
889 template < typename U >
890 bool operator <( U rhs ) const throw()
891 {
892 return details::GreaterThanTest< U, T >::GreaterThan( rhs, m_int );
893 }
894
895 bool operator <( SafeInt< T, E > rhs ) const throw()
896 {
897 return m_int < (T)rhs;
898 }
899
900 // Greater than or eq.
901 template < typename U >
throw()902 bool operator >=( U rhs ) const throw()
903 {
904 return !details::GreaterThanTest< U, T >::GreaterThan( rhs, m_int );
905 }
906
throw()907 bool operator >=( SafeInt< T, E > rhs ) const throw()
908 {
909 return m_int >= (T)rhs;
910 }
911
912 // Greater than
913 template < typename U >
throw()914 bool operator >( U rhs ) const throw()
915 {
916 return details::GreaterThanTest< T, U >::GreaterThan( m_int, rhs );
917 }
918
throw()919 bool operator >( SafeInt< T, E > rhs ) const throw()
920 {
921 return m_int > (T)rhs;
922 }
923
924 // Less than or eq.
925 template < typename U >
926 bool operator <=( U rhs ) const throw()
927 {
928 return !details::GreaterThanTest< T, U >::GreaterThan( m_int, rhs );
929 }
930
931 bool operator <=( SafeInt< T, E > rhs ) const throw()
932 {
933 return m_int <= (T)rhs;
934 }
935
936 // Equality
937 template < typename U >
938 bool operator ==( U rhs ) const throw()
939 {
940 return details::EqualityTest< T, U >::IsEquals( m_int, rhs );
941 }
942
943 // Need an explicit override for type bool
944 bool operator ==( bool rhs ) const throw()
945 {
946 return ( m_int == 0 ? false : true ) == rhs;
947 }
948
949 bool operator ==( SafeInt< T, E > rhs ) const throw() { return m_int == (T)rhs; }
950
951 // != operators
952 template < typename U >
953 bool operator !=( U rhs ) const throw()
954 {
955 return !details::EqualityTest< T, U >::IsEquals( m_int, rhs );
956 }
957
958 bool operator !=( bool b ) const throw()
959 {
960 return ( m_int == 0 ? false : true ) != b;
961 }
962
963 bool operator !=( SafeInt< T, E > rhs ) const throw() { return m_int != (T)rhs; }
964
965 // Shift operators
966 // Note - shift operators ALWAYS return the same type as the lhs
967 // specific version for SafeInt< T, E > not needed -
968 // code path is exactly the same as for SafeInt< U, E > as rhs
969
970 // Left shift
971 // Also, shifting > bitcount is undefined - trap in debug (check _SAFEINT_SHIFT_ASSERT)
972
973 template < typename U >
974 SafeInt< T, E > operator <<( U bits ) const throw()
975 {
976 _SAFEINT_SHIFT_ASSERT( !details::IntTraits< U >::isSigned || bits >= 0 );
977 _SAFEINT_SHIFT_ASSERT( bits < (int)details::IntTraits< T >::bitCount );
978
979 return SafeInt< T, E >( (T)( m_int << bits ) );
980 }
981
982 template < typename U >
983 SafeInt< T, E > operator <<( SafeInt< U, E > bits ) const throw()
984 {
985 _SAFEINT_SHIFT_ASSERT( !details::IntTraits< U >::isSigned || (U)bits >= 0 );
986 _SAFEINT_SHIFT_ASSERT( (U)bits < (int)details::IntTraits< T >::bitCount );
987
988 return SafeInt< T, E >( (T)( m_int << (U)bits ) );
989 }
990
991 // Left shift assignment
992
993 template < typename U >
994 SafeInt< T, E >& operator <<=( U bits ) throw()
995 {
996 _SAFEINT_SHIFT_ASSERT( !details::IntTraits< U >::isSigned || bits >= 0 );
997 _SAFEINT_SHIFT_ASSERT( bits < (int)details::IntTraits< T >::bitCount );
998
999 m_int <<= bits;
1000 return *this;
1001 }
1002
1003 template < typename U >
1004 SafeInt< T, E >& operator <<=( SafeInt< U, E > bits ) throw()
1005 {
1006 _SAFEINT_SHIFT_ASSERT( !details::IntTraits< U >::isSigned || (U)bits >= 0 );
1007 _SAFEINT_SHIFT_ASSERT( (U)bits < (int)details::IntTraits< T >::bitCount );
1008
1009 m_int <<= (U)bits;
1010 return *this;
1011 }
1012
1013 // Right shift
1014 template < typename U >
throw()1015 SafeInt< T, E > operator >>( U bits ) const throw()
1016 {
1017 _SAFEINT_SHIFT_ASSERT( !details::IntTraits< U >::isSigned || bits >= 0 );
1018 _SAFEINT_SHIFT_ASSERT( bits < (int)details::IntTraits< T >::bitCount );
1019
1020 return SafeInt< T, E >( (T)( m_int >> bits ) );
1021 }
1022
1023 template < typename U >
throw()1024 SafeInt< T, E > operator >>( SafeInt< U, E > bits ) const throw()
1025 {
1026 _SAFEINT_SHIFT_ASSERT( !details::IntTraits< U >::isSigned || (U)bits >= 0 );
1027 _SAFEINT_SHIFT_ASSERT( bits < (int)details::IntTraits< T >::bitCount );
1028
1029 return SafeInt< T, E >( (T)(m_int >> (U)bits) );
1030 }
1031
1032 // Right shift assignment
1033 template < typename U >
throw()1034 SafeInt< T, E >& operator >>=( U bits ) throw()
1035 {
1036 _SAFEINT_SHIFT_ASSERT( !details::IntTraits< U >::isSigned || bits >= 0 );
1037 _SAFEINT_SHIFT_ASSERT( bits < (int)details::IntTraits< T >::bitCount );
1038
1039 m_int >>= bits;
1040 return *this;
1041 }
1042
1043 template < typename U >
throw()1044 SafeInt< T, E >& operator >>=( SafeInt< U, E > bits ) throw()
1045 {
1046 _SAFEINT_SHIFT_ASSERT( !details::IntTraits< U >::isSigned || (U)bits >= 0 );
1047 _SAFEINT_SHIFT_ASSERT( (U)bits < (int)details::IntTraits< T >::bitCount );
1048
1049 m_int >>= (U)bits;
1050 return *this;
1051 }
1052
1053 // Bitwise operators
1054 // This only makes sense if we're dealing with the same type and size
1055 // demand a type T, or something that fits into a type T
1056
1057 // Bitwise &
throw()1058 SafeInt< T, E > operator &( SafeInt< T, E > rhs ) const throw()
1059 {
1060 return SafeInt< T, E >( m_int & (T)rhs );
1061 }
1062
1063 template < typename U >
throw()1064 SafeInt< T, E > operator &( U rhs ) const throw()
1065 {
1066 // we want to avoid setting bits by surprise
1067 // consider the case of lhs = int, value = 0xffffffff
1068 // rhs = char, value = 0xff
1069 //
1070 // programmer intent is to get only the lower 8 bits
1071 // normal behavior is to upcast both sides to an int
1072 // which then sign extends rhs, setting all the bits
1073
1074 // If you land in the assert, this is because the bitwise operator
1075 // was causing unexpected behavior. Fix is to properly cast your inputs
1076 // so that it works like you meant, not unexpectedly
1077
1078 return SafeInt< T, E >( details::BinaryAndHelper< T, U >::And( m_int, rhs ) );
1079 }
1080
1081 // Bitwise & assignment
throw()1082 SafeInt< T, E >& operator &=( SafeInt< T, E > rhs ) throw()
1083 {
1084 m_int &= (T)rhs;
1085 return *this;
1086 }
1087
1088 template < typename U >
throw()1089 SafeInt< T, E >& operator &=( U rhs ) throw()
1090 {
1091 m_int = details::BinaryAndHelper< T, U >::And( m_int, rhs );
1092 return *this;
1093 }
1094
1095 template < typename U >
throw()1096 SafeInt< T, E >& operator &=( SafeInt< U, E > rhs ) throw()
1097 {
1098 m_int = details::BinaryAndHelper< T, U >::And( m_int, (U)rhs );
1099 return *this;
1100 }
1101
1102 // XOR
1103 SafeInt< T, E > operator ^( SafeInt< T, E > rhs ) const throw()
1104 {
1105 return SafeInt< T, E >( (T)( m_int ^ (T)rhs ) );
1106 }
1107
1108 template < typename U >
1109 SafeInt< T, E > operator ^( U rhs ) const throw()
1110 {
1111 // If you land in the assert, this is because the bitwise operator
1112 // was causing unexpected behavior. Fix is to properly cast your inputs
1113 // so that it works like you meant, not unexpectedly
1114
1115 return SafeInt< T, E >( details::BinaryXorHelper< T, U >::Xor( m_int, rhs ) );
1116 }
1117
1118 // XOR assignment
1119 SafeInt< T, E >& operator ^=( SafeInt< T, E > rhs ) throw()
1120 {
1121 m_int ^= (T)rhs;
1122 return *this;
1123 }
1124
1125 template < typename U >
1126 SafeInt< T, E >& operator ^=( U rhs ) throw()
1127 {
1128 m_int = details::BinaryXorHelper< T, U >::Xor( m_int, rhs );
1129 return *this;
1130 }
1131
1132 template < typename U >
1133 SafeInt< T, E >& operator ^=( SafeInt< U, E > rhs ) throw()
1134 {
1135 m_int = details::BinaryXorHelper< T, U >::Xor( m_int, (U)rhs );
1136 return *this;
1137 }
1138
1139 // bitwise OR
1140 SafeInt< T, E > operator |( SafeInt< T, E > rhs ) const throw()
1141 {
1142 return SafeInt< T, E >( (T)( m_int | (T)rhs ) );
1143 }
1144
1145 template < typename U >
1146 SafeInt< T, E > operator |( U rhs ) const throw()
1147 {
1148 return SafeInt< T, E >( details::BinaryOrHelper< T, U >::Or( m_int, rhs ) );
1149 }
1150
1151 // bitwise OR assignment
1152 SafeInt< T, E >& operator |=( SafeInt< T, E > rhs ) throw()
1153 {
1154 m_int |= (T)rhs;
1155 return *this;
1156 }
1157
1158 template < typename U >
1159 SafeInt< T, E >& operator |=( U rhs ) throw()
1160 {
1161 m_int = details::BinaryOrHelper< T, U >::Or( m_int, rhs );
1162 return *this;
1163 }
1164
1165 template < typename U >
1166 SafeInt< T, E >& operator |=( SafeInt< U, E > rhs ) throw()
1167 {
1168 m_int = details::BinaryOrHelper< T, U >::Or( m_int, (U)rhs );
1169 return *this;
1170 }
1171
1172 // Miscellaneous helper functions
throw()1173 SafeInt< T, E > Min( SafeInt< T, E > test, SafeInt< T, E > floor = SafeInt< T, E >( details::IntTraits< T >::minInt ) ) const throw()
1174 {
1175 T tmp = test < m_int ? test : m_int;
1176 return tmp < floor ? floor : tmp;
1177 }
1178
throw()1179 SafeInt< T, E > Max( SafeInt< T, E > test, SafeInt< T, E > upper = SafeInt< T, E >( details::IntTraits< T >::maxInt ) ) const throw()
1180 {
1181 T tmp = test > m_int ? test : m_int;
1182 return tmp > upper ? upper : tmp;
1183 }
1184
Swap(SafeInt<T,E> & with)1185 void Swap( SafeInt< T, E >& with ) throw()
1186 {
1187 T temp( m_int );
1188 m_int = with.m_int;
1189 with.m_int = temp;
1190 }
1191
1192 template < int bits >
Align()1193 const SafeInt< T, E >& Align()
1194 {
1195 // Zero is always aligned
1196 if( m_int == 0 )
1197 return *this;
1198
1199 // We don't support aligning negative numbers at this time
1200 // Can't align unsigned numbers on bitCount (e.g., 8 bits = 256, unsigned char max = 255)
1201 // or signed numbers on bitCount-1 (e.g., 7 bits = 128, signed char max = 127).
1202 // Also makes no sense to try to align on negative or no bits.
1203
1204 _SAFEINT_SHIFT_ASSERT( ( ( details::IntTraits<T>::isSigned && bits < (int)details::IntTraits< T >::bitCount - 1 )
1205 || ( !details::IntTraits<T>::isSigned && bits < (int)details::IntTraits< T >::bitCount ) ) &&
1206 bits >= 0 && ( !details::IntTraits<T>::isSigned || m_int > 0 ) );
1207
1208 const T AlignValue = ( (T)1 << bits ) - 1;
1209
1210 m_int = ( m_int + AlignValue ) & ~AlignValue;
1211
1212 if( m_int <= 0 )
1213 E::SafeIntOnOverflow();
1214
1215 return *this;
1216 }
1217
1218 // Commonly needed alignments:
Align2()1219 const SafeInt< T, E >& Align2() { return Align< 1 >(); }
Align4()1220 const SafeInt< T, E >& Align4() { return Align< 2 >(); }
Align8()1221 const SafeInt< T, E >& Align8() { return Align< 3 >(); }
Align16()1222 const SafeInt< T, E >& Align16() { return Align< 4 >(); }
Align32()1223 const SafeInt< T, E >& Align32() { return Align< 5 >(); }
Align64()1224 const SafeInt< T, E >& Align64() { return Align< 6 >(); }
1225
1226 private:
1227 T m_int;
1228 };
1229
1230 // Externally defined functions for the case of U op SafeInt< T, E >
1231 template < typename T, typename U, typename E >
1232 bool operator <( U lhs, SafeInt< T, E > rhs ) throw()
1233 {
1234 return details::GreaterThanTest< T, U >::GreaterThan( (T)rhs, lhs );
1235 }
1236
1237 template < typename T, typename U, typename E >
1238 bool operator <( SafeInt< U, E > lhs, SafeInt< T, E > rhs ) throw()
1239 {
1240 return details::GreaterThanTest< T, U >::GreaterThan( (T)rhs, (U)lhs );
1241 }
1242
1243 // Greater than
1244 template < typename T, typename U, typename E >
throw()1245 bool operator >( U lhs, SafeInt< T, E > rhs ) throw()
1246 {
1247 return details::GreaterThanTest< U, T >::GreaterThan( lhs, (T)rhs );
1248 }
1249
1250 template < typename T, typename U, typename E >
throw()1251 bool operator >( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) throw()
1252 {
1253 return details::GreaterThanTest< T, U >::GreaterThan( (T)lhs, (U)rhs );
1254 }
1255
1256 // Greater than or equal
1257 template < typename T, typename U, typename E >
throw()1258 bool operator >=( U lhs, SafeInt< T, E > rhs ) throw()
1259 {
1260 return !details::GreaterThanTest< T, U >::GreaterThan( (T)rhs, lhs );
1261 }
1262
1263 template < typename T, typename U, typename E >
throw()1264 bool operator >=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) throw()
1265 {
1266 return !details::GreaterThanTest< U, T >::GreaterThan( (U)rhs, (T)lhs );
1267 }
1268
1269 // Less than or equal
1270 template < typename T, typename U, typename E >
1271 bool operator <=( U lhs, SafeInt< T, E > rhs ) throw()
1272 {
1273 return !details::GreaterThanTest< U, T >::GreaterThan( lhs, (T)rhs );
1274 }
1275
1276 template < typename T, typename U, typename E >
1277 bool operator <=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) throw()
1278 {
1279 return !details::GreaterThanTest< T, U >::GreaterThan( (T)lhs, (U)rhs );
1280 }
1281
1282 // equality
1283 // explicit overload for bool
1284 template < typename T, typename E >
1285 bool operator ==( bool lhs, SafeInt< T, E > rhs ) throw()
1286 {
1287 return lhs == ( (T)rhs == 0 ? false : true );
1288 }
1289
1290 template < typename T, typename U, typename E >
1291 bool operator ==( U lhs, SafeInt< T, E > rhs ) throw()
1292 {
1293 return details::EqualityTest< T, U >::IsEquals((T)rhs, lhs);
1294 }
1295
1296 template < typename T, typename U, typename E >
1297 bool operator ==( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) throw()
1298 {
1299 return details::EqualityTest< T, U >::IsEquals( (T)lhs, (U)rhs );
1300 }
1301
1302 //not equals
1303 template < typename T, typename U, typename E >
1304 bool operator !=( U lhs, SafeInt< T, E > rhs ) throw()
1305 {
1306 return !details::EqualityTest< T, U >::IsEquals( rhs, lhs );
1307 }
1308
1309 template < typename T, typename E >
1310 bool operator !=( bool lhs, SafeInt< T, E > rhs ) throw()
1311 {
1312 return ( (T)rhs == 0 ? false : true ) != lhs;
1313 }
1314
1315 template < typename T, typename U, typename E >
1316 bool operator !=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) throw()
1317 {
1318 return !details::EqualityTest< T, U >::IsEquals( lhs, rhs );
1319 }
1320
1321 // Modulus
1322 template < typename T, typename U, typename E >
1323 SafeInt< T, E > operator %( U lhs, SafeInt< T, E > rhs )
1324 {
1325 // Value of return depends on sign of lhs
1326 // This one may not be safe - bounds check in constructor
1327 // if lhs is negative and rhs is unsigned, this will throw an exception.
1328
1329 // Fast-track the simple case
1330 // same size and same sign
1331 #pragma warning(suppress:4127 6326)
1332 if( sizeof(T) == sizeof(U) && details::IntTraits< T >::isSigned == details::IntTraits< U >::isSigned )
1333 {
1334 if( rhs != 0 )
1335 {
1336 if( details::IntTraits< T >::isSigned && (T)rhs == -1 )
1337 return 0;
1338
1339 return SafeInt< T, E >( (T)( lhs % (T)rhs ) );
1340 }
1341
1342 E::SafeIntOnDivZero();
1343 }
1344
1345 return SafeInt< T, E >( ( SafeInt< U, E >( lhs ) % (T)rhs ) );
1346 }
1347
1348 // Multiplication
1349 template < typename T, typename U, typename E >
1350 SafeInt< T, E > operator *( U lhs, SafeInt< T, E > rhs )
1351 {
1352 T ret( 0 );
1353 details::MultiplicationHelper< T, U, E >::Multiply( (T)rhs, lhs, ret );
1354 return SafeInt< T, E >(ret);
1355 }
1356
1357 // Division
1358 template < typename T, typename U, typename E > SafeInt< T, E > operator /( U lhs, SafeInt< T, E > rhs )
1359 {
1360 #pragma warning(push)
1361 #pragma warning(disable: 4127 4146 4307 4310 6326)
1362 // Corner case - has to be handled separately
1363 if( details::DivisionMethod< U, T >::method == details::DivisionState_UnsignedSigned )
1364 {
1365 if( (T)rhs > 0 )
1366 return SafeInt< T, E >( lhs/(T)rhs );
1367
1368 // Now rhs is either negative, or zero
1369 if( (T)rhs != 0 )
1370 {
1371 if( sizeof( U ) >= 4 && sizeof( T ) <= sizeof( U ) )
1372 {
1373 // Problem case - normal casting behavior changes meaning
1374 // flip rhs to positive
1375 // any operator casts now do the right thing
1376 U tmp;
1377 if( sizeof(T) == 4 )
1378 tmp = lhs/(U)(unsigned __int32)( -(T)rhs );
1379 else
1380 tmp = lhs/(U)( -(T)rhs );
1381
1382 if( tmp <= details::IntTraits< T >::maxInt )
1383 return SafeInt< T, E >( -( (T)tmp ) );
1384
1385 // Corner case
1386 // Note - this warning happens because we're not using partial
1387 // template specialization in this case. For any real cases where
1388 // this block isn't optimized out, the warning won't be present.
1389 if( tmp == (U)details::IntTraits< T >::maxInt + 1 )
1390 return SafeInt< T, E >( details::IntTraits< T >::minInt );
1391
1392 E::SafeIntOnOverflow();
1393 }
1394
1395 return SafeInt< T, E >(lhs/(T)rhs);
1396 }
1397
1398 E::SafeIntOnDivZero();
1399 } // method == DivisionState_UnsignedSigned
1400
1401 if( details::SafeIntCompare< T, U >::isBothSigned )
1402 {
1403 if( lhs == details::IntTraits< U >::minInt && (T)rhs == -1 )
1404 {
1405 // corner case of a corner case - lhs = min int, rhs = -1,
1406 // but rhs is the return type, so in essence, we can return -lhs
1407 // if rhs is a larger type than lhs
1408 if( sizeof( U ) < sizeof( T ) )
1409 {
1410 return SafeInt< T, E >( (T)( -(T)details::IntTraits< U >::minInt ) );
1411 }
1412
1413 // If rhs is smaller or the same size int, then -minInt won't work
1414 E::SafeIntOnOverflow();
1415 }
1416 }
1417
1418 // Otherwise normal logic works with addition of bounds check when casting from U->T
1419 U ret;
1420 details::DivisionHelper< U, T, E >::Divide( lhs, (T)rhs, ret );
1421 return SafeInt< T, E >( ret );
1422 #pragma warning(pop)
1423 }
1424
1425 // Addition
1426 template < typename T, typename U, typename E >
1427 SafeInt< T, E > operator +( U lhs, SafeInt< T, E > rhs )
1428 {
1429 T ret( 0 );
1430 details::AdditionHelper< T, U, E >::Addition( (T)rhs, lhs, ret );
1431 return SafeInt< T, E >( ret );
1432 }
1433
1434 // Subtraction
1435 template < typename T, typename U, typename E >
1436 SafeInt< T, E > operator -( U lhs, SafeInt< T, E > rhs )
1437 {
1438 T ret( 0 );
1439 details::SubtractionHelper< U, T, E, details::SubtractionMethod2< U, T >::method >::Subtract( lhs, rhs.Ref(), ret );
1440
1441 return SafeInt< T, E >( ret );
1442 }
1443
1444 // Overrides designed to deal with cases where a SafeInt is assigned out
1445 // to a normal int - this at least makes the last operation safe
1446 // +=
1447 template < typename T, typename U, typename E >
1448 T& operator +=( T& lhs, SafeInt< U, E > rhs )
1449 {
1450 T ret( 0 );
1451 details::AdditionHelper< T, U, E >::Addition( lhs, (U)rhs, ret );
1452 lhs = ret;
1453 return lhs;
1454 }
1455
1456 template < typename T, typename U, typename E >
1457 T& operator -=( T& lhs, SafeInt< U, E > rhs )
1458 {
1459 T ret( 0 );
1460 details::SubtractionHelper< T, U, E >::Subtract( lhs, (U)rhs, ret );
1461 lhs = ret;
1462 return lhs;
1463 }
1464
1465 template < typename T, typename U, typename E >
1466 T& operator *=( T& lhs, SafeInt< U, E > rhs )
1467 {
1468 T ret( 0 );
1469 details::MultiplicationHelper< T, U, E >::Multiply( lhs, (U)rhs, ret );
1470 lhs = ret;
1471 return lhs;
1472 }
1473
1474 template < typename T, typename U, typename E >
1475 T& operator /=( T& lhs, SafeInt< U, E > rhs )
1476 {
1477 T ret( 0 );
1478 details::DivisionHelper< T, U, E >::Divide( lhs, (U)rhs, ret );
1479 lhs = ret;
1480 return lhs;
1481 }
1482
1483 template < typename T, typename U, typename E >
1484 T& operator %=( T& lhs, SafeInt< U, E > rhs )
1485 {
1486 T ret( 0 );
1487 details::ModulusHelper< T, U, E >::Modulus( lhs, (U)rhs, ret );
1488 lhs = ret;
1489 return lhs;
1490 }
1491
1492 template < typename T, typename U, typename E >
throw()1493 T& operator &=( T& lhs, SafeInt< U, E > rhs ) throw()
1494 {
1495 lhs = details::BinaryAndHelper< T, U >::And( lhs, (U)rhs );
1496 return lhs;
1497 }
1498
1499 template < typename T, typename U, typename E >
1500 T& operator ^=( T& lhs, SafeInt< U, E > rhs ) throw()
1501 {
1502 lhs = details::BinaryXorHelper< T, U >::Xor( lhs, (U)rhs );
1503 return lhs;
1504 }
1505
1506 template < typename T, typename U, typename E >
1507 T& operator |=( T& lhs, SafeInt< U, E > rhs ) throw()
1508 {
1509 lhs = details::BinaryOrHelper< T, U >::Or( lhs, (U)rhs );
1510 return lhs;
1511 }
1512
1513 template < typename T, typename U, typename E >
1514 T& operator <<=( T& lhs, SafeInt< U, E > rhs ) throw()
1515 {
1516 lhs = (T)( SafeInt< T, E >( lhs ) << (U)rhs );
1517 return lhs;
1518 }
1519
1520 template < typename T, typename U, typename E >
throw()1521 T& operator >>=( T& lhs, SafeInt< U, E > rhs ) throw()
1522 {
1523 lhs = (T)( SafeInt< T, E >( lhs ) >> (U)rhs );
1524 return lhs;
1525 }
1526
1527 // Specific pointer overrides
1528 // Note - this function makes no attempt to ensure
1529 // that the resulting pointer is still in the buffer, only
1530 // that no int overflows happened on the way to getting the new pointer
1531 template < typename T, typename U, typename E >
1532 T*& operator +=( T*& lhs, SafeInt< U, E > rhs )
1533 {
1534 // Cast the pointer to a number so we can do arithmetic
1535 SafeInt< uintptr_t, E > ptr_val = reinterpret_cast< uintptr_t >( lhs );
1536 // Check first that rhs is valid for the type of ptrdiff_t
1537 // and that multiplying by sizeof( T ) doesn't overflow a ptrdiff_t
1538 // Next, we need to add 2 SafeInts of different types, so unbox the ptr_diff
1539 // Finally, cast the number back to a pointer of the correct type
1540 lhs = reinterpret_cast< T* >( (uintptr_t)( ptr_val + (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) );
1541 return lhs;
1542 }
1543
1544 template < typename T, typename U, typename E >
1545 T*& operator -=( T*& lhs, SafeInt< U, E > rhs )
1546 {
1547 // Cast the pointer to a number so we can do arithmetic
1548 SafeInt< size_t, E > ptr_val = reinterpret_cast< uintptr_t >( lhs );
1549 // See above for comments
1550 lhs = reinterpret_cast< T* >( (uintptr_t)( ptr_val - (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) );
1551 return lhs;
1552 }
1553
1554 template < typename T, typename U, typename E >
1555 T*& operator *=( T* lhs, SafeInt< U, E >)
1556 {
1557 static_assert( details::DependentFalse< T >::value, "SafeInt<T>: This operator explicitly not supported" );
1558 return lhs;
1559 }
1560
1561 template < typename T, typename U, typename E >
1562 T*& operator /=( T* lhs, SafeInt< U, E >)
1563 {
1564 static_assert( details::DependentFalse< T >::value, "SafeInt<T>: This operator explicitly not supported" );
1565 return lhs;
1566 }
1567
1568 template < typename T, typename U, typename E >
1569 T*& operator %=( T* lhs, SafeInt< U, E >)
1570 {
1571 static_assert( details::DependentFalse< T >::value, "SafeInt<T>: This operator explicitly not supported" );
1572 return lhs;
1573 }
1574
1575 template < typename T, typename U, typename E >
1576 T*& operator &=( T* lhs, SafeInt< U, E >)
1577 {
1578 static_assert( details::DependentFalse< T >::value, "SafeInt<T>: This operator explicitly not supported" );
1579 return lhs;
1580 }
1581
1582 template < typename T, typename U, typename E >
1583 T*& operator ^=( T* lhs, SafeInt< U, E >)
1584 {
1585 static_assert( details::DependentFalse< T >::value, "SafeInt<T>: This operator explicitly not supported" );
1586 return lhs;
1587 }
1588
1589 template < typename T, typename U, typename E >
1590 T*& operator |=( T* lhs, SafeInt< U, E >)
1591 {
1592 static_assert( details::DependentFalse< T >::value, "SafeInt<T>: This operator explicitly not supported" );
1593 return lhs;
1594 }
1595
1596 template < typename T, typename U, typename E >
1597 T*& operator <<=( T* lhs, SafeInt< U, E >)
1598 {
1599 static_assert( details::DependentFalse< T >::value, "SafeInt<T>: This operator explicitly not supported" );
1600 return lhs;
1601 }
1602
1603 template < typename T, typename U, typename E >
1604 T*& operator >>=( T* lhs, SafeInt< U, E >)
1605 {
1606 static_assert( details::DependentFalse< T >::value, "SafeInt<T>: This operator explicitly not supported" );
1607 return lhs;
1608 }
1609
1610 // Shift operators
1611 // NOTE - shift operators always return the type of the lhs argument
1612
1613 // Left shift
1614 template < typename T, typename U, typename E >
1615 SafeInt< U, E > operator <<( U lhs, SafeInt< T, E > bits ) throw()
1616 {
1617 _SAFEINT_SHIFT_ASSERT( !details::IntTraits< T >::isSigned || (T)bits >= 0 );
1618 _SAFEINT_SHIFT_ASSERT( (T)bits < (int)details::IntTraits< U >::bitCount );
1619
1620 return SafeInt< U, E >( (U)( lhs << (T)bits ) );
1621 }
1622
1623 // Right shift
1624 template < typename T, typename U, typename E >
throw()1625 SafeInt< U, E > operator >>( U lhs, SafeInt< T, E > bits ) throw()
1626 {
1627 _SAFEINT_SHIFT_ASSERT( !details::IntTraits< T >::isSigned || (T)bits >= 0 );
1628 _SAFEINT_SHIFT_ASSERT( (T)bits < (int)details::IntTraits< U >::bitCount );
1629
1630 return SafeInt< U, E >( (U)( lhs >> (T)bits ) );
1631 }
1632
1633 // Bitwise operators
1634 // This only makes sense if we're dealing with the same type and size
1635 // demand a type T, or something that fits into a type T.
1636
1637 // Bitwise &
1638 template < typename T, typename U, typename E >
throw()1639 SafeInt< T, E > operator &( U lhs, SafeInt< T, E > rhs ) throw()
1640 {
1641 return SafeInt< T, E >( details::BinaryAndHelper< T, U >::And( (T)rhs, lhs ) );
1642 }
1643
1644 // Bitwise XOR
1645 template < typename T, typename U, typename E >
1646 SafeInt< T, E > operator ^( U lhs, SafeInt< T, E > rhs ) throw()
1647 {
1648 return SafeInt< T, E >(details::BinaryXorHelper< T, U >::Xor( (T)rhs, lhs ) );
1649 }
1650
1651 // Bitwise OR
1652 template < typename T, typename U, typename E >
1653 SafeInt< T, E > operator |( U lhs, SafeInt< T, E > rhs ) throw()
1654 {
1655 return SafeInt< T, E >( details::BinaryOrHelper< T, U >::Or( (T)rhs, lhs ) );
1656 }
1657
1658 } // namespace utilities
1659
1660 } // namespace msl
1661
1662 #pragma pack(pop)
1663
1664 #pragma warning(pop) // Disable /Wall warnings
1665 #endif // RC_INVOKED
1666