Reactos
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
19namespace msl
20{
21
22namespace utilities
23{
24
25namespace details
26{
27#pragma warning(push)
28#pragma warning(disable:4702)
29
30template < typename T >
31class DependentFalse { public: enum{ value = false }; };
32
33template < typename T > class NumericType;
34
35template <> class NumericType<bool> { public: enum{ isBool = true, isFloat = false, isInt = false }; };
36template <> class NumericType<char> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
37template <> class NumericType<unsigned char> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
38template <> class NumericType<signed char> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
39template <> class NumericType<short> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
40template <> class NumericType<unsigned short> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
41#ifdef _NATIVE_WCHAR_T_DEFINED
42template <> class NumericType<wchar_t> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
43#endif /* _NATIVE_WCHAR_T_DEFINED */
44template <> class NumericType<int> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
45template <> class NumericType<unsigned int> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
46template <> class NumericType<long> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
47template <> class NumericType<unsigned long> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
48template <> class NumericType<__int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
49template <> class NumericType<unsigned __int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
50template <> class NumericType<float> { public: enum{ isBool = false, isFloat = true, isInt = false }; };
51template <> class NumericType<double> { public: enum{ isBool = false, isFloat = true, isInt = false }; };
52template <> class NumericType<long double> { public: enum{ isBool = false, isFloat = true, isInt = false }; };
53// Catch-all for anything not supported
54template < typename T > class NumericType { public: enum{ isBool = false, isFloat = false, isInt = false }; };
55
56
57template < typename T > class IntTraits
58{
59public:
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<>
93struct SafeIntErrorPolicy_NoThrow
94{
95 static void SafeIntOnOverflow()
96 {
97 }
98
99 static void SafeIntOnDivZero()
100 {
101 }
102};
103
104template < typename T, typename U > class SafeIntCompare
105{
106public:
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
119template < typename U > class SafeIntCompare< float, U >
120{
121public:
122 enum
123 {
124 isBothSigned = IntTraits< U >::isSigned,
125 isBothUnsigned = false,
126 isLikeSigned = IntTraits< U >::isSigned,
127 isCastOK = true
128 };
129};
130
131template < typename U > class SafeIntCompare< double, U >
132{
133public:
134 enum
135 {
136 isBothSigned = IntTraits< U >::isSigned,
137 isBothUnsigned = false,
138 isLikeSigned = IntTraits< U >::isSigned,
139 isCastOK = true
140 };
141};
142
143template < typename U > class SafeIntCompare< long double, U >
144{
145public:
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
161template < typename T, typename U > class IntRegion
162{
163public:
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
197enum AbsMethod
198{
199 AbsMethodInt,
200 AbsMethodInt64,
201 AbsMethodNoop
202};
203
204template < typename T >
205class GetAbsMethod
206{
207public:
208 enum
209 {
210 method = IntTraits< T >::isLT64Bit && IntTraits< T >::isSigned ? AbsMethodInt :
211 IntTraits< T >::isInt64 ? AbsMethodInt64 : AbsMethodNoop
212 };
213};
214
215template < typename T, int Method = GetAbsMethod< T >::method > class AbsValueHelper;
216
217template < typename T > class AbsValueHelper < T, AbsMethodInt >
218{
219public:
220 static unsigned __int32 Abs( T t ) throw()
221 {
222 _ASSERTE( t < 0 );
223 return (unsigned __int32)-t;
224 }
225};
226
227template < typename T > class AbsValueHelper < T, AbsMethodInt64 >
228{
229public:
230 static unsigned __int64 Abs( T t ) throw()
231 {
232 _ASSERTE( t < 0 );
233 return (unsigned __int64)-t;
234 }
235};
236
237template < typename T > class AbsValueHelper < T, AbsMethodNoop >
238{
239public:
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
248template < typename T, typename E, bool fSigned > class NegationHelper;
249
250template < typename T, typename E > class NegationHelper < T, E, true > // Signed
251{
252public:
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
268template < typename T, typename E > class NegationHelper < T, E, false > // unsigned
269{
270public:
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
285enum CastMethod
286{
287 CastOK = 0,
288 CastCheckLTZero,
289 CastCheckGTMax,
290 CastCheckMinMaxUnsigned,
291 CastCheckMinMaxSigned,
292 CastFromFloat,
293 CastToBool,
294 CastFromBool
295};
296
297template < typename ToType, typename FromType >
298class GetCastMethod
299{
300public:
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
330template < typename T, typename U, typename E,
331 int Method = GetCastMethod< T, U >::method > class SafeCastHelper;
332
333template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastOK >
334{
335public:
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
345template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastFromFloat >
346{
347public:
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
363template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastFromBool >
364{
365public:
366 static SafeIntError Cast( bool b, T& t ) throw()
367 {
368 t = (T)( b ? 1 : 0 );
369 return SafeIntNoError;
370 }
371};
372
373template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastToBool >
374{
375public:
376 static SafeIntError Cast( T t, bool& b ) throw()
377 {
378 b = !!t;
379 return SafeIntNoError;
380 }
381};
382
383template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckLTZero >
384{
385public:
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
399template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckGTMax >
400{
401public:
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
415template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckMinMaxUnsigned >
416{
417public:
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
432template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckMinMaxSigned >
433{
434public:
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
450enum ComparisonMethod
451{
452 ComparisonMethod_Ok = 0,
453 ComparisonMethod_CastInt,
454 ComparisonMethod_CastInt64,
455 ComparisonMethod_UnsignedT,
456 ComparisonMethod_UnsignedU
457};
458
459template < typename T, typename U >
460class ValidComparison
461{
462public:
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
479template <typename T, typename U, int Method = ValidComparison< T, U >::method > class EqualityTest;
480
481template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_Ok >
482{
483public:
484 static bool IsEquals( const T t, const U u ) throw() { return ( t == u ); }
485};
486
487template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt >
488{
489public:
490 static bool IsEquals( const T t, const U u ) throw() { return ( (int)t == (int)u ); }
491};
492
493template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt64 >
494{
495public:
496 static bool IsEquals( const T t, const U u ) throw() { return ( (__int64)t == (__int64)u ); }
497};
498
499template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedT >
500{
501public:
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
515template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedU>
516{
517public:
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
531template <typename T, typename U, int Method = ValidComparison< T, U >::method > class GreaterThanTest;
532
533template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_Ok >
534{
535public:
536 static bool GreaterThan( const T t, const U u ) throw() { return ( t > u ); }
537};
538
539template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt >
540{
541public:
542 static bool GreaterThan( const T t, const U u ) throw() { return ( (int)t > (int)u ); }
543};
544
545template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt64 >
546{
547public:
548 static bool GreaterThan( const T t, const U u ) throw() { return ( (__int64)t > (__int64)u ); }
549};
550
551template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedT >
552{
553public:
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
567template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedU >
568{
569public:
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
585template <typename T, typename U, typename E, int Method = ValidComparison< T, U >::method > class ModulusHelper;
586
587template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_Ok>
588{
589public:
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
614template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_CastInt>
615{
616public:
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
641template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_CastInt64>
642{
643public:
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
667template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_UnsignedT>
668{
669public:
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
694template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_UnsignedU>
695{
696public:
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
720enum 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
741template < typename T, typename U >
742class MultiplicationMethod
743{
744public:
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
780template <typename T, typename U, typename E, int Method = MultiplicationMethod< T, U >::method > class MultiplicationHelper;
781
782template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastInt>
783{
784public:
785 //accepts signed, both less than 32-bit
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
801template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastUint >
802{
803public:
804 //accepts unsigned, both less than 32-bit
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
820template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastInt64>
821{
822public:
823 //mixed signed or both signed where at least one argument is 32-bit, and both a 32-bit or less
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
839template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastUint64>
840{
841public:
842 //both unsigned where at least one argument is 32-bit, and both are 32-bit or less
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
860template < typename T, typename U, typename E > class LargeIntRegMultiply;
861
862template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >
863{
864public:
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
929template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >
930{
931public:
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
975template< typename E > class LargeIntRegMultiply< unsigned __int64, signed __int32, E >
976{
977public:
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
990template< typename E > class LargeIntRegMultiply< unsigned __int64, signed __int64, E >
991{
992public:
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
1005template< typename E > class LargeIntRegMultiply< signed __int32, unsigned __int64, E >
1006{
1007public:
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
1059template < typename E > class LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >
1060{
1061public:
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
1089template < typename E > class LargeIntRegMultiply< unsigned __int32, signed __int64, E >
1090{
1091public:
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
1104template < typename E > class LargeIntRegMultiply< signed __int64, signed __int64, E >
1105{
1106public:
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
1157template < typename E > class LargeIntRegMultiply< signed __int64, unsigned __int32, E >
1158{
1159public:
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
1200template < typename E > class LargeIntRegMultiply< signed __int64, signed __int32, E >
1201{
1202public:
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
1253template < typename E > class LargeIntRegMultiply< signed __int32, signed __int64, E >
1254{
1255public:
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
1306template < typename E > class LargeIntRegMultiply< signed __int64, unsigned __int64, E >
1307{
1308public:
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
1351template < typename E > class MultiplicationHelper< unsigned __int64, unsigned __int64, E, MultiplicationState_Uint64Uint64 >
1352{
1353public:
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
1360template < typename U, typename E > class MultiplicationHelper<unsigned __int64, U, E, MultiplicationState_Uint64Uint >
1361{
1362public:
1363 //U is any unsigned int 32-bit or less
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
1371template < typename T, typename E > class MultiplicationHelper< T, unsigned __int64, E, MultiplicationState_UintUint64 >
1372{
1373public:
1374 // T is any unsigned int up to 32-bit
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
1390template < typename U, typename E > class MultiplicationHelper< unsigned __int64, U, E, MultiplicationState_Uint64Int >
1391{
1392public:
1393 //U is any signed int, up to 64-bit
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
1400template < typename E > class MultiplicationHelper<unsigned __int64, __int64, E, MultiplicationState_Uint64Int64 >
1401{
1402public:
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
1409template < typename T, typename E > class MultiplicationHelper< T, __int64, E, MultiplicationState_UintInt64 >
1410{
1411public:
1412 //T is unsigned up to 32-bit
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
1428template < typename U, typename E > class MultiplicationHelper<__int64, U, E, MultiplicationState_Int64Uint >
1429{
1430public:
1431 //U is unsigned up to 32-bit
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
1438template < typename E > class MultiplicationHelper<__int64, __int64, E, MultiplicationState_Int64Int64 >
1439{
1440public:
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
1447template < typename U, typename E > class MultiplicationHelper<__int64, U, E, MultiplicationState_Int64Int>
1448{
1449public:
1450 //U is signed up to 32-bit
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
1457template < typename T, typename E > class MultiplicationHelper< T, unsigned __int64, E, MultiplicationState_IntUint64 >
1458{
1459public:
1460 //T is signed up to 32-bit
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
1476template < typename E > class MultiplicationHelper<__int64, unsigned __int64, E, MultiplicationState_Int64Uint64>
1477{
1478public:
1479 //U is signed up to 32-bit
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
1486template < typename T, typename E > class MultiplicationHelper< T, __int64, E, MultiplicationState_IntInt64>
1487{
1488public:
1489 //T is signed, up to 32-bit
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
1505enum DivisionState
1506{
1507 DivisionState_OK,
1508 DivisionState_UnsignedSigned,
1509 DivisionState_SignedUnsigned32,
1510 DivisionState_SignedUnsigned64,
1511 DivisionState_SignedUnsigned,
1512 DivisionState_SignedSigned
1513};
1514
1515template < typename T, typename U > class DivisionMethod
1516{
1517public:
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
1531template < typename T, typename U, typename E, int Method = DivisionMethod< T, U >::method > class DivisionHelper;
1532
1533template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_OK >
1534{
1535public:
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
1549template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_UnsignedSigned>
1550{
1551public:
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
1579template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedUnsigned32 >
1580{
1581public:
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
1602template < typename T, typename E > class DivisionHelper< T, unsigned __int64, E, DivisionState_SignedUnsigned64 >
1603{
1604public:
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
1636template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedUnsigned>
1637{
1638public:
1639 // T is any signed, U is unsigned and smaller than 32-bit
1640 // In this case, standard operator casting is correct
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
1654template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedSigned>
1655{
1656public:
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
1677enum 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
1697template< typename T, typename U >
1698class AdditionMethod
1699{
1700public:
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
1734template < typename T, typename U, typename E, int Method = AdditionMethod< T, U >::method > class AdditionHelper;
1735
1736template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastIntCheckMax >
1737{
1738public:
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
1755template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUintCheckOverflow >
1756{
1757public:
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
1774template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUintCheckOverflowMax>
1775{
1776public:
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
1793template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckOverflow>
1794{
1795public:
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
1813template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckOverflowMax >
1814{
1815public:
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
1833template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastIntCheckMinMax >
1834{
1835public:
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)
1854template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckMinMax >
1855{
1856public:
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
1875template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckMax >
1876{
1877public:
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
1894template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckMinMax >
1895{
1896public:
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
1931template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckMinMax2>
1932{
1933public:
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
1963template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflow>
1964{
1965public:
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
1995template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflowMinMax>
1996{
1997public:
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
2017template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflowMax >
2018{
2019public:
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
2036template < typename E > class AdditionHelper < __int64, unsigned __int64, E, AdditionState_ManualCheckInt64Uint64 >
2037{
2038public:
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
2055template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_ManualCheck >
2056{
2057public:
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
2078enum 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
2106template < typename T, typename U > class SubtractionMethod
2107{
2108public:
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 >
2143template < typename T, typename U > class SubtractionMethod2
2144{
2145public:
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
2179template < typename T, typename U, typename E, int Method = SubtractionMethod< T, U >::method > class SubtractionHelper;
2180
2181template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_BothUnsigned >
2182{
2183public:
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
2198template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_BothUnsigned2 >
2199{
2200public:
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
2216template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastIntCheckMinMax >
2217{
2218public:
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
2236template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_CastIntCheckMinMax2 >
2237{
2238public:
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
2249template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastIntCheckMin >
2250{
2251public:
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
2269template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastInt64CheckMinMax >
2270{
2271public:
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
2282template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_CastInt64CheckMinMax2 >
2283{
2284public:
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
2295template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastInt64CheckMin >
2296{
2297public:
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
2315template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Uint64Int >
2316{
2317public:
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
2347template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Uint64Int2 >
2348{
2349public:
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
2392template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_UintInt64 >
2393{
2394public:
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
2427template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_UintInt642 >
2428{
2429public:
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
2457template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Int64Int >
2458{
2459public:
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
2487template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Int64Int2 >
2488{
2489public:
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
2531template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_IntInt64 >
2532{
2533public:
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
2595template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_IntInt642 >
2596{
2597public:
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
2616template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Int64Uint >
2617{
2618public:
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
2636template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Int64Uint2 >
2637{
2638public:
2639 // lhs is __int64, rhs is unsigned 32-bit or smaller
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
2655template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_IntUint64 >
2656{
2657public:
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
2689template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_IntUint642 >
2690{
2691public:
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
2706template < typename E > class SubtractionHelper< __int64, unsigned __int64, E, SubtractionState_Int64Uint64 >
2707{
2708public:
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
2724template < typename E > class SubtractionHelper< __int64, unsigned __int64, E, SubtractionState_Int64Uint642 >
2725{
2726public:
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
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
2742enum BinaryState
2743{
2744 BinaryState_OK,
2745 BinaryState_Int8,
2746 BinaryState_Int16,
2747 BinaryState_Int32
2748};
2749
2750template < typename T, typename U > class BinaryMethod
2751{
2752public:
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
2768template < typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryAndHelper;
2769
2770template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_OK >
2771{
2772public:
2773 static T And( T lhs, U rhs ){ return (T)( lhs & rhs ); }
2774};
2775
2776template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int8 >
2777{
2778public:
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
2787template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int16 >
2788{
2789public:
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
2798template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int32 >
2799{
2800public:
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
2809template < typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryOrHelper;
2810
2811template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_OK >
2812{
2813public:
2814 static T Or( T lhs, U rhs ){ return (T)( lhs | rhs ); }
2815};
2816
2817template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int8 >
2818{
2819public:
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
2828template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int16 >
2829{
2830public:
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
2839template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int32 >
2840{
2841public:
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
2850template <typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryXorHelper;
2851
2852template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_OK >
2853{
2854public:
2855 static T Xor( T lhs, U rhs ){ return (T)( lhs ^ rhs ); }
2856};
2857
2858template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int8 >
2859{
2860public:
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
2869template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int16 >
2870{
2871public:
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
2880template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int32 >
2881{
2882public:
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)