Reactos
at master 1665 lines 52 kB view raw
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 264namespace msl 265{ 266 267namespace utilities 268{ 269 270enum 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 283namespace msl 284{ 285 286namespace utilities 287{ 288 289class SafeIntException 290{ 291public: 292 SafeIntException() { m_code = SafeIntNoError; } 293 SafeIntException( SafeIntError code ) 294 { 295 m_code = code; 296 } 297 SafeIntError m_code; 298}; 299 300struct SafeIntErrorPolicy_SafeIntException 301{ 302 static __declspec(noreturn) void SafeIntOnOverflow() 303 { 304 _SAFEINT_EXCEPTION_ASSERT(); 305 throw SafeIntException( SafeIntArithmeticOverflow ); 306 } 307 308 static __declspec(noreturn) void SafeIntOnDivZero() 309 { 310 _SAFEINT_EXCEPTION_ASSERT(); 311 throw SafeIntException( SafeIntDivideByZero ); 312 } 313}; 314 315struct SafeIntErrorPolicy_InvalidParameter 316{ 317 static __declspec(noreturn) void SafeIntOnOverflow() 318 { 319 _SAFEINT_EXCEPTION_ASSERT(); 320 _CRT_SECURE_INVALID_PARAMETER("SafeInt Arithmetic Overflow"); 321 } 322 323 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 334template < typename T, typename U > 335inline 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 341template < typename T, typename U > 342inline bool SafeEquals( const T t, const U u ) throw() 343{ 344 return details::EqualityTest< T, U >::IsEquals( t, u ); 345} 346 347template < typename T, typename U > 348inline bool SafeNotEquals( const T t, const U u ) throw() 349{ 350 return !details::EqualityTest< T, U >::IsEquals( t, u ); 351} 352 353template < typename T, typename U > 354inline bool SafeGreaterThan( const T t, const U u ) throw() 355{ 356 return details::GreaterThanTest< T, U >::GreaterThan( t, u ); 357} 358 359template < typename T, typename U > 360inline bool SafeGreaterThanEquals( const T t, const U u ) throw() 361{ 362 return !details::GreaterThanTest< U, T >::GreaterThan( u, t ); 363} 364 365template < typename T, typename U > 366inline bool SafeLessThan( const T t, const U u ) throw() 367{ 368 return details::GreaterThanTest< U, T >::GreaterThan( u, t ); 369} 370 371template < typename T, typename U > 372inline bool SafeLessThanEquals( const T t, const U u ) throw() 373{ 374 return !details::GreaterThanTest< T, U >::GreaterThan( t, u ); 375} 376 377template < typename T, typename U > 378inline 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 383template < typename T, typename U > 384inline 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 390template < typename T, typename U > 391inline 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 397template < typename T, typename U > 398inline 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 404template < typename T, typename U > 405inline 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 412template < typename T, typename E = _SAFEINT_DEFAULT_ERROR_POLICY > 413class SafeInt 414{ 415public: 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; 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 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 > 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 > 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 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 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 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 516 operator __int16() const 517 { 518 __int16 val; 519 details::SafeCastHelper< __int16, T, E >::Cast( m_int, val ); 520 return val; 521 } 522 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 530 operator __int32() const 531 { 532 __int32 val; 533 details::SafeCastHelper< __int32, T, E >::Cast( m_int, val ); 534 return val; 535 } 536 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 560 operator __int64() const 561 { 562 __int64 val; 563 details::SafeCastHelper< __int64, T, E >::Cast( m_int, val ); 564 return val; 565 } 566 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 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 587 T* Ptr() throw() { return &m_int; } 588 const T* Ptr() const throw() { return &m_int; } 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 > 902 bool operator >=( U rhs ) const throw() 903 { 904 return !details::GreaterThanTest< U, T >::GreaterThan( rhs, m_int ); 905 } 906 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 > 914 bool operator >( U rhs ) const throw() 915 { 916 return details::GreaterThanTest< T, U >::GreaterThan( m_int, rhs ); 917 } 918 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 > 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 > 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 > 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 > 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 & 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 > 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 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 > 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 > 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 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 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 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 > 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: 1219 const SafeInt< T, E >& Align2() { return Align< 1 >(); } 1220 const SafeInt< T, E >& Align4() { return Align< 2 >(); } 1221 const SafeInt< T, E >& Align8() { return Align< 3 >(); } 1222 const SafeInt< T, E >& Align16() { return Align< 4 >(); } 1223 const SafeInt< T, E >& Align32() { return Align< 5 >(); } 1224 const SafeInt< T, E >& Align64() { return Align< 6 >(); } 1225 1226private: 1227 T m_int; 1228}; 1229 1230// Externally defined functions for the case of U op SafeInt< T, E > 1231template < typename T, typename U, typename E > 1232bool operator <( U lhs, SafeInt< T, E > rhs ) throw() 1233{ 1234 return details::GreaterThanTest< T, U >::GreaterThan( (T)rhs, lhs ); 1235} 1236 1237template < typename T, typename U, typename E > 1238bool 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 1244template < typename T, typename U, typename E > 1245bool operator >( U lhs, SafeInt< T, E > rhs ) throw() 1246{ 1247 return details::GreaterThanTest< U, T >::GreaterThan( lhs, (T)rhs ); 1248} 1249 1250template < typename T, typename U, typename E > 1251bool 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 1257template < typename T, typename U, typename E > 1258bool operator >=( U lhs, SafeInt< T, E > rhs ) throw() 1259{ 1260 return !details::GreaterThanTest< T, U >::GreaterThan( (T)rhs, lhs ); 1261} 1262 1263template < typename T, typename U, typename E > 1264bool 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 1270template < typename T, typename U, typename E > 1271bool operator <=( U lhs, SafeInt< T, E > rhs ) throw() 1272{ 1273 return !details::GreaterThanTest< U, T >::GreaterThan( lhs, (T)rhs ); 1274} 1275 1276template < typename T, typename U, typename E > 1277bool 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 1284template < typename T, typename E > 1285bool operator ==( bool lhs, SafeInt< T, E > rhs ) throw() 1286{ 1287 return lhs == ( (T)rhs == 0 ? false : true ); 1288} 1289 1290template < typename T, typename U, typename E > 1291bool operator ==( U lhs, SafeInt< T, E > rhs ) throw() 1292{ 1293 return details::EqualityTest< T, U >::IsEquals((T)rhs, lhs); 1294} 1295 1296template < typename T, typename U, typename E > 1297bool 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 1303template < typename T, typename U, typename E > 1304bool operator !=( U lhs, SafeInt< T, E > rhs ) throw() 1305{ 1306 return !details::EqualityTest< T, U >::IsEquals( rhs, lhs ); 1307} 1308 1309template < typename T, typename E > 1310bool operator !=( bool lhs, SafeInt< T, E > rhs ) throw() 1311{ 1312 return ( (T)rhs == 0 ? false : true ) != lhs; 1313} 1314 1315template < typename T, typename U, typename E > 1316bool operator !=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) throw() 1317{ 1318 return !details::EqualityTest< T, U >::IsEquals( lhs, rhs ); 1319} 1320 1321// Modulus 1322template < typename T, typename U, typename E > 1323SafeInt< 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 1349template < typename T, typename U, typename E > 1350SafeInt< 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 1358template < 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 1426template < typename T, typename U, typename E > 1427SafeInt< 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 1435template < typename T, typename U, typename E > 1436SafeInt< 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// += 1447template < typename T, typename U, typename E > 1448T& 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 1456template < typename T, typename U, typename E > 1457T& 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 1465template < typename T, typename U, typename E > 1466T& 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 1474template < typename T, typename U, typename E > 1475T& 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 1483template < typename T, typename U, typename E > 1484T& 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 1492template < typename T, typename U, typename E > 1493T& operator &=( T& lhs, SafeInt< U, E > rhs ) throw() 1494{ 1495 lhs = details::BinaryAndHelper< T, U >::And( lhs, (U)rhs ); 1496 return lhs; 1497} 1498 1499template < typename T, typename U, typename E > 1500T& operator ^=( T& lhs, SafeInt< U, E > rhs ) throw() 1501{ 1502 lhs = details::BinaryXorHelper< T, U >::Xor( lhs, (U)rhs ); 1503 return lhs; 1504} 1505 1506template < typename T, typename U, typename E > 1507T& operator |=( T& lhs, SafeInt< U, E > rhs ) throw() 1508{ 1509 lhs = details::BinaryOrHelper< T, U >::Or( lhs, (U)rhs ); 1510 return lhs; 1511} 1512 1513template < typename T, typename U, typename E > 1514T& operator <<=( T& lhs, SafeInt< U, E > rhs ) throw() 1515{ 1516 lhs = (T)( SafeInt< T, E >( lhs ) << (U)rhs ); 1517 return lhs; 1518} 1519 1520template < typename T, typename U, typename E > 1521T& 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 1531template < typename T, typename U, typename E > 1532T*& 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 1544template < typename T, typename U, typename E > 1545T*& 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 1554template < typename T, typename U, typename E > 1555T*& 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 1561template < typename T, typename U, typename E > 1562T*& 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 1568template < typename T, typename U, typename E > 1569T*& 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 1575template < typename T, typename U, typename E > 1576T*& 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 1582template < typename T, typename U, typename E > 1583T*& 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 1589template < typename T, typename U, typename E > 1590T*& 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 1596template < typename T, typename U, typename E > 1597T*& 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 1603template < typename T, typename U, typename E > 1604T*& 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 1614template < typename T, typename U, typename E > 1615SafeInt< 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 1624template < typename T, typename U, typename E > 1625SafeInt< 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 & 1638template < typename T, typename U, typename E > 1639SafeInt< 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 1645template < typename T, typename U, typename E > 1646SafeInt< 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 1652template < typename T, typename U, typename E > 1653SafeInt< 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