xref: /reactos/sdk/include/ucrt/safeint_internal.h (revision 04e0dc4a)
1 /***
2 *safeint_internal.h - Internal details for SafeInt (see safeint.h)
3 *
4 *       Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose:
7 *       Private internal details for SafeInt.
8 *       The constructs and functions in Microsoft::Utilities::details are not
9 *       meant to be used by external code and can change at any time.
10 *
11 ****/
12 
13 #pragma once
14 
15 #include <crtdbg.h>
16 
17 #pragma pack(push, _CRT_PACKING)
18 
19 namespace msl
20 {
21 
22 namespace utilities
23 {
24 
25 namespace details
26 {
27 #pragma warning(push)
28 #pragma warning(disable:4702)
29 
30 template < typename T >
31 class DependentFalse { public: enum{ value = false }; };
32 
33 template < typename T > class NumericType;
34 
35 template <> class NumericType<bool>             { public: enum{ isBool = true,  isFloat = false, isInt = false }; };
36 template <> class NumericType<char>             { public: enum{ isBool = false, isFloat = false, isInt = true }; };
37 template <> class NumericType<unsigned char>    { public: enum{ isBool = false, isFloat = false, isInt = true }; };
38 template <> class NumericType<signed char>      { public: enum{ isBool = false, isFloat = false, isInt = true }; };
39 template <> class NumericType<short>            { public: enum{ isBool = false, isFloat = false, isInt = true }; };
40 template <> class NumericType<unsigned short>   { public: enum{ isBool = false, isFloat = false, isInt = true }; };
41 #ifdef _NATIVE_WCHAR_T_DEFINED
42 template <> class NumericType<wchar_t>          { public: enum{ isBool = false, isFloat = false, isInt = true }; };
43 #endif  /* _NATIVE_WCHAR_T_DEFINED */
44 template <> class NumericType<int>              { public: enum{ isBool = false, isFloat = false, isInt = true }; };
45 template <> class NumericType<unsigned int>     { public: enum{ isBool = false, isFloat = false, isInt = true }; };
46 template <> class NumericType<long>             { public: enum{ isBool = false, isFloat = false, isInt = true }; };
47 template <> class NumericType<unsigned long>    { public: enum{ isBool = false, isFloat = false, isInt = true }; };
48 template <> class NumericType<__int64>          { public: enum{ isBool = false, isFloat = false, isInt = true }; };
49 template <> class NumericType<unsigned __int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
50 template <> class NumericType<float>            { public: enum{ isBool = false, isFloat = true,  isInt = false }; };
51 template <> class NumericType<double>           { public: enum{ isBool = false, isFloat = true,  isInt = false }; };
52 template <> class NumericType<long double>      { public: enum{ isBool = false, isFloat = true,  isInt = false }; };
53 // Catch-all for anything not supported
54 template < typename T > class NumericType       { public: enum{ isBool = false, isFloat = false, isInt = false }; };
55 
56 
57 template < typename T > class IntTraits
58 {
59 public:
60     static_assert( NumericType<T>::isInt || NumericType<T>::isBool, "non-integral type T" );
61     enum
62     {
63 #pragma warning(suppress:4804)
64         isSigned  = ( (T)(-1) < 0 ),
65         is64Bit   = ( sizeof(T) == 8 ),
66         is32Bit   = ( sizeof(T) == 4 ),
67         is16Bit   = ( sizeof(T) == 2 ),
68         is8Bit    = ( sizeof(T) == 1 ),
69         isLT32Bit = ( sizeof(T) < 4 ),
70         isLT64Bit = ( sizeof(T) < 8 ),
71         isInt8    = ( sizeof(T) == 1 && isSigned ),
72         isUint8   = ( sizeof(T) == 1 && !isSigned ),
73         isInt16   = ( sizeof(T) == 2 && isSigned ),
74         isUint16  = ( sizeof(T) == 2 && !isSigned ),
75         isInt32   = ( sizeof(T) == 4 && isSigned ),
76         isUint32  = ( sizeof(T) == 4 && !isSigned ),
77         isInt64   = ( sizeof(T) == 8 && isSigned ),
78         isUint64  = ( sizeof(T) == 8 && !isSigned ),
79         bitCount  = ( sizeof(T)*8 ),
80 #pragma warning(suppress:4804)
81         isBool    = NumericType<T>::isBool
82     };
83 
84 #pragma warning(push)
85 #pragma warning(disable:4310)
86 #pragma warning(disable:4804) // suppress warning about '<<' being an unsafe operation when T is bool
87     const static T maxInt = isSigned ? ((T)~((T)1 << (T)(bitCount-1))) : ((T)(~(T)0));
88     const static T minInt = isSigned ? ((T)((T)1 << (T)(bitCount-1)))  : ((T)0);
89 #pragma warning(pop)
90 };
91 
92 // this is strictly internal and not to be used as a policy in SafeInt<>
93 struct SafeIntErrorPolicy_NoThrow
94 {
SafeIntOnOverflowSafeIntErrorPolicy_NoThrow95     static void SafeIntOnOverflow()
96     {
97     }
98 
SafeIntOnDivZeroSafeIntErrorPolicy_NoThrow99     static void SafeIntOnDivZero()
100     {
101     }
102 };
103 
104 template < typename T, typename U > class SafeIntCompare
105 {
106 public:
107     enum
108     {
109         isBothSigned   = (IntTraits< T >::isSigned && IntTraits< U >::isSigned),
110         isBothUnsigned = (!IntTraits< T >::isSigned && !IntTraits< U >::isSigned),
111         isLikeSigned   = (static_cast<bool>(IntTraits< T >::isSigned) == static_cast<bool>(IntTraits< U >::isSigned)),
112         isCastOK       = ((isLikeSigned && sizeof(T) >= sizeof(U)) ||
113         (IntTraits< T >::isSigned && sizeof(T) > sizeof(U))),
114         isBothLT32Bit  = (IntTraits< T >::isLT32Bit && IntTraits< U >::isLT32Bit),
115         isBothLT64Bit  = (IntTraits< T >::isLT64Bit && IntTraits< U >::isLT64Bit)
116     };
117 };
118 
119 template < typename U > class SafeIntCompare< float, U >
120 {
121 public:
122     enum
123     {
124         isBothSigned   = IntTraits< U >::isSigned,
125         isBothUnsigned = false,
126         isLikeSigned   = IntTraits< U >::isSigned,
127         isCastOK       = true
128     };
129 };
130 
131 template < typename U > class SafeIntCompare< double, U >
132 {
133 public:
134     enum
135     {
136         isBothSigned   = IntTraits< U >::isSigned,
137         isBothUnsigned = false,
138         isLikeSigned   = IntTraits< U >::isSigned,
139         isCastOK       = true
140     };
141 };
142 
143 template < typename U > class SafeIntCompare< long double, U >
144 {
145 public:
146     enum
147     {
148         isBothSigned   = IntTraits< U >::isSigned,
149         isBothUnsigned = false,
150         isLikeSigned   = IntTraits< U >::isSigned,
151         isCastOK       = true
152     };
153 };
154 
155 //all of the arithmetic operators can be solved by the same code within
156 //each of these regions without resorting to compile-time constant conditionals
157 //most operators collapse the problem into less than the 22 zones, but this is used
158 //as the first cut
159 //using this also helps ensure that we handle all of the possible cases correctly
160 
161 template < typename T, typename U > class IntRegion
162 {
163 public:
164     enum
165     {
166         //unsigned-unsigned zone
167         IntZone_UintLT32_UintLT32 = SafeIntCompare< T,U >::isBothUnsigned && SafeIntCompare< T,U >::isBothLT32Bit,
168         IntZone_Uint32_UintLT64   = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit,
169         IntZone_UintLT32_Uint32   = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit,
170         IntZone_Uint64_Uint       = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is64Bit,
171         IntZone_UintLT64_Uint64   = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit,
172         //unsigned-signed
173         IntZone_UintLT32_IntLT32  = !IntTraits< T >::isSigned && IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit,
174         IntZone_Uint32_IntLT64    = IntTraits< T >::isUint32 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit,
175         IntZone_UintLT32_Int32    = !IntTraits< T >::isSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::isInt32,
176         IntZone_Uint64_Int        = IntTraits< T >::isUint64 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit,
177         IntZone_UintLT64_Int64    = !IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isInt64,
178         IntZone_Uint64_Int64      = IntTraits< T >::isUint64 && IntTraits< U >::isInt64,
179         //signed-signed
180         IntZone_IntLT32_IntLT32   = SafeIntCompare< T,U >::isBothSigned && SafeIntCompare< T, U >::isBothLT32Bit,
181         IntZone_Int32_IntLT64     = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit,
182         IntZone_IntLT32_Int32     = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit,
183         IntZone_Int64_Int64       = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isInt64 && IntTraits< U >::isInt64,
184         IntZone_Int64_Int         = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is64Bit && IntTraits< U >::isLT64Bit,
185         IntZone_IntLT64_Int64     = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit,
186         //signed-unsigned
187         IntZone_IntLT32_UintLT32  = IntTraits< T >::isSigned && !IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit,
188         IntZone_Int32_UintLT32    = IntTraits< T >::isInt32 && !IntTraits< U >::isSigned && IntTraits< U >::isLT32Bit,
189         IntZone_IntLT64_Uint32    = IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isUint32,
190         IntZone_Int64_UintLT64    = IntTraits< T >::isInt64 && !IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit,
191         IntZone_Int_Uint64        = IntTraits< T >::isSigned && IntTraits< U >::isUint64 && IntTraits< T >::isLT64Bit,
192         IntZone_Int64_Uint64      = IntTraits< T >::isInt64 && IntTraits< U >::isUint64
193     };
194 };
195 
196 // useful function to help with getting the magnitude of a negative number
197 enum AbsMethod
198 {
199     AbsMethodInt,
200     AbsMethodInt64,
201     AbsMethodNoop
202 };
203 
204 template < typename T >
205 class GetAbsMethod
206 {
207 public:
208     enum
209     {
210         method = IntTraits< T >::isLT64Bit && IntTraits< T >::isSigned ? AbsMethodInt :
211         IntTraits< T >::isInt64 ? AbsMethodInt64 : AbsMethodNoop
212     };
213 };
214 
215 template < typename T, int Method = GetAbsMethod< T >::method > class AbsValueHelper;
216 
217 template < typename T > class AbsValueHelper < T, AbsMethodInt >
218 {
219 public:
Abs(T t)220     static unsigned __int32 Abs( T t ) throw()
221     {
222         _ASSERTE( t < 0 );
223         return (unsigned __int32)-t;
224     }
225 };
226 
227 template < typename T > class AbsValueHelper < T, AbsMethodInt64 >
228 {
229 public:
Abs(T t)230     static unsigned __int64 Abs( T t ) throw()
231     {
232         _ASSERTE( t < 0 );
233         return (unsigned __int64)-t;
234     }
235 };
236 
237 template < typename T > class AbsValueHelper < T, AbsMethodNoop >
238 {
239 public:
Abs(T t)240     static T Abs( T t ) throw()
241     {
242         // Why are you calling Abs on an unsigned number ???
243         _ASSERTE( ("AbsValueHelper::Abs should not be called with an unsigned integer type", 0) );
244         return t;
245     }
246 };
247 
248 template < typename T, typename E, bool fSigned > class NegationHelper;
249 
250 template < typename T, typename E > class NegationHelper < T, E, true > // Signed
251 {
252 public:
Negative(T t,T & ret)253     static SafeIntError Negative( T t, T& ret )
254     {
255         // corner case
256         if( t != IntTraits< T >::minInt )
257         {
258             // cast prevents unneeded checks in the case of small ints
259             ret = -t;
260             return SafeIntNoError;
261         }
262         E::SafeIntOnOverflow();
263         return SafeIntArithmeticOverflow;
264     }
265 };
266 
267 
268 template < typename T, typename E > class NegationHelper < T, E, false > // unsigned
269 {
270 public:
Negative(T t,T & ret)271     static SafeIntError Negative( T t, T& ret ) throw()
272     {
273         _SAFEINT_UNSIGNED_NEGATION_BEHAVIOR();
274 
275 #pragma warning(suppress:4127)
276         _ASSERTE( !IntTraits<T>::isLT32Bit );
277 
278 #pragma warning(suppress:4146)
279         ret = -t;
280         return SafeIntNoError;
281     }
282 };
283 
284 //core logic to determine casting behavior
285 enum CastMethod
286 {
287     CastOK = 0,
288     CastCheckLTZero,
289     CastCheckGTMax,
290     CastCheckMinMaxUnsigned,
291     CastCheckMinMaxSigned,
292     CastFromFloat,
293     CastToBool,
294     CastFromBool
295 };
296 
297 template < typename ToType, typename FromType >
298 class GetCastMethod
299 {
300 public:
301     enum
302     {
303         method =  ( IntTraits< FromType >::isBool &&
304         !IntTraits< ToType >::isBool )                    ? CastFromBool :
305 
306         ( !IntTraits< FromType >::isBool &&
307         IntTraits< ToType >::isBool )                     ? CastToBool :
308         ( NumericType< FromType >::isFloat &&
309         !NumericType< ToType >::isFloat )                 ? CastFromFloat :
310 
311         ( SafeIntCompare< ToType, FromType >::isCastOK ||
312         ( NumericType< ToType >::isFloat &&
313         !NumericType< FromType >::isFloat ) )          ? CastOK :
314 
315         ( ( IntTraits< ToType >::isSigned &&
316         !IntTraits< FromType >::isSigned &&
317         sizeof( FromType ) >= sizeof( ToType ) ) ||
318         ( SafeIntCompare< ToType, FromType >::isBothUnsigned &&
319         sizeof( FromType ) > sizeof( ToType ) ) )      ? CastCheckGTMax :
320 
321         ( !IntTraits< ToType >::isSigned &&
322         IntTraits< FromType >::isSigned &&
323         sizeof( ToType ) >= sizeof( FromType ) )          ? CastCheckLTZero :
324 
325         ( !IntTraits< ToType >::isSigned )                    ? CastCheckMinMaxUnsigned
326         : CastCheckMinMaxSigned
327     };
328 };
329 
330 template < typename T, typename U, typename E,
331     int Method = GetCastMethod< T, U >::method > class SafeCastHelper;
332 
333 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastOK >
334 {
335 public:
Cast(U u,T & t)336     static SafeIntError Cast( U u, T& t ) throw()
337     {
338         t = (T)u;
339         return SafeIntNoError;
340     }
341 };
342 
343 // special case floats and doubles
344 // tolerate loss of precision
345 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastFromFloat >
346 {
347 public:
Cast(U u,T & t)348     static SafeIntError Cast( U u, T& t )
349     {
350         if( u <= (U)IntTraits< T >::maxInt &&
351             u >= (U)IntTraits< T >::minInt )
352         {
353             t = (T)u;
354             return SafeIntNoError;
355         }
356 
357         E::SafeIntOnOverflow();
358         return SafeIntArithmeticOverflow;
359     }
360 };
361 
362 // Match on any method where a bool is cast to type T
363 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastFromBool >
364 {
365 public:
Cast(bool b,T & t)366     static SafeIntError Cast( bool b, T& t ) throw()
367     {
368         t = (T)( b ? 1 : 0 );
369         return SafeIntNoError;
370     }
371 };
372 
373 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastToBool >
374 {
375 public:
Cast(T t,bool & b)376     static SafeIntError Cast( T t, bool& b ) throw()
377     {
378         b = !!t;
379         return SafeIntNoError;
380     }
381 };
382 
383 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckLTZero >
384 {
385 public:
Cast(U u,T & t)386     static SafeIntError Cast( U u, T& t )
387     {
388         if( u < 0 )
389         {
390             E::SafeIntOnOverflow();
391             return SafeIntArithmeticOverflow;
392         }
393 
394         t = (T)u;
395         return SafeIntNoError;
396     }
397 };
398 
399 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckGTMax >
400 {
401 public:
Cast(U u,T & t)402     static SafeIntError Cast( U u, T& t )
403     {
404         if( u > IntTraits< T >::maxInt )
405         {
406             E::SafeIntOnOverflow();
407             return SafeIntArithmeticOverflow;
408         }
409 
410         t = (T)u;
411         return SafeIntNoError;
412     }
413 };
414 
415 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckMinMaxUnsigned >
416 {
417 public:
Cast(U u,T & t)418     static SafeIntError Cast( U u, T& t )
419     {
420         // U is signed - T could be either signed or unsigned
421         if( u > IntTraits< T >::maxInt || u < 0 )
422         {
423             E::SafeIntOnOverflow();
424             return SafeIntArithmeticOverflow;
425         }
426 
427         t = (T)u;
428         return SafeIntNoError;
429     }
430 };
431 
432 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckMinMaxSigned >
433 {
434 public:
Cast(U u,T & t)435     static SafeIntError Cast( U u, T& t )
436     {
437         // T, U are signed
438         if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt )
439         {
440             E::SafeIntOnOverflow();
441             return SafeIntArithmeticOverflow;
442         }
443 
444         t = (T)u;
445         return SafeIntNoError;
446     }
447 };
448 
449 //core logic to determine whether a comparison is valid, or needs special treatment
450 enum ComparisonMethod
451 {
452     ComparisonMethod_Ok = 0,
453     ComparisonMethod_CastInt,
454     ComparisonMethod_CastInt64,
455     ComparisonMethod_UnsignedT,
456     ComparisonMethod_UnsignedU
457 };
458 
459 template < typename T, typename U >
460 class ValidComparison
461 {
462 public:
463     enum
464     {
465 #if _SAFEINT_USE_ANSI_CONVERSIONS
466         method = ComparisonMethod_Ok
467 #else  /* _SAFEINT_USE_ANSI_CONVERSIONS */
468         method = ( ( SafeIntCompare< T, U >::isLikeSigned )                              ? ComparisonMethod_Ok :
469         ( ( IntTraits< T >::isSigned && sizeof(T) < 8 && sizeof(U) < 4 ) ||
470         ( IntTraits< U >::isSigned && sizeof(T) < 4 && sizeof(U) < 8 ) )  ? ComparisonMethod_CastInt :
471         ( ( IntTraits< T >::isSigned && sizeof(U) < 8 ) ||
472         ( IntTraits< U >::isSigned && sizeof(T) < 8 ) )                   ? ComparisonMethod_CastInt64 :
473         ( !IntTraits< T >::isSigned )                                       ? ComparisonMethod_UnsignedT :
474         ComparisonMethod_UnsignedU )
475 #endif  /* _SAFEINT_USE_ANSI_CONVERSIONS */
476     };
477 };
478 
479 template <typename T, typename U, int Method = ValidComparison< T, U >::method > class EqualityTest;
480 
481 template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_Ok >
482 {
483 public:
IsEquals(const T t,const U u)484     static bool IsEquals( const T t, const U u ) throw() { return ( t == u ); }
485 };
486 
487 template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt >
488 {
489 public:
IsEquals(const T t,const U u)490     static bool IsEquals( const T t, const U u ) throw() { return ( (int)t == (int)u ); }
491 };
492 
493 template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt64 >
494 {
495 public:
IsEquals(const T t,const U u)496     static bool IsEquals( const T t, const U u ) throw() { return ( (__int64)t == (__int64)u ); }
497 };
498 
499 template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedT >
500 {
501 public:
IsEquals(const T t,const U u)502     static bool IsEquals( const T t, const U u ) throw()
503     {
504         //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
505         if( u < 0 )
506         {
507             return false;
508         }
509 
510         //else safe to cast to type T
511         return ( t == (T)u );
512     }
513 };
514 
515 template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedU>
516 {
517 public:
IsEquals(const T t,const U u)518     static bool IsEquals( const T t, const U u ) throw()
519     {
520         //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
521         if( t < 0 )
522         {
523             return false;
524         }
525 
526         //else safe to cast to type U
527         return ( (U)t == u );
528     }
529 };
530 
531 template <typename T, typename U, int Method = ValidComparison< T, U >::method > class GreaterThanTest;
532 
533 template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_Ok >
534 {
535 public:
GreaterThan(const T t,const U u)536     static bool GreaterThan( const T t, const U u ) throw() { return ( t > u ); }
537 };
538 
539 template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt >
540 {
541 public:
GreaterThan(const T t,const U u)542     static bool GreaterThan( const T t, const U u ) throw() { return ( (int)t > (int)u ); }
543 };
544 
545 template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt64 >
546 {
547 public:
GreaterThan(const T t,const U u)548     static bool GreaterThan( const T t, const U u ) throw() { return ( (__int64)t > (__int64)u ); }
549 };
550 
551 template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedT >
552 {
553 public:
GreaterThan(const T t,const U u)554     static bool GreaterThan( const T t, const U u ) throw()
555     {
556         // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
557         if( u < 0 )
558         {
559             return SafeIntNoError;
560         }
561 
562         // else safe to cast to type T
563         return ( t > (T)u );
564     }
565 };
566 
567 template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedU >
568 {
569 public:
GreaterThan(const T t,const U u)570     static bool GreaterThan( const T t, const U u ) throw()
571     {
572         // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
573         if( t < 0 )
574         {
575             return false;
576         }
577 
578         // else safe to cast to type U
579         return ( (U)t > u );
580     }
581 };
582 
583 // Modulus is simpler than comparison, but follows much the same logic
584 // using this set of functions, it can't fail except in a div 0 situation
585 template <typename T, typename U, typename E, int Method = ValidComparison< T, U >::method > class ModulusHelper;
586 
587 template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_Ok>
588 {
589 public:
Modulus(const T & t,const U & u,T & result)590     static SafeIntError Modulus( const T& t, const U& u, T& result )
591     {
592         if(u == 0)
593         {
594             E::SafeIntOnDivZero();
595             return SafeIntDivideByZero;
596         }
597 
598         // trap corner case
599 #pragma warning(suppress:4127)
600         if( IntTraits< U >::isSigned )
601         {
602             if(u == -1)
603             {
604                 result = 0;
605                 return SafeIntNoError;
606             }
607         }
608 
609         result = (T)(t % u);
610         return SafeIntNoError;
611     }
612 };
613 
614 template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_CastInt>
615 {
616 public:
Modulus(const T & t,const U & u,T & result)617     static SafeIntError Modulus( const T& t, const U& u, T& result )
618     {
619         if(u == 0)
620         {
621             E::SafeIntOnDivZero();
622             return SafeIntDivideByZero;
623         }
624 
625         // trap corner case
626 #pragma warning(suppress:4127)
627         if( IntTraits< U >::isSigned )
628         {
629             if(u == -1)
630             {
631                 result = 0;
632                 return SafeIntNoError;
633             }
634         }
635 
636         result = (T)(t % u);
637         return SafeIntNoError;
638     }
639 };
640 
641 template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_CastInt64>
642 {
643 public:
Modulus(const T & t,const U & u,T & result)644     static SafeIntError Modulus( const T& t, const U& u, T& result )
645     {
646         if(u == 0)
647         {
648             E::SafeIntOnDivZero();
649             return SafeIntDivideByZero;
650         }
651 
652 #pragma warning(suppress:4127)
653         if(IntTraits< U >::isSigned && u == -1)
654         {
655             result = 0;
656         }
657         else
658         {
659             result = (T)((__int64)t % (__int64)u);
660         }
661 
662         return SafeIntNoError;
663     }
664 };
665 
666 // T is unsigned __int64, U is any signed int
667 template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_UnsignedT>
668 {
669 public:
Modulus(const T & t,const U & u,T & result)670     static SafeIntError Modulus( const T& t, const U& u, T& result )
671     {
672         if(u == 0)
673         {
674             E::SafeIntOnDivZero();
675             return SafeIntDivideByZero;
676         }
677 
678         // u could be negative - if so, need to convert to positive
679         // casts below are always safe due to the way modulus works
680         if(u < 0)
681         {
682             result = (T)(t % AbsValueHelper< U >::Abs(u));
683         }
684         else
685         {
686             result = (T)(t % u);
687         }
688 
689         return SafeIntNoError;
690     }
691 };
692 
693 // U is unsigned __int64, T any signed int
694 template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_UnsignedU>
695 {
696 public:
Modulus(const T & t,const U & u,T & result)697     static SafeIntError Modulus( const T& t, const U& u, T& result )
698     {
699         if(u == 0)
700         {
701             E::SafeIntOnDivZero();
702             return SafeIntDivideByZero;
703         }
704 
705         //t could be negative - if so, need to convert to positive
706         if(t < 0)
707         {
708             result = -(T)( AbsValueHelper< T >::Abs( t ) % u );
709         }
710         else
711         {
712             result = (T)((T)t % u);
713         }
714 
715         return SafeIntNoError;
716     }
717 };
718 
719 //core logic to determine method to check multiplication
720 enum MultiplicationState
721 {
722     MultiplicationState_CastInt = 0,  // One or both signed, smaller than 32-bit
723     MultiplicationState_CastInt64,    // One or both signed, smaller than 64-bit
724     MultiplicationState_CastUint,     // Both are unsigned, smaller than 32-bit
725     MultiplicationState_CastUint64,   // Both are unsigned, both 32-bit or smaller
726     MultiplicationState_Uint64Uint,   // Both are unsigned, lhs 64-bit, rhs 32-bit or smaller
727     MultiplicationState_Uint64Uint64, // Both are unsigned int64
728     MultiplicationState_Uint64Int,    // lhs is unsigned int64, rhs int32
729     MultiplicationState_Uint64Int64,  // lhs is unsigned int64, rhs signed int64
730     MultiplicationState_UintUint64,   // Both are unsigned, lhs 32-bit or smaller, rhs 64-bit
731     MultiplicationState_UintInt64,    // lhs unsigned 32-bit or less, rhs int64
732     MultiplicationState_Int64Uint,    // lhs int64, rhs unsigned int32
733     MultiplicationState_Int64Int64,   // lhs int64, rhs int64
734     MultiplicationState_Int64Int,     // lhs int64, rhs int32
735     MultiplicationState_IntUint64,    // lhs int, rhs unsigned int64
736     MultiplicationState_IntInt64,     // lhs int, rhs int64
737     MultiplicationState_Int64Uint64,  // lhs int64, rhs uint64
738     MultiplicationState_Error
739 };
740 
741 template < typename T, typename U >
742 class MultiplicationMethod
743 {
744 public:
745     enum
746     {
747         // unsigned-unsigned
748         method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32  ? MultiplicationState_CastUint :
749         (IntRegion< T,U >::IntZone_Uint32_UintLT64 ||
750         IntRegion< T,U >::IntZone_UintLT32_Uint32)   ? MultiplicationState_CastUint64 :
751         SafeIntCompare< T,U >::isBothUnsigned &&
752         IntTraits< T >::isUint64 && IntTraits< U >::isUint64 ? MultiplicationState_Uint64Uint64 :
753         (IntRegion< T,U >::IntZone_Uint64_Uint)       ? MultiplicationState_Uint64Uint :
754         (IntRegion< T,U >::IntZone_UintLT64_Uint64)   ? MultiplicationState_UintUint64 :
755         // unsigned-signed
756         (IntRegion< T,U >::IntZone_UintLT32_IntLT32)  ? MultiplicationState_CastInt :
757         (IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
758         IntRegion< T,U >::IntZone_UintLT32_Int32)    ? MultiplicationState_CastInt64 :
759         (IntRegion< T,U >::IntZone_Uint64_Int)        ? MultiplicationState_Uint64Int :
760         (IntRegion< T,U >::IntZone_UintLT64_Int64)    ? MultiplicationState_UintInt64 :
761         (IntRegion< T,U >::IntZone_Uint64_Int64)      ? MultiplicationState_Uint64Int64 :
762         // signed-signed
763         (IntRegion< T,U >::IntZone_IntLT32_IntLT32)   ? MultiplicationState_CastInt :
764         (IntRegion< T,U >::IntZone_Int32_IntLT64 ||
765         IntRegion< T,U >::IntZone_IntLT32_Int32)     ? MultiplicationState_CastInt64 :
766         (IntRegion< T,U >::IntZone_Int64_Int64)       ? MultiplicationState_Int64Int64 :
767         (IntRegion< T,U >::IntZone_Int64_Int)         ? MultiplicationState_Int64Int :
768         (IntRegion< T,U >::IntZone_IntLT64_Int64)     ? MultiplicationState_IntInt64 :
769         // signed-unsigned
770         (IntRegion< T,U >::IntZone_IntLT32_UintLT32)  ? MultiplicationState_CastInt :
771         (IntRegion< T,U >::IntZone_Int32_UintLT32 ||
772         IntRegion< T,U >::IntZone_IntLT64_Uint32)    ? MultiplicationState_CastInt64 :
773         (IntRegion< T,U >::IntZone_Int64_UintLT64)    ? MultiplicationState_Int64Uint :
774         (IntRegion< T,U >::IntZone_Int_Uint64)        ? MultiplicationState_IntUint64 :
775         (IntRegion< T,U >::IntZone_Int64_Uint64       ? MultiplicationState_Int64Uint64 :
776         MultiplicationState_Error ) )
777     };
778 };
779 
780 template <typename T, typename U, typename E, int Method = MultiplicationMethod< T, U >::method > class MultiplicationHelper;
781 
782 template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastInt>
783 {
784 public:
785     //accepts signed, both less than 32-bit
Multiply(const T & t,const U & u,T & ret)786     static SafeIntError Multiply( const T& t, const U& u, T& ret )
787     {
788         int tmp = t * u;
789 
790         if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt )
791         {
792             E::SafeIntOnOverflow();
793             return SafeIntArithmeticOverflow;
794         }
795 
796         ret = (T)tmp;
797         return SafeIntNoError;
798     }
799 };
800 
801 template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastUint >
802 {
803 public:
804     //accepts unsigned, both less than 32-bit
Multiply(const T & t,const U & u,T & ret)805     static SafeIntError Multiply( const T& t, const U& u, T& ret )
806     {
807         unsigned int tmp = t * u;
808 
809         if( tmp > IntTraits< T >::maxInt )
810         {
811             E::SafeIntOnOverflow();
812             return SafeIntArithmeticOverflow;
813         }
814 
815         ret = (T)tmp;
816         return SafeIntNoError;
817     }
818 };
819 
820 template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastInt64>
821 {
822 public:
823     //mixed signed or both signed where at least one argument is 32-bit, and both a 32-bit or less
Multiply(const T & t,const U & u,T & ret)824     static SafeIntError Multiply( const T& t, const U& u, T& ret )
825     {
826         __int64 tmp = (__int64)t * (__int64)u;
827 
828         if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt)
829         {
830             E::SafeIntOnOverflow();
831             return SafeIntArithmeticOverflow;
832         }
833 
834         ret = (T)tmp;
835         return SafeIntNoError;
836     }
837 };
838 
839 template < typename T, typename U, typename E  > class MultiplicationHelper< T, U, E, MultiplicationState_CastUint64>
840 {
841 public:
842     //both unsigned where at least one argument is 32-bit, and both are 32-bit or less
Multiply(const T & t,const U & u,T & ret)843     static SafeIntError Multiply( const T& t, const U& u, T& ret )
844     {
845         unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u;
846 
847         if(tmp > (unsigned __int64)IntTraits< T >::maxInt)
848         {
849             E::SafeIntOnOverflow();
850             return SafeIntArithmeticOverflow;
851         }
852 
853         ret = (T)tmp;
854         return SafeIntNoError;
855     }
856 };
857 
858 // T = left arg and return type
859 // U = right arg
860 template < typename T, typename U, typename E > class LargeIntRegMultiply;
861 
862 template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >
863 {
864 public:
RegMultiply(const unsigned __int64 & a,const unsigned __int64 & b,unsigned __int64 & ret)865     static SafeIntError RegMultiply( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64& ret )
866     {
867         unsigned __int32 aHigh, aLow, bHigh, bLow;
868 
869         // Consider that a*b can be broken up into:
870         // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow)
871         // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)
872         // Note - same approach applies for 128 bit math on a 64-bit system
873 
874         aHigh = (unsigned __int32)(a >> 32);
875         aLow  = (unsigned __int32)a;
876         bHigh = (unsigned __int32)(b >> 32);
877         bLow  = (unsigned __int32)b;
878 
879         ret = 0;
880 
881         if(aHigh == 0)
882         {
883             if(bHigh != 0)
884             {
885                 ret = (unsigned __int64)aLow * (unsigned __int64)bHigh;
886             }
887         }
888         else if(bHigh == 0)
889         {
890             if(aHigh != 0)
891             {
892                 ret = (unsigned __int64)aHigh * (unsigned __int64)bLow;
893             }
894         }
895         else
896         {
897             E::SafeIntOnOverflow();
898             return SafeIntArithmeticOverflow;
899         }
900 
901         if(ret != 0)
902         {
903             unsigned __int64 tmp;
904 
905             if((unsigned __int32)(ret >> 32) != 0)
906             {
907                 E::SafeIntOnOverflow();
908                 return SafeIntArithmeticOverflow;
909             }
910 
911             ret <<= 32;
912             tmp = (unsigned __int64)aLow * (unsigned __int64)bLow;
913             ret += tmp;
914 
915             if(ret < tmp)
916             {
917                 E::SafeIntOnOverflow();
918                 return SafeIntArithmeticOverflow;
919             }
920 
921             return SafeIntNoError;
922         }
923 
924         ret = (unsigned __int64)aLow * (unsigned __int64)bLow;
925         return SafeIntNoError;
926     }
927 };
928 
929 template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >
930 {
931 public:
RegMultiply(const unsigned __int64 & a,unsigned __int32 b,unsigned __int64 & ret)932     static SafeIntError RegMultiply( const unsigned __int64& a, unsigned __int32 b, unsigned __int64& ret )
933     {
934         unsigned __int32 aHigh, aLow;
935 
936         // Consider that a*b can be broken up into:
937         // (aHigh * 2^32 + aLow) * b
938         // => (aHigh * b * 2^32) + (aLow * b)
939 
940         aHigh = (unsigned __int32)(a >> 32);
941         aLow  = (unsigned __int32)a;
942 
943         ret = 0;
944 
945         if(aHigh != 0)
946         {
947             ret = (unsigned __int64)aHigh * (unsigned __int64)b;
948 
949             unsigned __int64 tmp;
950 
951             if((unsigned __int32)(ret >> 32) != 0)
952             {
953                 E::SafeIntOnOverflow();
954                 return SafeIntArithmeticOverflow;
955             }
956 
957             ret <<= 32;
958             tmp = (unsigned __int64)aLow * (unsigned __int64)b;
959             ret += tmp;
960 
961             if(ret < tmp)
962             {
963                 E::SafeIntOnOverflow();
964                 return SafeIntArithmeticOverflow;
965             }
966 
967             return SafeIntNoError;
968         }
969 
970         ret = (unsigned __int64)aLow * (unsigned __int64)b;
971         return SafeIntNoError;
972     }
973 };
974 
975 template< typename E > class LargeIntRegMultiply< unsigned __int64, signed __int32, E >
976 {
977 public:
RegMultiply(const unsigned __int64 & a,signed __int32 b,unsigned __int64 & ret)978     static SafeIntError RegMultiply( const unsigned __int64& a, signed __int32 b, unsigned __int64& ret )
979     {
980         if( b < 0 && a != 0 )
981         {
982             E::SafeIntOnOverflow();
983             return SafeIntArithmeticOverflow;
984         }
985 
986         return LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::RegMultiply(a, (unsigned __int32)b, ret);
987     }
988 };
989 
990 template< typename E > class LargeIntRegMultiply< unsigned __int64, signed __int64, E >
991 {
992 public:
RegMultiply(const unsigned __int64 & a,signed __int64 b,unsigned __int64 & ret)993     static SafeIntError RegMultiply( const unsigned __int64& a, signed __int64 b, unsigned __int64& ret )
994     {
995         if( b < 0 && a != 0 )
996         {
997             E::SafeIntOnOverflow();
998             return SafeIntArithmeticOverflow;
999         }
1000 
1001         return LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::RegMultiply(a, (unsigned __int64)b, ret);
1002     }
1003 };
1004 
1005 template< typename E > class LargeIntRegMultiply< signed __int32, unsigned __int64, E >
1006 {
1007 public:
RegMultiply(signed __int32 a,const unsigned __int64 & b,signed __int32 & ret)1008     static SafeIntError RegMultiply( signed __int32 a, const unsigned __int64& b, signed __int32& ret )
1009     {
1010         unsigned __int32 bHigh, bLow;
1011         bool fIsNegative = false;
1012 
1013         // Consider that a*b can be broken up into:
1014         // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow)
1015         // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)
1016 
1017         bHigh = (unsigned __int32)(b >> 32);
1018         bLow  = (unsigned __int32)b;
1019 
1020         ret = 0;
1021 
1022         if(bHigh != 0 && a != 0)
1023         {
1024             E::SafeIntOnOverflow();
1025             return SafeIntArithmeticOverflow;
1026         }
1027 
1028         if( a < 0 )
1029         {
1030             a = -a;
1031             fIsNegative = true;
1032         }
1033 
1034         unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow;
1035 
1036 
1037         if( !fIsNegative )
1038         {
1039             if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt )
1040             {
1041                 ret = (signed __int32)tmp;
1042                 return SafeIntNoError;
1043             }
1044         }
1045         else
1046         {
1047             if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 )
1048             {
1049                 ret = -( (signed __int32)tmp );
1050                 return SafeIntNoError;
1051             }
1052         }
1053 
1054         E::SafeIntOnOverflow();
1055         return SafeIntArithmeticOverflow;
1056     }
1057 };
1058 
1059 template < typename E > class LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >
1060 {
1061 public:
RegMultiply(unsigned __int32 a,const unsigned __int64 & b,unsigned __int32 & ret)1062     static SafeIntError RegMultiply( unsigned __int32 a, const unsigned __int64& b, unsigned __int32& ret )
1063     {
1064         // Consider that a*b can be broken up into:
1065         // (bHigh * 2^32 + bLow) * a
1066         // => (bHigh * a * 2^32) + (bLow * a)
1067         // In this case, the result must fit into 32-bits
1068         // If bHigh != 0 && a != 0, immediate error.
1069 
1070         if( (unsigned __int32)(b >> 32) != 0 && a != 0 )
1071         {
1072             E::SafeIntOnOverflow();
1073             return SafeIntArithmeticOverflow;
1074         }
1075 
1076         unsigned __int64 tmp = b * (unsigned __int64)a;
1077 
1078         if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow
1079         {
1080             E::SafeIntOnOverflow();
1081             return SafeIntArithmeticOverflow;
1082         }
1083 
1084         ret = (unsigned __int32)tmp;
1085         return SafeIntNoError;
1086     }
1087 };
1088 
1089 template < typename E > class LargeIntRegMultiply< unsigned __int32, signed __int64, E >
1090 {
1091 public:
RegMultiply(unsigned __int32 a,const signed __int64 & b,unsigned __int32 & ret)1092     static SafeIntError RegMultiply( unsigned __int32 a, const signed __int64& b, unsigned __int32& ret )
1093     {
1094         if( b < 0 && a != 0 )
1095         {
1096             E::SafeIntOnOverflow();
1097             return SafeIntArithmeticOverflow;
1098         }
1099 
1100         return LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >::RegMultiply( a, (unsigned __int64)b, ret );
1101     }
1102 };
1103 
1104 template < typename E > class LargeIntRegMultiply< signed __int64, signed __int64, E >
1105 {
1106 public:
RegMultiply(const signed __int64 & a,const signed __int64 & b,signed __int64 & ret)1107     static SafeIntError RegMultiply( const signed __int64& a, const signed __int64& b, signed __int64& ret )
1108     {
1109         bool aNegative = false;
1110         bool bNegative = false;
1111 
1112         unsigned __int64 tmp;
1113         __int64 a1 = a;
1114         __int64 b1 = b;
1115 
1116         if( a1 < 0 )
1117         {
1118             aNegative = true;
1119             a1 = -a1;
1120         }
1121 
1122         if( b1 < 0 )
1123         {
1124             bNegative = true;
1125             b1 = -b1;
1126         }
1127 
1128         if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::
1129             RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, tmp ) == SafeIntNoError )
1130         {
1131             // The unsigned multiplication didn't overflow
1132             if( aNegative ^ bNegative )
1133             {
1134                 // Result must be negative
1135                 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
1136                 {
1137                     ret = -(signed __int64)tmp;
1138                     return SafeIntNoError;
1139                 }
1140             }
1141             else
1142             {
1143                 // Result must be positive
1144                 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
1145                 {
1146                     ret = (signed __int64)tmp;
1147                     return SafeIntNoError;
1148                 }
1149             }
1150         }
1151 
1152         E::SafeIntOnOverflow();
1153         return SafeIntArithmeticOverflow;
1154     }
1155 };
1156 
1157 template < typename E > class LargeIntRegMultiply< signed __int64, unsigned __int32, E >
1158 {
1159 public:
RegMultiply(const signed __int64 & a,unsigned __int32 b,signed __int64 & ret)1160     static SafeIntError RegMultiply( const signed __int64& a, unsigned __int32 b, signed __int64& ret )
1161     {
1162         bool aNegative = false;
1163         unsigned __int64 tmp;
1164         __int64 a1 = a;
1165 
1166         if( a1 < 0 )
1167         {
1168             aNegative = true;
1169             a1 = -a1;
1170         }
1171 
1172         if( LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::RegMultiply( (unsigned __int64)a1, b, tmp ) == SafeIntNoError )
1173         {
1174             // The unsigned multiplication didn't overflow
1175             if( aNegative )
1176             {
1177                 // Result must be negative
1178                 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
1179                 {
1180                     ret = -(signed __int64)tmp;
1181                     return SafeIntNoError;
1182                 }
1183             }
1184             else
1185             {
1186                 // Result must be positive
1187                 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
1188                 {
1189                     ret = (signed __int64)tmp;
1190                     return SafeIntNoError;
1191                 }
1192             }
1193         }
1194 
1195         E::SafeIntOnOverflow();
1196         return SafeIntArithmeticOverflow;
1197     }
1198 };
1199 
1200 template < typename E > class LargeIntRegMultiply< signed __int64, signed __int32, E >
1201 {
1202 public:
RegMultiply(const signed __int64 & a,signed __int32 b,signed __int64 & ret)1203     static SafeIntError RegMultiply( const signed __int64& a, signed __int32 b, signed __int64& ret )
1204     {
1205         bool aNegative = false;
1206         bool bNegative = false;
1207 
1208         unsigned __int64 tmp;
1209         __int64 a1 = a;
1210         __int64 b1 = b;
1211 
1212         if( a1 < 0 )
1213         {
1214             aNegative = true;
1215             a1 = -a1;
1216         }
1217 
1218         if( b1 < 0 )
1219         {
1220             bNegative = true;
1221             b1 = -b1;
1222         }
1223 
1224         if( LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::
1225             RegMultiply( (unsigned __int64)a1, (unsigned __int32)b1, tmp ) == SafeIntNoError )
1226         {
1227             // The unsigned multiplication didn't overflow
1228             if( aNegative ^ bNegative )
1229             {
1230                 // Result must be negative
1231                 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
1232                 {
1233                     ret = -(signed __int64)tmp;
1234                     return SafeIntNoError;
1235                 }
1236             }
1237             else
1238             {
1239                 // Result must be positive
1240                 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
1241                 {
1242                     ret = (signed __int64)tmp;
1243                     return SafeIntNoError;
1244                 }
1245             }
1246         }
1247 
1248         E::SafeIntOnOverflow();
1249         return SafeIntArithmeticOverflow;
1250     }
1251 };
1252 
1253 template < typename E > class LargeIntRegMultiply< signed __int32, signed __int64, E >
1254 {
1255 public:
RegMultiply(signed __int32 a,const signed __int64 & b,signed __int32 & ret)1256     static SafeIntError RegMultiply( signed __int32 a, const signed __int64& b, signed __int32& ret )
1257     {
1258         bool aNegative = false;
1259         bool bNegative = false;
1260 
1261         unsigned __int32 tmp;
1262         __int64 b1 = b;
1263 
1264         if( a < 0 )
1265         {
1266             aNegative = true;
1267             a = -a;
1268         }
1269 
1270         if( b1 < 0 )
1271         {
1272             bNegative = true;
1273             b1 = -b1;
1274         }
1275 
1276         if( LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >::
1277             RegMultiply( (unsigned __int32)a, (unsigned __int64)b1, tmp )  == SafeIntNoError )
1278         {
1279             // The unsigned multiplication didn't overflow
1280             if( aNegative ^ bNegative )
1281             {
1282                 // Result must be negative
1283                 if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt )
1284                 {
1285 #pragma warning(suppress:4146)
1286                     ret = -tmp;
1287                     return SafeIntNoError;
1288                 }
1289             }
1290             else
1291             {
1292                 // Result must be positive
1293                 if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt )
1294                 {
1295                     ret = (signed __int32)tmp;
1296                     return SafeIntNoError;
1297                 }
1298             }
1299         }
1300 
1301         E::SafeIntOnOverflow();
1302         return SafeIntArithmeticOverflow;
1303     }
1304 };
1305 
1306 template < typename E > class LargeIntRegMultiply< signed __int64, unsigned __int64, E >
1307 {
1308 public:
RegMultiply(const signed __int64 & a,const unsigned __int64 & b,signed __int64 & ret)1309     static SafeIntError RegMultiply( const signed __int64& a, const unsigned __int64& b, signed __int64& ret )
1310     {
1311         bool aNegative = false;
1312 
1313         unsigned __int64 tmp;
1314         __int64 a1 = a;
1315 
1316         if( a1 < 0 )
1317         {
1318             aNegative = true;
1319             a1 = -a1;
1320         }
1321 
1322         if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::
1323             RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, tmp )  == SafeIntNoError )
1324         {
1325             // The unsigned multiplication didn't overflow
1326             if( aNegative )
1327             {
1328                 // Result must be negative
1329                 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
1330                 {
1331                     ret = -((signed __int64)tmp);
1332                     return SafeIntNoError;
1333                 }
1334             }
1335             else
1336             {
1337                 // Result must be positive
1338                 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
1339                 {
1340                     ret = (signed __int64)tmp;
1341                     return SafeIntNoError;
1342                 }
1343             }
1344         }
1345 
1346         E::SafeIntOnOverflow();
1347         return SafeIntArithmeticOverflow;
1348     }
1349 };
1350 
1351 template < typename E > class MultiplicationHelper< unsigned __int64, unsigned __int64, E, MultiplicationState_Uint64Uint64 >
1352 {
1353 public:
Multiply(const unsigned __int64 & t,const unsigned __int64 & u,unsigned __int64 & ret)1354     static SafeIntError Multiply( const unsigned __int64& t, const unsigned __int64& u, unsigned __int64& ret )
1355     {
1356         return LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::RegMultiply( t, u, ret );
1357     }
1358 };
1359 
1360 template < typename U, typename E > class MultiplicationHelper<unsigned __int64, U, E, MultiplicationState_Uint64Uint >
1361 {
1362 public:
1363     //U is any unsigned int 32-bit or less
Multiply(const unsigned __int64 & t,const U & u,unsigned __int64 & ret)1364     static SafeIntError Multiply( const unsigned __int64& t, const U& u, unsigned __int64& ret )
1365     {
1366         return LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::RegMultiply( t, (unsigned __int32)u, ret );
1367     }
1368 };
1369 
1370 // converse of the previous function
1371 template < typename T, typename E > class MultiplicationHelper< T, unsigned __int64, E, MultiplicationState_UintUint64 >
1372 {
1373 public:
1374     // T is any unsigned int up to 32-bit
Multiply(const T & t,const unsigned __int64 & u,T & ret)1375     static SafeIntError Multiply( const T& t, const unsigned __int64& u, T& ret )
1376     {
1377         unsigned __int32 tmp;
1378 
1379         if( LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >::RegMultiply( t, u, tmp ) == SafeIntNoError &&
1380             SafeCastHelper< T, unsigned __int32, E >::Cast(tmp, ret) == SafeIntNoError )
1381         {
1382             return SafeIntNoError;
1383         }
1384 
1385         E::SafeIntOnOverflow();
1386         return SafeIntArithmeticOverflow;
1387     }
1388 };
1389 
1390 template < typename U, typename E > class MultiplicationHelper< unsigned __int64, U, E, MultiplicationState_Uint64Int >
1391 {
1392 public:
1393     //U is any signed int, up to 64-bit
Multiply(const unsigned __int64 & t,const U & u,unsigned __int64 & ret)1394     static SafeIntError Multiply(const unsigned __int64& t, const U& u, unsigned __int64& ret)
1395     {
1396         return LargeIntRegMultiply< unsigned __int64, signed __int32, E >::RegMultiply(t, (signed __int32)u, ret);
1397     }
1398 };
1399 
1400 template < typename E > class MultiplicationHelper<unsigned __int64, __int64, E, MultiplicationState_Uint64Int64 >
1401 {
1402 public:
Multiply(const unsigned __int64 & t,const __int64 & u,unsigned __int64 & ret)1403     static SafeIntError Multiply(const unsigned __int64& t, const __int64& u, unsigned __int64& ret)
1404     {
1405         return LargeIntRegMultiply< unsigned __int64, __int64, E >::RegMultiply(t, u, ret);
1406     }
1407 };
1408 
1409 template < typename T, typename E > class MultiplicationHelper< T, __int64, E, MultiplicationState_UintInt64 >
1410 {
1411 public:
1412     //T is unsigned up to 32-bit
Multiply(const T & t,const __int64 & u,T & ret)1413     static SafeIntError Multiply( const T& t, const __int64& u, T& ret )
1414     {
1415         unsigned __int32 tmp;
1416 
1417         if( LargeIntRegMultiply< unsigned __int32, __int64, E >::RegMultiply( (unsigned __int32)t, u, tmp ) == SafeIntNoError &&
1418             SafeCastHelper< T, unsigned __int32, E >::Cast( tmp, ret ) == SafeIntNoError )
1419         {
1420             return SafeIntNoError;
1421         }
1422 
1423         E::SafeIntOnOverflow();
1424         return SafeIntArithmeticOverflow;
1425     }
1426 };
1427 
1428 template < typename U, typename E > class MultiplicationHelper<__int64, U, E, MultiplicationState_Int64Uint >
1429 {
1430 public:
1431     //U is unsigned up to 32-bit
Multiply(const __int64 & t,const U & u,__int64 & ret)1432     static SafeIntError Multiply( const __int64& t, const U& u, __int64& ret )
1433     {
1434         return LargeIntRegMultiply< __int64, unsigned __int32, E >::RegMultiply( t, (unsigned __int32)u, ret );
1435     }
1436 };
1437 
1438 template < typename E > class MultiplicationHelper<__int64, __int64, E, MultiplicationState_Int64Int64 >
1439 {
1440 public:
Multiply(const __int64 & t,const __int64 & u,__int64 & ret)1441     static SafeIntError Multiply( const __int64& t, const __int64& u, __int64& ret )
1442     {
1443         return LargeIntRegMultiply< __int64, __int64, E >::RegMultiply( t, u, ret );
1444     }
1445 };
1446 
1447 template < typename U, typename E > class MultiplicationHelper<__int64, U, E, MultiplicationState_Int64Int>
1448 {
1449 public:
1450     //U is signed up to 32-bit
Multiply(const __int64 & t,U u,__int64 & ret)1451     static SafeIntError Multiply( const __int64& t, U u, __int64& ret )
1452     {
1453         return LargeIntRegMultiply< __int64, __int32, E >::RegMultiply( t, (__int32)u, ret );
1454     }
1455 };
1456 
1457 template < typename T, typename E > class MultiplicationHelper< T, unsigned __int64, E, MultiplicationState_IntUint64 >
1458 {
1459 public:
1460     //T is signed up to 32-bit
Multiply(T t,const unsigned __int64 & u,T & ret)1461     static SafeIntError Multiply(T t, const unsigned __int64& u, T& ret)
1462     {
1463         __int32 tmp;
1464 
1465         if( LargeIntRegMultiply< __int32, unsigned __int64, E >::RegMultiply( (__int32)t, u, tmp ) == SafeIntNoError &&
1466             SafeCastHelper< T, __int32, E >::Cast( tmp, ret ) == SafeIntNoError )
1467         {
1468             return SafeIntNoError;
1469         }
1470 
1471         E::SafeIntOnOverflow();
1472         return SafeIntArithmeticOverflow;
1473     }
1474 };
1475 
1476 template < typename E > class MultiplicationHelper<__int64, unsigned __int64, E, MultiplicationState_Int64Uint64>
1477 {
1478 public:
1479     //U is signed up to 32-bit
Multiply(const __int64 & t,const unsigned __int64 & u,__int64 & ret)1480     static SafeIntError Multiply( const __int64& t, const unsigned __int64& u, __int64& ret )
1481     {
1482         return LargeIntRegMultiply< __int64, unsigned __int64, E >::RegMultiply( t, u, ret );
1483     }
1484 };
1485 
1486 template < typename T, typename E > class MultiplicationHelper< T, __int64, E, MultiplicationState_IntInt64>
1487 {
1488 public:
1489     //T is signed, up to 32-bit
Multiply(T t,const __int64 & u,T & ret)1490     static SafeIntError Multiply( T t, const __int64& u, T& ret )
1491     {
1492         __int32 tmp;
1493 
1494         if( LargeIntRegMultiply< __int32, __int64, E >::RegMultiply( (__int32)t, u, tmp ) == SafeIntNoError &&
1495             SafeCastHelper< T, __int32, E >::Cast( tmp, ret ) == SafeIntNoError )
1496         {
1497             return SafeIntNoError;
1498         }
1499 
1500         E::SafeIntOnOverflow();
1501         return SafeIntArithmeticOverflow;
1502     }
1503 };
1504 
1505 enum DivisionState
1506 {
1507     DivisionState_OK,
1508     DivisionState_UnsignedSigned,
1509     DivisionState_SignedUnsigned32,
1510     DivisionState_SignedUnsigned64,
1511     DivisionState_SignedUnsigned,
1512     DivisionState_SignedSigned
1513 };
1514 
1515 template < typename T, typename U > class DivisionMethod
1516 {
1517 public:
1518     enum
1519     {
1520         method = (SafeIntCompare< T, U >::isBothUnsigned        ? DivisionState_OK :
1521         (!IntTraits< T >::isSigned && IntTraits< U >::isSigned) ? DivisionState_UnsignedSigned :
1522         (IntTraits< T >::isSigned &&
1523         IntTraits< U >::isUint32 &&
1524         IntTraits< T >::isLT64Bit)                           ? DivisionState_SignedUnsigned32 :
1525         (IntTraits< T >::isSigned && IntTraits< U >::isUint64)  ? DivisionState_SignedUnsigned64 :
1526         (IntTraits< T >::isSigned && !IntTraits< U >::isSigned) ? DivisionState_SignedUnsigned :
1527         DivisionState_SignedSigned)
1528     };
1529 };
1530 
1531 template < typename T, typename U, typename E, int Method = DivisionMethod< T, U >::method > class DivisionHelper;
1532 
1533 template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_OK >
1534 {
1535 public:
Divide(const T & t,const U & u,T & result)1536     static SafeIntError Divide( const T& t, const U& u, T& result )
1537     {
1538         if( u == 0 )
1539         {
1540             E::SafeIntOnDivZero();
1541             return SafeIntDivideByZero;
1542         }
1543 
1544         result = (T)( t/u );
1545         return SafeIntNoError;
1546     }
1547 };
1548 
1549 template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_UnsignedSigned>
1550 {
1551 public:
Divide(const T & t,const U & u,T & result)1552     static SafeIntError Divide( const T& t, const U& u, T& result )
1553     {
1554         if( u > 0 )
1555         {
1556             result = (T)( t/u );
1557             return SafeIntNoError;
1558         }
1559 
1560         if( u == 0 )
1561         {
1562             E::SafeIntOnDivZero();
1563             return SafeIntDivideByZero;
1564         }
1565 
1566         // it is always an error to try and divide an unsigned number by a negative signed number
1567         // unless u is bigger than t
1568         if( AbsValueHelper< U >::Abs( u ) > t )
1569         {
1570             result = 0;
1571             return SafeIntNoError;
1572         }
1573 
1574         E::SafeIntOnOverflow();
1575         return SafeIntArithmeticOverflow;
1576     }
1577 };
1578 
1579 template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedUnsigned32 >
1580 {
1581 public:
Divide(const T & t,const U & u,T & result)1582     static SafeIntError Divide( const T& t, const U& u, T& result )
1583     {
1584         if( u == 0 )
1585         {
1586             E::SafeIntOnDivZero();
1587             return SafeIntDivideByZero;
1588         }
1589 
1590         // Test for t > 0
1591         // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors
1592         // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional
1593         if( t > 0 )
1594             result = (T)( t/u );
1595         else
1596             result = (T)( (__int64)t/(__int64)u );
1597 
1598         return SafeIntNoError;
1599     }
1600 };
1601 
1602 template < typename T, typename E > class DivisionHelper< T, unsigned __int64, E, DivisionState_SignedUnsigned64 >
1603 {
1604 public:
Divide(const T & t,const unsigned __int64 & u,T & result)1605     static SafeIntError Divide( const T& t, const unsigned __int64& u, T& result )
1606     {
1607         if( u == 0 )
1608         {
1609             E::SafeIntOnDivZero();
1610             return SafeIntDivideByZero;
1611         }
1612 
1613         if( u <= (unsigned __int64)IntTraits< T >::maxInt )
1614         {
1615             // Else u can safely be cast to T
1616 #pragma warning(suppress:4127)
1617             if( sizeof( T ) < sizeof( __int64 ) )
1618                 result = (T)( (int)t/(int)u );
1619             else
1620                 result = (T)((__int64)t/(__int64)u);
1621         }
1622         else // Corner case
1623             if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt )
1624             {
1625                 // Min int divided by its own magnitude is -1
1626                 result = -1;
1627             }
1628             else
1629             {
1630                 result = 0;
1631             }
1632             return SafeIntNoError;
1633     }
1634 };
1635 
1636 template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedUnsigned>
1637 {
1638 public:
1639     // T is any signed, U is unsigned and smaller than 32-bit
1640     // In this case, standard operator casting is correct
Divide(const T & t,const U & u,T & result)1641     static SafeIntError Divide( const T& t, const U& u, T& result )
1642     {
1643         if( u == 0 )
1644         {
1645             E::SafeIntOnDivZero();
1646             return SafeIntDivideByZero;
1647         }
1648 
1649         result = (T)( t/u );
1650         return SafeIntNoError;
1651     }
1652 };
1653 
1654 template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedSigned>
1655 {
1656 public:
Divide(const T & t,const U & u,T & result)1657     static SafeIntError Divide( const T& t, const U& u, T& result )
1658     {
1659         if( u == 0 )
1660         {
1661             E::SafeIntOnDivZero();
1662             return SafeIntDivideByZero;
1663         }
1664 
1665         // Must test for corner case
1666         if( t == IntTraits< T >::minInt && u == -1 )
1667         {
1668             E::SafeIntOnOverflow();
1669             return SafeIntArithmeticOverflow;
1670         }
1671 
1672         result = (T)( t/u );
1673         return SafeIntNoError;
1674     }
1675 };
1676 
1677 enum AdditionState
1678 {
1679     AdditionState_CastIntCheckMax,
1680     AdditionState_CastUintCheckOverflow,
1681     AdditionState_CastUintCheckOverflowMax,
1682     AdditionState_CastUint64CheckOverflow,
1683     AdditionState_CastUint64CheckOverflowMax,
1684     AdditionState_CastIntCheckMinMax,
1685     AdditionState_CastInt64CheckMinMax,
1686     AdditionState_CastInt64CheckMax,
1687     AdditionState_CastUint64CheckMinMax,
1688     AdditionState_CastUint64CheckMinMax2,
1689     AdditionState_CastInt64CheckOverflow,
1690     AdditionState_CastInt64CheckOverflowMinMax,
1691     AdditionState_CastInt64CheckOverflowMax,
1692     AdditionState_ManualCheckInt64Uint64,
1693     AdditionState_ManualCheck,
1694     AdditionState_Error
1695 };
1696 
1697 template< typename T, typename U >
1698 class AdditionMethod
1699 {
1700 public:
1701     enum
1702     {
1703         //unsigned-unsigned
1704         method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32  ? AdditionState_CastIntCheckMax :
1705         (IntRegion< T,U >::IntZone_Uint32_UintLT64)   ? AdditionState_CastUintCheckOverflow :
1706         (IntRegion< T,U >::IntZone_UintLT32_Uint32)   ? AdditionState_CastUintCheckOverflowMax :
1707         (IntRegion< T,U >::IntZone_Uint64_Uint)       ? AdditionState_CastUint64CheckOverflow :
1708         (IntRegion< T,U >::IntZone_UintLT64_Uint64)   ? AdditionState_CastUint64CheckOverflowMax :
1709         //unsigned-signed
1710         (IntRegion< T,U >::IntZone_UintLT32_IntLT32)  ? AdditionState_CastIntCheckMinMax :
1711         (IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
1712         IntRegion< T,U >::IntZone_UintLT32_Int32)    ? AdditionState_CastInt64CheckMinMax :
1713         (IntRegion< T,U >::IntZone_Uint64_Int ||
1714         IntRegion< T,U >::IntZone_Uint64_Int64)      ? AdditionState_CastUint64CheckMinMax :
1715         (IntRegion< T,U >::IntZone_UintLT64_Int64)    ? AdditionState_CastUint64CheckMinMax2 :
1716         //signed-signed
1717         (IntRegion< T,U >::IntZone_IntLT32_IntLT32)   ? AdditionState_CastIntCheckMinMax :
1718         (IntRegion< T,U >::IntZone_Int32_IntLT64 ||
1719         IntRegion< T,U >::IntZone_IntLT32_Int32)     ? AdditionState_CastInt64CheckMinMax :
1720         (IntRegion< T,U >::IntZone_Int64_Int ||
1721         IntRegion< T,U >::IntZone_Int64_Int64)       ? AdditionState_CastInt64CheckOverflow :
1722         (IntRegion< T,U >::IntZone_IntLT64_Int64)     ? AdditionState_CastInt64CheckOverflowMinMax :
1723         //signed-unsigned
1724         (IntRegion< T,U >::IntZone_IntLT32_UintLT32)  ? AdditionState_CastIntCheckMax :
1725         (IntRegion< T,U >::IntZone_Int32_UintLT32 ||
1726         IntRegion< T,U >::IntZone_IntLT64_Uint32)    ? AdditionState_CastInt64CheckMax :
1727         (IntRegion< T,U >::IntZone_Int64_UintLT64)    ? AdditionState_CastInt64CheckOverflowMax :
1728         (IntRegion< T,U >::IntZone_Int64_Uint64)      ? AdditionState_ManualCheckInt64Uint64 :
1729         (IntRegion< T,U >::IntZone_Int_Uint64)        ? AdditionState_ManualCheck :
1730         AdditionState_Error)
1731     };
1732 };
1733 
1734 template < typename T, typename U, typename E, int Method = AdditionMethod< T, U >::method > class AdditionHelper;
1735 
1736 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastIntCheckMax >
1737 {
1738 public:
Addition(const T & lhs,const U & rhs,T & result)1739     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
1740     {
1741         //16-bit or less unsigned addition
1742         __int32 tmp = lhs + rhs;
1743 
1744         if( tmp <= (__int32)IntTraits< T >::maxInt )
1745         {
1746             result = (T)tmp;
1747             return SafeIntNoError;
1748         }
1749 
1750         E::SafeIntOnOverflow();
1751         return SafeIntArithmeticOverflow;
1752     }
1753 };
1754 
1755 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUintCheckOverflow >
1756 {
1757 public:
Addition(const T & lhs,const U & rhs,T & result)1758     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
1759     {
1760         // 32-bit or less - both are unsigned
1761         unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;
1762 
1763         //we added didn't get smaller
1764         if( tmp >= lhs )
1765         {
1766             result = (T)tmp;
1767             return SafeIntNoError;
1768         }
1769         E::SafeIntOnOverflow();
1770         return SafeIntArithmeticOverflow;
1771     }
1772 };
1773 
1774 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUintCheckOverflowMax>
1775 {
1776 public:
Addition(const T & lhs,const U & rhs,T & result)1777     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
1778     {
1779         // 32-bit or less - both are unsigned
1780         unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;
1781 
1782         // We added and it didn't get smaller or exceed maxInt
1783         if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
1784         {
1785             result = (T)tmp;
1786             return SafeIntNoError;
1787         }
1788         E::SafeIntOnOverflow();
1789         return SafeIntArithmeticOverflow;
1790     }
1791 };
1792 
1793 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckOverflow>
1794 {
1795 public:
Addition(const T & lhs,const U & rhs,T & result)1796     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
1797     {
1798         // lhs unsigned __int64, rhs unsigned
1799         unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
1800 
1801         // We added and it didn't get smaller
1802         if(tmp >= lhs)
1803         {
1804             result = (T)tmp;
1805             return SafeIntNoError;
1806         }
1807 
1808         E::SafeIntOnOverflow();
1809         return SafeIntArithmeticOverflow;
1810     }
1811 };
1812 
1813 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckOverflowMax >
1814 {
1815 public:
Addition(const T & lhs,const U & rhs,T & result)1816     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
1817     {
1818         //lhs unsigned __int64, rhs unsigned
1819         unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
1820 
1821         // We added and it didn't get smaller
1822         if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
1823         {
1824             result = (T)tmp;
1825             return SafeIntNoError;
1826         }
1827 
1828         E::SafeIntOnOverflow();
1829         return SafeIntArithmeticOverflow;
1830     }
1831 };
1832 
1833 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastIntCheckMinMax >
1834 {
1835 public:
Addition(const T & lhs,const U & rhs,T & result)1836     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
1837     {
1838         // 16-bit or less - one or both are signed
1839         __int32 tmp = lhs + rhs;
1840 
1841         if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt )
1842         {
1843             result = (T)tmp;
1844             return SafeIntNoError;
1845         }
1846 
1847         E::SafeIntOnOverflow();
1848         return SafeIntArithmeticOverflow;
1849     }
1850 };
1851 
1852 #pragma warning(push)
1853 #pragma warning(disable:4702)
1854 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckMinMax >
1855 {
1856 public:
Addition(const T & lhs,const U & rhs,T & result)1857     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
1858     {
1859         // 32-bit or less - one or both are signed
1860         __int64 tmp = (__int64)lhs + (__int64)rhs;
1861 
1862         if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt )
1863         {
1864             result = (T)tmp;
1865             return SafeIntNoError;
1866         }
1867 
1868         E::SafeIntOnOverflow();
1869         return SafeIntArithmeticOverflow;
1870         // return E::SafeIntOnOverflow2();
1871     }
1872 };
1873 #pragma warning(pop)
1874 
1875 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckMax >
1876 {
1877 public:
Addition(const T & lhs,const U & rhs,T & result)1878     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
1879     {
1880         // 32-bit or less - lhs signed, rhs unsigned
1881         __int64 tmp = (__int64)lhs + (__int64)rhs;
1882 
1883         if( tmp <= IntTraits< T >::maxInt )
1884         {
1885             result = (T)tmp;
1886             return SafeIntNoError;
1887         }
1888 
1889         E::SafeIntOnOverflow();
1890         return SafeIntArithmeticOverflow;
1891     }
1892 };
1893 
1894 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckMinMax >
1895 {
1896 public:
Addition(const T & lhs,const U & rhs,T & result)1897     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
1898     {
1899         // lhs is unsigned __int64, rhs signed
1900         unsigned __int64 tmp;
1901 
1902         if( rhs < 0 )
1903         {
1904             // So we're effectively subtracting
1905             tmp = AbsValueHelper< U >::Abs( rhs );
1906 
1907             if( tmp <= lhs )
1908             {
1909                 result = lhs - tmp;
1910                 return SafeIntNoError;
1911             }
1912         }
1913         else
1914         {
1915             // now we know that rhs can be safely cast into an unsigned __int64
1916             tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
1917 
1918             // We added and it did not become smaller
1919             if( tmp >= lhs )
1920             {
1921                 result = (T)tmp;
1922                 return SafeIntNoError;
1923             }
1924         }
1925 
1926         E::SafeIntOnOverflow();
1927         return SafeIntArithmeticOverflow;
1928     }
1929 };
1930 
1931 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckMinMax2>
1932 {
1933 public:
Addition(const T & lhs,const U & rhs,T & result)1934     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
1935     {
1936         // lhs is unsigned and < 64-bit, rhs signed __int64
1937         if( rhs < 0 )
1938         {
1939             if( lhs >= (unsigned __int64)( -rhs ) )//negation is safe, since rhs is 64-bit
1940             {
1941                 result = (T)( lhs + rhs );
1942                 return SafeIntNoError;
1943             }
1944         }
1945         else
1946         {
1947             // now we know that rhs can be safely cast into an unsigned __int64
1948             unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
1949 
1950             // special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff
1951             // it is not possible for the operation above to overflow, so just check max
1952             if( tmp <= IntTraits< T >::maxInt )
1953             {
1954                 result = (T)tmp;
1955                 return SafeIntNoError;
1956             }
1957         }
1958         E::SafeIntOnOverflow();
1959         return SafeIntArithmeticOverflow;
1960     }
1961 };
1962 
1963 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflow>
1964 {
1965 public:
Addition(const T & lhs,const U & rhs,T & result)1966     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
1967     {
1968         // lhs is signed __int64, rhs signed
1969         __int64 tmp = (__int64)lhs + (__int64)rhs;
1970 
1971         if( lhs >= 0 )
1972         {
1973             // mixed sign cannot overflow
1974             if( rhs >= 0 && tmp < lhs )
1975             {
1976                 E::SafeIntOnOverflow();
1977                 return SafeIntArithmeticOverflow;
1978             }
1979         }
1980         else
1981         {
1982             // lhs negative
1983             if( rhs < 0 && tmp > lhs )
1984             {
1985                 E::SafeIntOnOverflow();
1986                 return SafeIntArithmeticOverflow;
1987             }
1988         }
1989 
1990         result = (T)tmp;
1991         return SafeIntNoError;
1992     }
1993 };
1994 
1995 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflowMinMax>
1996 {
1997 public:
Addition(const T & lhs,const U & rhs,T & result)1998     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
1999     {
2000         //rhs is signed __int64, lhs signed
2001         __int64 tmp;
2002 
2003         if( AdditionHelper< __int64, __int64, E, AdditionState_CastInt64CheckOverflow >::
2004             Addition( (__int64)lhs, (__int64)rhs, tmp ) == SafeIntNoError &&
2005             tmp <= IntTraits< T >::maxInt &&
2006             tmp >= IntTraits< T >::minInt )
2007         {
2008             result = (T)tmp;
2009             return SafeIntNoError;
2010         }
2011 
2012         E::SafeIntOnOverflow();
2013         return SafeIntArithmeticOverflow;
2014     }
2015 };
2016 
2017 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflowMax >
2018 {
2019 public:
Addition(const T & lhs,const U & rhs,T & result)2020     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
2021     {
2022         //lhs is signed __int64, rhs unsigned < 64-bit
2023         __int64 tmp = lhs + (__int64)rhs;
2024 
2025         if( tmp >= lhs )
2026         {
2027             result = (T)tmp;
2028             return SafeIntNoError;
2029         }
2030 
2031         E::SafeIntOnOverflow();
2032         return SafeIntArithmeticOverflow;
2033     }
2034 };
2035 
2036 template < typename E > class AdditionHelper < __int64, unsigned __int64, E, AdditionState_ManualCheckInt64Uint64 >
2037 {
2038 public:
Addition(const __int64 & lhs,const unsigned __int64 & rhs,__int64 & result)2039     static SafeIntError Addition( const __int64& lhs, const unsigned __int64& rhs, __int64& result )
2040     {
2041         // rhs is unsigned __int64, lhs __int64
2042         __int64 tmp = lhs + (__int64)rhs;
2043 
2044         if( tmp >= lhs )
2045         {
2046             result = tmp;
2047             return SafeIntNoError;
2048         }
2049 
2050         E::SafeIntOnOverflow();
2051         return SafeIntArithmeticOverflow;
2052     }
2053 };
2054 
2055 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_ManualCheck >
2056 {
2057 public:
Addition(const T & lhs,const U & rhs,T & result)2058     static SafeIntError Addition( const T& lhs, const U& rhs, T& result )
2059     {
2060         // rhs is unsigned __int64, lhs signed, 32-bit or less
2061 
2062         if( (unsigned __int32)( rhs >> 32 ) == 0 )
2063         {
2064             // Now it just happens to work out that the standard behavior does what we want
2065             // Adding explicit casts to show exactly what's happening here
2066             __int32 tmp = (__int32)( (unsigned __int32)rhs + (unsigned __int32)lhs );
2067 
2068             if( tmp >= lhs &&
2069                 SafeCastHelper< T, __int32, E >::Cast( tmp, result ) == SafeIntNoError )
2070                 return SafeIntNoError;
2071         }
2072 
2073         E::SafeIntOnOverflow();
2074         return SafeIntArithmeticOverflow;
2075     }
2076 };
2077 
2078 enum SubtractionState
2079 {
2080     SubtractionState_BothUnsigned,
2081     SubtractionState_CastIntCheckMinMax,
2082     SubtractionState_CastIntCheckMin,
2083     SubtractionState_CastInt64CheckMinMax,
2084     SubtractionState_CastInt64CheckMin,
2085     SubtractionState_Uint64Int,
2086     SubtractionState_UintInt64,
2087     SubtractionState_Int64Int,
2088     SubtractionState_IntInt64,
2089     SubtractionState_Int64Uint,
2090     SubtractionState_IntUint64,
2091     SubtractionState_Int64Uint64,
2092     // states for SubtractionMethod2
2093     SubtractionState_BothUnsigned2,
2094     SubtractionState_CastIntCheckMinMax2,
2095     SubtractionState_CastInt64CheckMinMax2,
2096     SubtractionState_Uint64Int2,
2097     SubtractionState_UintInt642,
2098     SubtractionState_Int64Int2,
2099     SubtractionState_IntInt642,
2100     SubtractionState_Int64Uint2,
2101     SubtractionState_IntUint642,
2102     SubtractionState_Int64Uint642,
2103     SubtractionState_Error
2104 };
2105 
2106 template < typename T, typename U > class SubtractionMethod
2107 {
2108 public:
2109     enum
2110     {
2111         // unsigned-unsigned
2112         method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 ||
2113         (IntRegion< T,U >::IntZone_Uint32_UintLT64)   ||
2114         (IntRegion< T,U >::IntZone_UintLT32_Uint32)   ||
2115         (IntRegion< T,U >::IntZone_Uint64_Uint)       ||
2116         (IntRegion< T,U >::IntZone_UintLT64_Uint64))      ? SubtractionState_BothUnsigned :
2117         // unsigned-signed
2118         (IntRegion< T,U >::IntZone_UintLT32_IntLT32)      ? SubtractionState_CastIntCheckMinMax :
2119         (IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
2120         IntRegion< T,U >::IntZone_UintLT32_Int32)        ? SubtractionState_CastInt64CheckMinMax :
2121         (IntRegion< T,U >::IntZone_Uint64_Int ||
2122         IntRegion< T,U >::IntZone_Uint64_Int64)          ? SubtractionState_Uint64Int :
2123         (IntRegion< T,U >::IntZone_UintLT64_Int64)        ? SubtractionState_UintInt64 :
2124         // signed-signed
2125         (IntRegion< T,U >::IntZone_IntLT32_IntLT32)       ? SubtractionState_CastIntCheckMinMax :
2126         (IntRegion< T,U >::IntZone_Int32_IntLT64 ||
2127         IntRegion< T,U >::IntZone_IntLT32_Int32)         ? SubtractionState_CastInt64CheckMinMax :
2128         (IntRegion< T,U >::IntZone_Int64_Int ||
2129         IntRegion< T,U >::IntZone_Int64_Int64)           ? SubtractionState_Int64Int :
2130         (IntRegion< T,U >::IntZone_IntLT64_Int64)         ? SubtractionState_IntInt64 :
2131         // signed-unsigned
2132         (IntRegion< T,U >::IntZone_IntLT32_UintLT32)      ? SubtractionState_CastIntCheckMin :
2133         (IntRegion< T,U >::IntZone_Int32_UintLT32 ||
2134         IntRegion< T,U >::IntZone_IntLT64_Uint32)        ? SubtractionState_CastInt64CheckMin :
2135         (IntRegion< T,U >::IntZone_Int64_UintLT64)        ? SubtractionState_Int64Uint :
2136         (IntRegion< T,U >::IntZone_Int_Uint64)            ? SubtractionState_IntUint64 :
2137         (IntRegion< T,U >::IntZone_Int64_Uint64)          ? SubtractionState_Int64Uint64 :
2138         SubtractionState_Error)
2139     };
2140 };
2141 
2142 // this is for the case of U - SafeInt< T, E >
2143 template < typename T, typename U > class SubtractionMethod2
2144 {
2145 public:
2146     enum
2147     {
2148         // unsigned-unsigned
2149         method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 ||
2150         (IntRegion< T,U >::IntZone_Uint32_UintLT64)   ||
2151         (IntRegion< T,U >::IntZone_UintLT32_Uint32)   ||
2152         (IntRegion< T,U >::IntZone_Uint64_Uint)       ||
2153         (IntRegion< T,U >::IntZone_UintLT64_Uint64))     ? SubtractionState_BothUnsigned2 :
2154         // unsigned-signed
2155         (IntRegion< T,U >::IntZone_UintLT32_IntLT32)     ? SubtractionState_CastIntCheckMinMax2 :
2156         (IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
2157         IntRegion< T,U >::IntZone_UintLT32_Int32)       ? SubtractionState_CastInt64CheckMinMax2 :
2158         (IntRegion< T,U >::IntZone_Uint64_Int ||
2159         IntRegion< T,U >::IntZone_Uint64_Int64)         ? SubtractionState_Uint64Int2 :
2160         (IntRegion< T,U >::IntZone_UintLT64_Int64)       ? SubtractionState_UintInt642 :
2161         // signed-signed
2162         (IntRegion< T,U >::IntZone_IntLT32_IntLT32)      ? SubtractionState_CastIntCheckMinMax2 :
2163         (IntRegion< T,U >::IntZone_Int32_IntLT64 ||
2164         IntRegion< T,U >::IntZone_IntLT32_Int32)        ? SubtractionState_CastInt64CheckMinMax2 :
2165         (IntRegion< T,U >::IntZone_Int64_Int ||
2166         IntRegion< T,U >::IntZone_Int64_Int64)          ? SubtractionState_Int64Int2 :
2167         (IntRegion< T,U >::IntZone_IntLT64_Int64)        ? SubtractionState_IntInt642 :
2168         // signed-unsigned
2169         (IntRegion< T,U >::IntZone_IntLT32_UintLT32)     ? SubtractionState_CastIntCheckMinMax2 :
2170         (IntRegion< T,U >::IntZone_Int32_UintLT32 ||
2171         IntRegion< T,U >::IntZone_IntLT64_Uint32)       ? SubtractionState_CastInt64CheckMinMax2 :
2172         (IntRegion< T,U >::IntZone_Int64_UintLT64)       ? SubtractionState_Int64Uint2 :
2173         (IntRegion< T,U >::IntZone_Int_Uint64)           ? SubtractionState_IntUint642 :
2174         (IntRegion< T,U >::IntZone_Int64_Uint64)         ? SubtractionState_Int64Uint642 :
2175         SubtractionState_Error)
2176     };
2177 };
2178 
2179 template < typename T, typename U, typename E, int Method = SubtractionMethod< T, U >::method > class SubtractionHelper;
2180 
2181 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_BothUnsigned >
2182 {
2183 public:
Subtract(const T & lhs,const U & rhs,T & result)2184     static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
2185     {
2186         // both are unsigned - easy case
2187         if( rhs <= lhs )
2188         {
2189             result = (T)( lhs - rhs );
2190             return SafeIntNoError;
2191         }
2192 
2193         E::SafeIntOnOverflow();
2194         return SafeIntArithmeticOverflow;
2195     }
2196 };
2197 
2198 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_BothUnsigned2 >
2199 {
2200 public:
Subtract(const T & lhs,const U & rhs,U & result)2201     static SafeIntError Subtract( const T& lhs, const U& rhs, U& result )
2202     {
2203         // both are unsigned - easy case
2204         // Except we do have to check for overflow - lhs could be larger than result can hold
2205         if( rhs <= lhs )
2206         {
2207             T tmp = (T)(lhs - rhs);
2208             return SafeCastHelper< U, T, E>::Cast( tmp, result);
2209         }
2210 
2211         E::SafeIntOnOverflow();
2212         return SafeIntArithmeticOverflow;
2213     }
2214 };
2215 
2216 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastIntCheckMinMax >
2217 {
2218 public:
Subtract(const T & lhs,const U & rhs,T & result)2219     static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
2220     {
2221         // both values are 16-bit or less
2222         // rhs is signed, so could end up increasing or decreasing
2223         __int32 tmp = lhs - rhs;
2224 
2225         if( SafeCastHelper< T, __int32, E >::Cast( tmp, result ) == SafeIntNoError )
2226         {
2227             result = (T)tmp;
2228             return SafeIntNoError;
2229         }
2230 
2231         E::SafeIntOnOverflow();
2232         return SafeIntArithmeticOverflow;
2233     }
2234 };
2235 
2236 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_CastIntCheckMinMax2 >
2237 {
2238 public:
Subtract(const U & lhs,const T & rhs,T & result)2239     static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
2240     {
2241         // both values are 16-bit or less
2242         // rhs is signed, so could end up increasing or decreasing
2243         __int32 tmp = lhs - rhs;
2244 
2245         return SafeCastHelper< T, __int32, E >::Cast( tmp, result );
2246     }
2247 };
2248 
2249 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastIntCheckMin >
2250 {
2251 public:
Subtract(const T & lhs,const U & rhs,T & result)2252     static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
2253     {
2254         // both values are 16-bit or less
2255         // rhs is unsigned - check only minimum
2256         __int32 tmp = lhs - rhs;
2257 
2258         if( tmp >= (__int32)IntTraits< T >::minInt )
2259         {
2260             result = (T)tmp;
2261             return SafeIntNoError;
2262         }
2263 
2264         E::SafeIntOnOverflow();
2265         return SafeIntArithmeticOverflow;
2266     }
2267 };
2268 
2269 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastInt64CheckMinMax >
2270 {
2271 public:
Subtract(const T & lhs,const U & rhs,T & result)2272     static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
2273     {
2274         // both values are 32-bit or less
2275         // rhs is signed, so could end up increasing or decreasing
2276         __int64 tmp = (__int64)lhs - (__int64)rhs;
2277 
2278         return SafeCastHelper< T, __int64, E >::Cast( tmp, result );
2279     }
2280 };
2281 
2282 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_CastInt64CheckMinMax2 >
2283 {
2284 public:
Subtract(const U & lhs,const T & rhs,T & result)2285     static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
2286     {
2287         // both values are 32-bit or less
2288         // rhs is signed, so could end up increasing or decreasing
2289         __int64 tmp = (__int64)lhs - (__int64)rhs;
2290 
2291         return SafeCastHelper< T, __int64, E >::Cast( tmp, result );
2292     }
2293 };
2294 
2295 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastInt64CheckMin >
2296 {
2297 public:
Subtract(const T & lhs,const U & rhs,T & result)2298     static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
2299     {
2300         // both values are 32-bit or less
2301         // rhs is unsigned - check only minimum
2302         __int64 tmp = (__int64)lhs - (__int64)rhs;
2303 
2304         if( tmp >= (__int64)IntTraits< T >::minInt )
2305         {
2306             result = (T)tmp;
2307             return SafeIntNoError;
2308         }
2309 
2310         E::SafeIntOnOverflow();
2311         return SafeIntArithmeticOverflow;
2312     }
2313 };
2314 
2315 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Uint64Int >
2316 {
2317 public:
Subtract(const T & lhs,const U & rhs,T & result)2318     static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
2319     {
2320         // lhs is an unsigned __int64, rhs signed
2321         // must first see if rhs is positive or negative
2322         if( rhs >= 0 )
2323         {
2324             if( (unsigned __int64)rhs <= lhs )
2325             {
2326                 result = (T)( lhs - (unsigned __int64)rhs );
2327                 return SafeIntNoError;
2328             }
2329         }
2330         else
2331         {
2332             // we're now effectively adding
2333             T tmp = lhs + AbsValueHelper< U >::Abs( rhs );
2334 
2335             if(tmp >= lhs)
2336             {
2337                 result = tmp;
2338                 return SafeIntNoError;
2339             }
2340         }
2341 
2342         E::SafeIntOnOverflow();
2343         return SafeIntArithmeticOverflow;
2344     }
2345 };
2346 
2347 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Uint64Int2 >
2348 {
2349 public:
Subtract(const U & lhs,const T & rhs,T & result)2350     static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
2351     {
2352         // U is unsigned __int64, T is signed
2353         if( rhs < 0 )
2354         {
2355             // treat this as addition
2356             unsigned __int64 tmp;
2357 
2358             tmp = lhs + (unsigned __int64)AbsValueHelper< T >::Abs( rhs );
2359 
2360             // must check for addition overflow and max
2361             if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
2362             {
2363                 result = (T)tmp;
2364                 return SafeIntNoError;
2365             }
2366         }
2367         else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works
2368         {
2369             // result is negative
2370             // implies that lhs must fit into T, and result cannot overflow
2371             // Also allows us to drop to 32-bit math, which is faster on a 32-bit system
2372             result = (T)lhs - (T)rhs;
2373             return SafeIntNoError;
2374         }
2375         else
2376         {
2377             // result is positive
2378             unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;
2379 
2380             if( tmp <= IntTraits< T >::maxInt )
2381             {
2382                 result = (T)tmp;
2383                 return SafeIntNoError;
2384             }
2385         }
2386 
2387         E::SafeIntOnOverflow();
2388         return SafeIntArithmeticOverflow;
2389     }
2390 };
2391 
2392 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_UintInt64 >
2393 {
2394 public:
Subtract(const T & lhs,const U & rhs,T & result)2395     static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
2396     {
2397         // lhs is an unsigned int32 or smaller, rhs signed __int64
2398         // must first see if rhs is positive or negative
2399         if( rhs >= 0 )
2400         {
2401             if( (unsigned __int64)rhs <= lhs )
2402             {
2403                 result = (T)( lhs - (T)rhs );
2404                 return SafeIntNoError;
2405             }
2406         }
2407         else
2408         {
2409             // we're now effectively adding
2410             // since lhs is 32-bit, and rhs cannot exceed 2^63
2411             // this addition cannot overflow
2412             unsigned __int64 tmp = lhs + (unsigned __int64)( -rhs ); // negation safe
2413 
2414             // but we could exceed MaxInt
2415             if(tmp <= IntTraits< T >::maxInt)
2416             {
2417                 result = (T)tmp;
2418                 return SafeIntNoError;
2419             }
2420         }
2421 
2422         E::SafeIntOnOverflow();
2423         return SafeIntArithmeticOverflow;
2424     }
2425 };
2426 
2427 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_UintInt642 >
2428 {
2429 public:
Subtract(const U & lhs,const T & rhs,T & result)2430     static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
2431     {
2432         // U unsigned 32-bit or less, T __int64
2433         if( rhs >= 0 )
2434         {
2435             // overflow not possible
2436             result = (T)( (__int64)lhs - rhs );
2437             return SafeIntNoError;
2438         }
2439         else
2440         {
2441             // we effectively have an addition
2442             // which cannot overflow internally
2443             unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs );
2444 
2445             if( tmp <= (unsigned __int64)IntTraits< T >::maxInt )
2446             {
2447                 result = (T)tmp;
2448                 return SafeIntNoError;
2449             }
2450         }
2451 
2452         E::SafeIntOnOverflow();
2453         return SafeIntArithmeticOverflow;
2454     }
2455 };
2456 
2457 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Int64Int >
2458 {
2459 public:
Subtract(const T & lhs,const U & rhs,T & result)2460     static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
2461     {
2462         // lhs is an __int64, rhs signed (up to 64-bit)
2463         // we have essentially 4 cases:
2464         //
2465         // 1) lhs positive, rhs positive - overflow not possible
2466         // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error
2467         // 3) lhs negative, rhs positive - check result <= lhs
2468         // 4) lhs negative, rhs negative - overflow not possible
2469 
2470         __int64 tmp = lhs - rhs;
2471 
2472         // Note - ideally, we can order these so that true conditionals
2473         // lead to success, which enables better pipelining
2474         // It isn't practical here
2475         if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2
2476             ( rhs >= 0 && tmp > lhs ) )             // condition 3
2477         {
2478             E::SafeIntOnOverflow();
2479             return SafeIntArithmeticOverflow;
2480         }
2481 
2482         result = (T)tmp;
2483         return SafeIntNoError;
2484     }
2485 };
2486 
2487 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Int64Int2 >
2488 {
2489 public:
Subtract(const U & lhs,const T & rhs,T & result)2490     static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
2491     {
2492         // lhs __int64, rhs any signed int (including __int64)
2493         __int64 tmp = lhs - rhs;
2494 
2495         // we have essentially 4 cases:
2496         //
2497         // 1) lhs positive, rhs positive - overflow not possible in tmp
2498         // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error
2499         // 3) lhs negative, rhs positive - check result <= lhs
2500         // 4) lhs negative, rhs negative - overflow not possible in tmp
2501 
2502         if( lhs >= 0 )
2503         {
2504             // if both positive, overflow to negative not possible
2505             // which is why we'll explicitly check maxInt, and not call SafeCast
2506 #pragma warning(suppress:4127)
2507             if( ( IntTraits< T >::isLT64Bit && tmp > IntTraits< T >::maxInt ) ||
2508                 ( rhs < 0 && tmp < lhs ) )
2509             {
2510                 E::SafeIntOnOverflow();
2511                 return SafeIntArithmeticOverflow;
2512             }
2513         }
2514         else
2515         {
2516             // lhs negative
2517 #pragma warning(suppress:4127)
2518             if( ( IntTraits< T >::isLT64Bit && tmp < IntTraits< T >::minInt) ||
2519                 ( rhs >=0 && tmp > lhs ) )
2520             {
2521                 E::SafeIntOnOverflow();
2522                 return SafeIntArithmeticOverflow;
2523             }
2524         }
2525 
2526         result = (T)tmp;
2527         return SafeIntNoError;
2528     }
2529 };
2530 
2531 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_IntInt64 >
2532 {
2533 public:
Subtract(const T & lhs,const U & rhs,T & result)2534     static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
2535     {
2536         // lhs is a 32-bit int or less, rhs __int64
2537         // we have essentially 4 cases:
2538         //
2539         // lhs positive, rhs positive - rhs could be larger than lhs can represent
2540         // lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int
2541         // lhs negative, rhs positive - check tmp <= lhs and tmp < min int
2542         // lhs negative, rhs negative - addition cannot internally overflow, check against max
2543 
2544         __int64 tmp = (__int64)lhs - rhs;
2545 
2546         if( lhs >= 0 )
2547         {
2548             // first case
2549             if( rhs >= 0 )
2550             {
2551                 if( tmp >= IntTraits< T >::minInt )
2552                 {
2553                     result = (T)tmp;
2554                     return SafeIntNoError;
2555                 }
2556             }
2557             else
2558             {
2559                 // second case
2560                 if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
2561                 {
2562                     result = (T)tmp;
2563                     return SafeIntNoError;
2564                 }
2565             }
2566         }
2567         else
2568         {
2569             // lhs < 0
2570             // third case
2571             if( rhs >= 0 )
2572             {
2573                 if( tmp <= lhs && tmp >= IntTraits< T >::minInt )
2574                 {
2575                     result = (T)tmp;
2576                     return SafeIntNoError;
2577                 }
2578             }
2579             else
2580             {
2581                 // fourth case
2582                 if( tmp <= IntTraits< T >::maxInt )
2583                 {
2584                     result = (T)tmp;
2585                     return SafeIntNoError;
2586                 }
2587             }
2588         }
2589 
2590         E::SafeIntOnOverflow();
2591         return SafeIntArithmeticOverflow;
2592     }
2593 };
2594 
2595 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_IntInt642 >
2596 {
2597 public:
Subtract(const U & lhs,const T & rhs,T & result)2598     static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
2599     {
2600         // lhs is any signed int32 or smaller, rhs is int64
2601         __int64 tmp = (__int64)lhs - rhs;
2602 
2603         if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) ||
2604             ( rhs > 0 && tmp > lhs ) )
2605         {
2606             E::SafeIntOnOverflow();
2607             return SafeIntArithmeticOverflow;
2608             //else OK
2609         }
2610 
2611         result = (T)tmp;
2612         return SafeIntNoError;
2613     }
2614 };
2615 
2616 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Int64Uint >
2617 {
2618 public:
Subtract(const T & lhs,const U & rhs,T & result)2619     static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
2620     {
2621         // lhs is a 64-bit int, rhs unsigned int32 or smaller
2622 
2623         __int64 tmp = lhs - (__int64)rhs;
2624 
2625         if( tmp <= lhs )
2626         {
2627             result = (T)tmp;
2628             return SafeIntNoError;
2629         }
2630 
2631         E::SafeIntOnOverflow();
2632         return SafeIntArithmeticOverflow;
2633     }
2634 };
2635 
2636 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Int64Uint2 >
2637 {
2638 public:
2639     // lhs is __int64, rhs is unsigned 32-bit or smaller
Subtract(const U & lhs,const T & rhs,T & result)2640     static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
2641     {
2642         __int64 tmp = lhs - (__int64)rhs;
2643 
2644         if( tmp <= IntTraits< T >::maxInt && tmp >= IntTraits< T >::minInt )
2645         {
2646             result = (T)tmp;
2647             return SafeIntNoError;
2648         }
2649 
2650         E::SafeIntOnOverflow();
2651         return SafeIntArithmeticOverflow;
2652     }
2653 };
2654 
2655 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_IntUint64 >
2656 {
2657 public:
Subtract(const T & lhs,const U & rhs,T & result)2658     static SafeIntError Subtract( const T& lhs, const U& rhs, T& result )
2659     {
2660         // lhs is any signed int, rhs unsigned int64
2661         // check against available range
2662 
2663         // We need the absolute value of IntTraits< T >::minInt
2664         // This will give it to us without extraneous compiler warnings
2665         const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1;
2666 
2667         if( lhs < 0 )
2668         {
2669             if( rhs <= AbsMinIntT - AbsValueHelper< T >::Abs( lhs ) )
2670             {
2671                 result = (T)( lhs - rhs );
2672                 return SafeIntNoError;
2673             }
2674         }
2675         else
2676         {
2677             if( rhs <= AbsMinIntT + (unsigned __int64)lhs )
2678             {
2679                 result = (T)( lhs - rhs );
2680                 return SafeIntNoError;
2681             }
2682         }
2683 
2684         E::SafeIntOnOverflow();
2685         return SafeIntArithmeticOverflow;
2686     }
2687 };
2688 
2689 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_IntUint642 >
2690 {
2691 public:
Subtract(const U & lhs,const T & rhs,T & result)2692     static SafeIntError Subtract( const U& lhs, const T& rhs, T& result )
2693     {
2694         // We run into upcasting problems on comparison - needs 2 checks
2695         if( lhs >= 0 && (T)lhs >= rhs )
2696         {
2697             result = (T)((U)lhs - (U)rhs);
2698             return SafeIntNoError;
2699         }
2700 
2701         E::SafeIntOnOverflow();
2702         return SafeIntArithmeticOverflow;
2703     }
2704 };
2705 
2706 template < typename E > class SubtractionHelper< __int64, unsigned __int64, E, SubtractionState_Int64Uint64 >
2707 {
2708 public:
Subtract(const __int64 & lhs,const unsigned __int64 & rhs,__int64 & result)2709     static SafeIntError Subtract( const __int64& lhs, const unsigned __int64& rhs, __int64& result )
2710     {
2711         // if we subtract, and it gets larger, there's a problem
2712         __int64 tmp = lhs - (__int64)rhs;
2713 
2714         if( tmp <= lhs )
2715         {
2716             result = tmp;
2717             return SafeIntNoError;
2718         }
2719         E::SafeIntOnOverflow();
2720         return SafeIntArithmeticOverflow;
2721     }
2722 };
2723 
2724 template < typename E > class SubtractionHelper< __int64, unsigned __int64, E, SubtractionState_Int64Uint642 >
2725 {
2726 public:
2727     // If lhs is negative, immediate problem - return must be positive, and subtracting only makes it
2728     // get smaller. If rhs > lhs, then it would also go negative, which is the other case
Subtract(const __int64 & lhs,const unsigned __int64 & rhs,unsigned __int64 & result)2729     static SafeIntError Subtract( const __int64& lhs, const unsigned __int64& rhs, unsigned __int64& result )
2730     {
2731         if( lhs >= 0 && (unsigned __int64)lhs >= rhs )
2732         {
2733             result = (unsigned __int64)lhs - rhs;
2734             return SafeIntNoError;
2735         }
2736 
2737         E::SafeIntOnOverflow();
2738         return SafeIntArithmeticOverflow;
2739     }
2740 };
2741 
2742 enum BinaryState
2743 {
2744     BinaryState_OK,
2745     BinaryState_Int8,
2746     BinaryState_Int16,
2747     BinaryState_Int32
2748 };
2749 
2750 template < typename T, typename U > class BinaryMethod
2751 {
2752 public:
2753     enum
2754     {
2755         // If both operands are unsigned OR
2756         //    return type is smaller than rhs OR
2757         //    return type is larger and rhs is unsigned
2758         // Then binary operations won't produce unexpected results
2759         method = ( sizeof( T ) <= sizeof( U ) ||
2760         SafeIntCompare< T, U >::isBothUnsigned ||
2761         !IntTraits< U >::isSigned )          ? BinaryState_OK :
2762         IntTraits< U >::isInt8               ? BinaryState_Int8 :
2763         IntTraits< U >::isInt16              ? BinaryState_Int16
2764         : BinaryState_Int32
2765     };
2766 };
2767 
2768 template < typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryAndHelper;
2769 
2770 template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_OK >
2771 {
2772 public:
And(T lhs,U rhs)2773     static T And( T lhs, U rhs ){ return (T)( lhs & rhs ); }
2774 };
2775 
2776 template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int8 >
2777 {
2778 public:
And(T lhs,U rhs)2779     static T And( T lhs, U rhs )
2780     {
2781         // cast forces sign extension to be zeros
2782         _SAFEINT_BINARY_ASSERT( ( lhs & rhs ) == ( lhs & (unsigned __int8)rhs ) );
2783         return (T)( lhs & (unsigned __int8)rhs );
2784     }
2785 };
2786 
2787 template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int16 >
2788 {
2789 public:
And(T lhs,U rhs)2790     static T And( T lhs, U rhs )
2791     {
2792         //cast forces sign extension to be zeros
2793         _SAFEINT_BINARY_ASSERT( ( lhs & rhs ) == ( lhs & (unsigned __int16)rhs ) );
2794         return (T)( lhs & (unsigned __int16)rhs );
2795     }
2796 };
2797 
2798 template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int32 >
2799 {
2800 public:
And(T lhs,U rhs)2801     static T And( T lhs, U rhs )
2802     {
2803         //cast forces sign extension to be zeros
2804         _SAFEINT_BINARY_ASSERT( ( lhs & rhs ) == ( lhs & (unsigned __int32)rhs ) );
2805         return (T)( lhs & (unsigned __int32)rhs );
2806     }
2807 };
2808 
2809 template < typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryOrHelper;
2810 
2811 template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_OK >
2812 {
2813 public:
Or(T lhs,U rhs)2814     static T Or( T lhs, U rhs ){ return (T)( lhs | rhs ); }
2815 };
2816 
2817 template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int8 >
2818 {
2819 public:
Or(T lhs,U rhs)2820     static T Or( T lhs, U rhs )
2821     {
2822         //cast forces sign extension to be zeros
2823         _SAFEINT_BINARY_ASSERT( ( lhs | rhs ) == ( lhs | (unsigned __int8)rhs ) );
2824         return (T)( lhs | (unsigned __int8)rhs );
2825     }
2826 };
2827 
2828 template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int16 >
2829 {
2830 public:
Or(T lhs,U rhs)2831     static T Or( T lhs, U rhs )
2832     {
2833         //cast forces sign extension to be zeros
2834         _SAFEINT_BINARY_ASSERT( ( lhs | rhs ) == ( lhs | (unsigned __int16)rhs ) );
2835         return (T)( lhs | (unsigned __int16)rhs );
2836     }
2837 };
2838 
2839 template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int32 >
2840 {
2841 public:
Or(T lhs,U rhs)2842     static T Or( T lhs, U rhs )
2843     {
2844         //cast forces sign extension to be zeros
2845         _SAFEINT_BINARY_ASSERT( ( lhs | rhs ) == ( lhs | (unsigned __int32)rhs ) );
2846         return (T)( lhs | (unsigned __int32)rhs );
2847     }
2848 };
2849 
2850 template <typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryXorHelper;
2851 
2852 template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_OK >
2853 {
2854 public:
Xor(T lhs,U rhs)2855     static T Xor( T lhs, U rhs ){ return (T)( lhs ^ rhs ); }
2856 };
2857 
2858 template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int8 >
2859 {
2860 public:
Xor(T lhs,U rhs)2861     static T Xor( T lhs, U rhs )
2862     {
2863         // cast forces sign extension to be zeros
2864         _SAFEINT_BINARY_ASSERT( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int8)rhs ) );
2865         return (T)( lhs ^ (unsigned __int8)rhs );
2866     }
2867 };
2868 
2869 template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int16 >
2870 {
2871 public:
Xor(T lhs,U rhs)2872     static T Xor( T lhs, U rhs )
2873     {
2874         // cast forces sign extension to be zeros
2875         _SAFEINT_BINARY_ASSERT( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int16)rhs ) );
2876         return (T)( lhs ^ (unsigned __int16)rhs );
2877     }
2878 };
2879 
2880 template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int32 >
2881 {
2882 public:
Xor(T lhs,U rhs)2883     static T Xor( T lhs, U rhs )
2884     {
2885         // cast forces sign extension to be zeros
2886         _SAFEINT_BINARY_ASSERT( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int32)rhs ) );
2887         return (T)( lhs ^ (unsigned __int32)rhs );
2888     }
2889 };
2890 
2891 #pragma warning(pop)
2892 } // namespace details
2893 
2894 } // namespace utilities
2895 
2896 } // namespace msl
2897 
2898 #pragma pack(pop)
2899