Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899/****safeint_internal.h - Internal details for SafeInt (see safeint.h)** Copyright (c) Microsoft Corporation. All rights reserved.**Purpose:* Private internal details for SafeInt.* The constructs and functions in Microsoft::Utilities::details are not* meant to be used by external code and can change at any time.*****/
#pragma once
#include <crtdbg.h>
#pragma pack(push, _CRT_PACKING)
namespace msl{
namespace utilities{
namespace details{#pragma warning(push)#pragma warning(disable:4702)
template < typename T >class DependentFalse { public: enum{ value = false }; };
template < typename T > class NumericType;
template <> class NumericType<bool> { public: enum{ isBool = true, isFloat = false, isInt = false }; };template <> class NumericType<char> { public: enum{ isBool = false, isFloat = false, isInt = true }; };template <> class NumericType<unsigned char> { public: enum{ isBool = false, isFloat = false, isInt = true }; };template <> class NumericType<signed char> { public: enum{ isBool = false, isFloat = false, isInt = true }; };template <> class NumericType<short> { public: enum{ isBool = false, isFloat = false, isInt = true }; };template <> class NumericType<unsigned short> { public: enum{ isBool = false, isFloat = false, isInt = true }; };#ifdef _NATIVE_WCHAR_T_DEFINEDtemplate <> class NumericType<wchar_t> { public: enum{ isBool = false, isFloat = false, isInt = true }; };#endif /* _NATIVE_WCHAR_T_DEFINED */template <> class NumericType<int> { public: enum{ isBool = false, isFloat = false, isInt = true }; };template <> class NumericType<unsigned int> { public: enum{ isBool = false, isFloat = false, isInt = true }; };template <> class NumericType<long> { public: enum{ isBool = false, isFloat = false, isInt = true }; };template <> class NumericType<unsigned long> { public: enum{ isBool = false, isFloat = false, isInt = true }; };template <> class NumericType<__int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; };template <> class NumericType<unsigned __int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; };template <> class NumericType<float> { public: enum{ isBool = false, isFloat = true, isInt = false }; };template <> class NumericType<double> { public: enum{ isBool = false, isFloat = true, isInt = false }; };template <> class NumericType<long double> { public: enum{ isBool = false, isFloat = true, isInt = false }; };// Catch-all for anything not supportedtemplate < typename T > class NumericType { public: enum{ isBool = false, isFloat = false, isInt = false }; };
template < typename T > class IntTraits{public: static_assert( NumericType<T>::isInt || NumericType<T>::isBool, "non-integral type T" ); enum {#pragma warning(suppress:4804) isSigned = ( (T)(-1) < 0 ), is64Bit = ( sizeof(T) == 8 ), is32Bit = ( sizeof(T) == 4 ), is16Bit = ( sizeof(T) == 2 ), is8Bit = ( sizeof(T) == 1 ), isLT32Bit = ( sizeof(T) < 4 ), isLT64Bit = ( sizeof(T) < 8 ), isInt8 = ( sizeof(T) == 1 && isSigned ), isUint8 = ( sizeof(T) == 1 && !isSigned ), isInt16 = ( sizeof(T) == 2 && isSigned ), isUint16 = ( sizeof(T) == 2 && !isSigned ), isInt32 = ( sizeof(T) == 4 && isSigned ), isUint32 = ( sizeof(T) == 4 && !isSigned ), isInt64 = ( sizeof(T) == 8 && isSigned ), isUint64 = ( sizeof(T) == 8 && !isSigned ), bitCount = ( sizeof(T)*8 ),#pragma warning(suppress:4804) isBool = NumericType<T>::isBool };
#pragma warning(push)#pragma warning(disable:4310)#pragma warning(disable:4804) // suppress warning about '<<' being an unsafe operation when T is bool const static T maxInt = isSigned ? ((T)~((T)1 << (T)(bitCount-1))) : ((T)(~(T)0)); const static T minInt = isSigned ? ((T)((T)1 << (T)(bitCount-1))) : ((T)0);#pragma warning(pop)};
// this is strictly internal and not to be used as a policy in SafeInt<>struct SafeIntErrorPolicy_NoThrow{ static void SafeIntOnOverflow() { }
static void SafeIntOnDivZero() { }};
template < typename T, typename U > class SafeIntCompare{public: enum { isBothSigned = (IntTraits< T >::isSigned && IntTraits< U >::isSigned), isBothUnsigned = (!IntTraits< T >::isSigned && !IntTraits< U >::isSigned), isLikeSigned = (static_cast<bool>(IntTraits< T >::isSigned) == static_cast<bool>(IntTraits< U >::isSigned)), isCastOK = ((isLikeSigned && sizeof(T) >= sizeof(U)) || (IntTraits< T >::isSigned && sizeof(T) > sizeof(U))), isBothLT32Bit = (IntTraits< T >::isLT32Bit && IntTraits< U >::isLT32Bit), isBothLT64Bit = (IntTraits< T >::isLT64Bit && IntTraits< U >::isLT64Bit) };};
template < typename U > class SafeIntCompare< float, U >{public: enum { isBothSigned = IntTraits< U >::isSigned, isBothUnsigned = false, isLikeSigned = IntTraits< U >::isSigned, isCastOK = true };};
template < typename U > class SafeIntCompare< double, U >{public: enum { isBothSigned = IntTraits< U >::isSigned, isBothUnsigned = false, isLikeSigned = IntTraits< U >::isSigned, isCastOK = true };};
template < typename U > class SafeIntCompare< long double, U >{public: enum { isBothSigned = IntTraits< U >::isSigned, isBothUnsigned = false, isLikeSigned = IntTraits< U >::isSigned, isCastOK = true };};
//all of the arithmetic operators can be solved by the same code within//each of these regions without resorting to compile-time constant conditionals//most operators collapse the problem into less than the 22 zones, but this is used//as the first cut//using this also helps ensure that we handle all of the possible cases correctly
template < typename T, typename U > class IntRegion{public: enum { //unsigned-unsigned zone IntZone_UintLT32_UintLT32 = SafeIntCompare< T,U >::isBothUnsigned && SafeIntCompare< T,U >::isBothLT32Bit, IntZone_Uint32_UintLT64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit, IntZone_UintLT32_Uint32 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit, IntZone_Uint64_Uint = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is64Bit, IntZone_UintLT64_Uint64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit, //unsigned-signed IntZone_UintLT32_IntLT32 = !IntTraits< T >::isSigned && IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit, IntZone_Uint32_IntLT64 = IntTraits< T >::isUint32 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, IntZone_UintLT32_Int32 = !IntTraits< T >::isSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::isInt32, IntZone_Uint64_Int = IntTraits< T >::isUint64 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, IntZone_UintLT64_Int64 = !IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isInt64, IntZone_Uint64_Int64 = IntTraits< T >::isUint64 && IntTraits< U >::isInt64, //signed-signed IntZone_IntLT32_IntLT32 = SafeIntCompare< T,U >::isBothSigned && SafeIntCompare< T, U >::isBothLT32Bit, IntZone_Int32_IntLT64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit, IntZone_IntLT32_Int32 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit, IntZone_Int64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isInt64 && IntTraits< U >::isInt64, IntZone_Int64_Int = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is64Bit && IntTraits< U >::isLT64Bit, IntZone_IntLT64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit, //signed-unsigned IntZone_IntLT32_UintLT32 = IntTraits< T >::isSigned && !IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit, IntZone_Int32_UintLT32 = IntTraits< T >::isInt32 && !IntTraits< U >::isSigned && IntTraits< U >::isLT32Bit, IntZone_IntLT64_Uint32 = IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isUint32, IntZone_Int64_UintLT64 = IntTraits< T >::isInt64 && !IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, IntZone_Int_Uint64 = IntTraits< T >::isSigned && IntTraits< U >::isUint64 && IntTraits< T >::isLT64Bit, IntZone_Int64_Uint64 = IntTraits< T >::isInt64 && IntTraits< U >::isUint64 };};
// useful function to help with getting the magnitude of a negative numberenum AbsMethod{ AbsMethodInt, AbsMethodInt64, AbsMethodNoop};
template < typename T >class GetAbsMethod{public: enum { method = IntTraits< T >::isLT64Bit && IntTraits< T >::isSigned ? AbsMethodInt : IntTraits< T >::isInt64 ? AbsMethodInt64 : AbsMethodNoop };};
template < typename T, int Method = GetAbsMethod< T >::method > class AbsValueHelper;
template < typename T > class AbsValueHelper < T, AbsMethodInt >{public: static unsigned __int32 Abs( T t ) throw() { _ASSERTE( t < 0 ); return (unsigned __int32)-t; }};
template < typename T > class AbsValueHelper < T, AbsMethodInt64 >{public: static unsigned __int64 Abs( T t ) throw() { _ASSERTE( t < 0 ); return (unsigned __int64)-t; }};
template < typename T > class AbsValueHelper < T, AbsMethodNoop >{public: static T Abs( T t ) throw() { // Why are you calling Abs on an unsigned number ??? _ASSERTE( ("AbsValueHelper::Abs should not be called with an unsigned integer type", 0) ); return t; }};
template < typename T, typename E, bool fSigned > class NegationHelper;
template < typename T, typename E > class NegationHelper < T, E, true > // Signed{public: static SafeIntError Negative( T t, T& ret ) { // corner case if( t != IntTraits< T >::minInt ) { // cast prevents unneeded checks in the case of small ints ret = -t; return SafeIntNoError; } E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename E > class NegationHelper < T, E, false > // unsigned{public: static SafeIntError Negative( T t, T& ret ) throw() { _SAFEINT_UNSIGNED_NEGATION_BEHAVIOR();
#pragma warning(suppress:4127) _ASSERTE( !IntTraits<T>::isLT32Bit );
#pragma warning(suppress:4146) ret = -t; return SafeIntNoError; }};
//core logic to determine casting behaviorenum CastMethod{ CastOK = 0, CastCheckLTZero, CastCheckGTMax, CastCheckMinMaxUnsigned, CastCheckMinMaxSigned, CastFromFloat, CastToBool, CastFromBool};
template < typename ToType, typename FromType >class GetCastMethod{public: enum { method = ( IntTraits< FromType >::isBool && !IntTraits< ToType >::isBool ) ? CastFromBool :
( !IntTraits< FromType >::isBool && IntTraits< ToType >::isBool ) ? CastToBool : ( NumericType< FromType >::isFloat && !NumericType< ToType >::isFloat ) ? CastFromFloat :
( SafeIntCompare< ToType, FromType >::isCastOK || ( NumericType< ToType >::isFloat && !NumericType< FromType >::isFloat ) ) ? CastOK :
( ( IntTraits< ToType >::isSigned && !IntTraits< FromType >::isSigned && sizeof( FromType ) >= sizeof( ToType ) ) || ( SafeIntCompare< ToType, FromType >::isBothUnsigned && sizeof( FromType ) > sizeof( ToType ) ) ) ? CastCheckGTMax :
( !IntTraits< ToType >::isSigned && IntTraits< FromType >::isSigned && sizeof( ToType ) >= sizeof( FromType ) ) ? CastCheckLTZero :
( !IntTraits< ToType >::isSigned ) ? CastCheckMinMaxUnsigned : CastCheckMinMaxSigned };};
template < typename T, typename U, typename E, int Method = GetCastMethod< T, U >::method > class SafeCastHelper;
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastOK >{public: static SafeIntError Cast( U u, T& t ) throw() { t = (T)u; return SafeIntNoError; }};
// special case floats and doubles// tolerate loss of precisiontemplate < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastFromFloat >{public: static SafeIntError Cast( U u, T& t ) { if( u <= (U)IntTraits< T >::maxInt && u >= (U)IntTraits< T >::minInt ) { t = (T)u; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
// Match on any method where a bool is cast to type Ttemplate < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastFromBool >{public: static SafeIntError Cast( bool b, T& t ) throw() { t = (T)( b ? 1 : 0 ); return SafeIntNoError; }};
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastToBool >{public: static SafeIntError Cast( T t, bool& b ) throw() { b = !!t; return SafeIntNoError; }};
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckLTZero >{public: static SafeIntError Cast( U u, T& t ) { if( u < 0 ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
t = (T)u; return SafeIntNoError; }};
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckGTMax >{public: static SafeIntError Cast( U u, T& t ) { if( u > IntTraits< T >::maxInt ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
t = (T)u; return SafeIntNoError; }};
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckMinMaxUnsigned >{public: static SafeIntError Cast( U u, T& t ) { // U is signed - T could be either signed or unsigned if( u > IntTraits< T >::maxInt || u < 0 ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
t = (T)u; return SafeIntNoError; }};
template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckMinMaxSigned >{public: static SafeIntError Cast( U u, T& t ) { // T, U are signed if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
t = (T)u; return SafeIntNoError; }};
//core logic to determine whether a comparison is valid, or needs special treatmentenum ComparisonMethod{ ComparisonMethod_Ok = 0, ComparisonMethod_CastInt, ComparisonMethod_CastInt64, ComparisonMethod_UnsignedT, ComparisonMethod_UnsignedU};
template < typename T, typename U >class ValidComparison{public: enum {#if _SAFEINT_USE_ANSI_CONVERSIONS method = ComparisonMethod_Ok#else /* _SAFEINT_USE_ANSI_CONVERSIONS */ method = ( ( SafeIntCompare< T, U >::isLikeSigned ) ? ComparisonMethod_Ok : ( ( IntTraits< T >::isSigned && sizeof(T) < 8 && sizeof(U) < 4 ) || ( IntTraits< U >::isSigned && sizeof(T) < 4 && sizeof(U) < 8 ) ) ? ComparisonMethod_CastInt : ( ( IntTraits< T >::isSigned && sizeof(U) < 8 ) || ( IntTraits< U >::isSigned && sizeof(T) < 8 ) ) ? ComparisonMethod_CastInt64 : ( !IntTraits< T >::isSigned ) ? ComparisonMethod_UnsignedT : ComparisonMethod_UnsignedU )#endif /* _SAFEINT_USE_ANSI_CONVERSIONS */ };};
template <typename T, typename U, int Method = ValidComparison< T, U >::method > class EqualityTest;
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_Ok >{public: static bool IsEquals( const T t, const U u ) throw() { return ( t == u ); }};
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt >{public: static bool IsEquals( const T t, const U u ) throw() { return ( (int)t == (int)u ); }};
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt64 >{public: static bool IsEquals( const T t, const U u ) throw() { return ( (__int64)t == (__int64)u ); }};
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedT >{public: static bool IsEquals( const T t, const U u ) throw() { //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller if( u < 0 ) { return false; }
//else safe to cast to type T return ( t == (T)u ); }};
template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedU>{public: static bool IsEquals( const T t, const U u ) throw() { //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller if( t < 0 ) { return false; }
//else safe to cast to type U return ( (U)t == u ); }};
template <typename T, typename U, int Method = ValidComparison< T, U >::method > class GreaterThanTest;
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_Ok >{public: static bool GreaterThan( const T t, const U u ) throw() { return ( t > u ); }};
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt >{public: static bool GreaterThan( const T t, const U u ) throw() { return ( (int)t > (int)u ); }};
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt64 >{public: static bool GreaterThan( const T t, const U u ) throw() { return ( (__int64)t > (__int64)u ); }};
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedT >{public: static bool GreaterThan( const T t, const U u ) throw() { // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller if( u < 0 ) { return SafeIntNoError; }
// else safe to cast to type T return ( t > (T)u ); }};
template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedU >{public: static bool GreaterThan( const T t, const U u ) throw() { // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller if( t < 0 ) { return false; }
// else safe to cast to type U return ( (U)t > u ); }};
// Modulus is simpler than comparison, but follows much the same logic// using this set of functions, it can't fail except in a div 0 situationtemplate <typename T, typename U, typename E, int Method = ValidComparison< T, U >::method > class ModulusHelper;
template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_Ok>{public: static SafeIntError Modulus( const T& t, const U& u, T& result ) { if(u == 0) { E::SafeIntOnDivZero(); return SafeIntDivideByZero; }
// trap corner case#pragma warning(suppress:4127) if( IntTraits< U >::isSigned ) { if(u == -1) { result = 0; return SafeIntNoError; } }
result = (T)(t % u); return SafeIntNoError; }};
template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_CastInt>{public: static SafeIntError Modulus( const T& t, const U& u, T& result ) { if(u == 0) { E::SafeIntOnDivZero(); return SafeIntDivideByZero; }
// trap corner case#pragma warning(suppress:4127) if( IntTraits< U >::isSigned ) { if(u == -1) { result = 0; return SafeIntNoError; } }
result = (T)(t % u); return SafeIntNoError; }};
template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_CastInt64>{public: static SafeIntError Modulus( const T& t, const U& u, T& result ) { if(u == 0) { E::SafeIntOnDivZero(); return SafeIntDivideByZero; }
#pragma warning(suppress:4127) if(IntTraits< U >::isSigned && u == -1) { result = 0; } else { result = (T)((__int64)t % (__int64)u); }
return SafeIntNoError; }};
// T is unsigned __int64, U is any signed inttemplate <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_UnsignedT>{public: static SafeIntError Modulus( const T& t, const U& u, T& result ) { if(u == 0) { E::SafeIntOnDivZero(); return SafeIntDivideByZero; }
// u could be negative - if so, need to convert to positive // casts below are always safe due to the way modulus works if(u < 0) { result = (T)(t % AbsValueHelper< U >::Abs(u)); } else { result = (T)(t % u); }
return SafeIntNoError; }};
// U is unsigned __int64, T any signed inttemplate <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_UnsignedU>{public: static SafeIntError Modulus( const T& t, const U& u, T& result ) { if(u == 0) { E::SafeIntOnDivZero(); return SafeIntDivideByZero; }
//t could be negative - if so, need to convert to positive if(t < 0) { result = -(T)( AbsValueHelper< T >::Abs( t ) % u ); } else { result = (T)((T)t % u); }
return SafeIntNoError; }};
//core logic to determine method to check multiplicationenum MultiplicationState{ MultiplicationState_CastInt = 0, // One or both signed, smaller than 32-bit MultiplicationState_CastInt64, // One or both signed, smaller than 64-bit MultiplicationState_CastUint, // Both are unsigned, smaller than 32-bit MultiplicationState_CastUint64, // Both are unsigned, both 32-bit or smaller MultiplicationState_Uint64Uint, // Both are unsigned, lhs 64-bit, rhs 32-bit or smaller MultiplicationState_Uint64Uint64, // Both are unsigned int64 MultiplicationState_Uint64Int, // lhs is unsigned int64, rhs int32 MultiplicationState_Uint64Int64, // lhs is unsigned int64, rhs signed int64 MultiplicationState_UintUint64, // Both are unsigned, lhs 32-bit or smaller, rhs 64-bit MultiplicationState_UintInt64, // lhs unsigned 32-bit or less, rhs int64 MultiplicationState_Int64Uint, // lhs int64, rhs unsigned int32 MultiplicationState_Int64Int64, // lhs int64, rhs int64 MultiplicationState_Int64Int, // lhs int64, rhs int32 MultiplicationState_IntUint64, // lhs int, rhs unsigned int64 MultiplicationState_IntInt64, // lhs int, rhs int64 MultiplicationState_Int64Uint64, // lhs int64, rhs uint64 MultiplicationState_Error};
template < typename T, typename U >class MultiplicationMethod{public: enum { // unsigned-unsigned method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? MultiplicationState_CastUint : (IntRegion< T,U >::IntZone_Uint32_UintLT64 || IntRegion< T,U >::IntZone_UintLT32_Uint32) ? MultiplicationState_CastUint64 : SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isUint64 && IntTraits< U >::isUint64 ? MultiplicationState_Uint64Uint64 : (IntRegion< T,U >::IntZone_Uint64_Uint) ? MultiplicationState_Uint64Uint : (IntRegion< T,U >::IntZone_UintLT64_Uint64) ? MultiplicationState_UintUint64 : // unsigned-signed (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? MultiplicationState_CastInt : (IntRegion< T,U >::IntZone_Uint32_IntLT64 || IntRegion< T,U >::IntZone_UintLT32_Int32) ? MultiplicationState_CastInt64 : (IntRegion< T,U >::IntZone_Uint64_Int) ? MultiplicationState_Uint64Int : (IntRegion< T,U >::IntZone_UintLT64_Int64) ? MultiplicationState_UintInt64 : (IntRegion< T,U >::IntZone_Uint64_Int64) ? MultiplicationState_Uint64Int64 : // signed-signed (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? MultiplicationState_CastInt : (IntRegion< T,U >::IntZone_Int32_IntLT64 || IntRegion< T,U >::IntZone_IntLT32_Int32) ? MultiplicationState_CastInt64 : (IntRegion< T,U >::IntZone_Int64_Int64) ? MultiplicationState_Int64Int64 : (IntRegion< T,U >::IntZone_Int64_Int) ? MultiplicationState_Int64Int : (IntRegion< T,U >::IntZone_IntLT64_Int64) ? MultiplicationState_IntInt64 : // signed-unsigned (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? MultiplicationState_CastInt : (IntRegion< T,U >::IntZone_Int32_UintLT32 || IntRegion< T,U >::IntZone_IntLT64_Uint32) ? MultiplicationState_CastInt64 : (IntRegion< T,U >::IntZone_Int64_UintLT64) ? MultiplicationState_Int64Uint : (IntRegion< T,U >::IntZone_Int_Uint64) ? MultiplicationState_IntUint64 : (IntRegion< T,U >::IntZone_Int64_Uint64 ? MultiplicationState_Int64Uint64 : MultiplicationState_Error ) ) };};
template <typename T, typename U, typename E, int Method = MultiplicationMethod< T, U >::method > class MultiplicationHelper;
template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastInt>{public: //accepts signed, both less than 32-bit static SafeIntError Multiply( const T& t, const U& u, T& ret ) { int tmp = t * u;
if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
ret = (T)tmp; return SafeIntNoError; }};
template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastUint >{public: //accepts unsigned, both less than 32-bit static SafeIntError Multiply( const T& t, const U& u, T& ret ) { unsigned int tmp = t * u;
if( tmp > IntTraits< T >::maxInt ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
ret = (T)tmp; return SafeIntNoError; }};
template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastInt64>{public: //mixed signed or both signed where at least one argument is 32-bit, and both a 32-bit or less static SafeIntError Multiply( const T& t, const U& u, T& ret ) { __int64 tmp = (__int64)t * (__int64)u;
if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
ret = (T)tmp; return SafeIntNoError; }};
template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastUint64>{public: //both unsigned where at least one argument is 32-bit, and both are 32-bit or less static SafeIntError Multiply( const T& t, const U& u, T& ret ) { unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u;
if(tmp > (unsigned __int64)IntTraits< T >::maxInt) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
ret = (T)tmp; return SafeIntNoError; }};
// T = left arg and return type// U = right argtemplate < typename T, typename U, typename E > class LargeIntRegMultiply;
template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >{public: static SafeIntError RegMultiply( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64& ret ) { unsigned __int32 aHigh, aLow, bHigh, bLow;
// Consider that a*b can be broken up into: // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow) // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow) // Note - same approach applies for 128 bit math on a 64-bit system
aHigh = (unsigned __int32)(a >> 32); aLow = (unsigned __int32)a; bHigh = (unsigned __int32)(b >> 32); bLow = (unsigned __int32)b;
ret = 0;
if(aHigh == 0) { if(bHigh != 0) { ret = (unsigned __int64)aLow * (unsigned __int64)bHigh; } } else if(bHigh == 0) { if(aHigh != 0) { ret = (unsigned __int64)aHigh * (unsigned __int64)bLow; } } else { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
if(ret != 0) { unsigned __int64 tmp;
if((unsigned __int32)(ret >> 32) != 0) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
ret <<= 32; tmp = (unsigned __int64)aLow * (unsigned __int64)bLow; ret += tmp;
if(ret < tmp) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
return SafeIntNoError; }
ret = (unsigned __int64)aLow * (unsigned __int64)bLow; return SafeIntNoError; }};
template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >{public: static SafeIntError RegMultiply( const unsigned __int64& a, unsigned __int32 b, unsigned __int64& ret ) { unsigned __int32 aHigh, aLow;
// Consider that a*b can be broken up into: // (aHigh * 2^32 + aLow) * b // => (aHigh * b * 2^32) + (aLow * b)
aHigh = (unsigned __int32)(a >> 32); aLow = (unsigned __int32)a;
ret = 0;
if(aHigh != 0) { ret = (unsigned __int64)aHigh * (unsigned __int64)b;
unsigned __int64 tmp;
if((unsigned __int32)(ret >> 32) != 0) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
ret <<= 32; tmp = (unsigned __int64)aLow * (unsigned __int64)b; ret += tmp;
if(ret < tmp) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
return SafeIntNoError; }
ret = (unsigned __int64)aLow * (unsigned __int64)b; return SafeIntNoError; }};
template< typename E > class LargeIntRegMultiply< unsigned __int64, signed __int32, E >{public: static SafeIntError RegMultiply( const unsigned __int64& a, signed __int32 b, unsigned __int64& ret ) { if( b < 0 && a != 0 ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
return LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::RegMultiply(a, (unsigned __int32)b, ret); }};
template< typename E > class LargeIntRegMultiply< unsigned __int64, signed __int64, E >{public: static SafeIntError RegMultiply( const unsigned __int64& a, signed __int64 b, unsigned __int64& ret ) { if( b < 0 && a != 0 ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
return LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::RegMultiply(a, (unsigned __int64)b, ret); }};
template< typename E > class LargeIntRegMultiply< signed __int32, unsigned __int64, E >{public: static SafeIntError RegMultiply( signed __int32 a, const unsigned __int64& b, signed __int32& ret ) { unsigned __int32 bHigh, bLow; bool fIsNegative = false;
// Consider that a*b can be broken up into: // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow) // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)
bHigh = (unsigned __int32)(b >> 32); bLow = (unsigned __int32)b;
ret = 0;
if(bHigh != 0 && a != 0) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
if( a < 0 ) { a = -a; fIsNegative = true; }
unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow;
if( !fIsNegative ) { if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt ) { ret = (signed __int32)tmp; return SafeIntNoError; } } else { if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 ) { ret = -( (signed __int32)tmp ); return SafeIntNoError; } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename E > class LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >{public: static SafeIntError RegMultiply( unsigned __int32 a, const unsigned __int64& b, unsigned __int32& ret ) { // Consider that a*b can be broken up into: // (bHigh * 2^32 + bLow) * a // => (bHigh * a * 2^32) + (bLow * a) // In this case, the result must fit into 32-bits // If bHigh != 0 && a != 0, immediate error.
if( (unsigned __int32)(b >> 32) != 0 && a != 0 ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
unsigned __int64 tmp = b * (unsigned __int64)a;
if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
ret = (unsigned __int32)tmp; return SafeIntNoError; }};
template < typename E > class LargeIntRegMultiply< unsigned __int32, signed __int64, E >{public: static SafeIntError RegMultiply( unsigned __int32 a, const signed __int64& b, unsigned __int32& ret ) { if( b < 0 && a != 0 ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
return LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >::RegMultiply( a, (unsigned __int64)b, ret ); }};
template < typename E > class LargeIntRegMultiply< signed __int64, signed __int64, E >{public: static SafeIntError RegMultiply( const signed __int64& a, const signed __int64& b, signed __int64& ret ) { bool aNegative = false; bool bNegative = false;
unsigned __int64 tmp; __int64 a1 = a; __int64 b1 = b;
if( a1 < 0 ) { aNegative = true; a1 = -a1; }
if( b1 < 0 ) { bNegative = true; b1 = -b1; }
if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >:: RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, tmp ) == SafeIntNoError ) { // The unsigned multiplication didn't overflow if( aNegative ^ bNegative ) { // Result must be negative if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) { ret = -(signed __int64)tmp; return SafeIntNoError; } } else { // Result must be positive if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) { ret = (signed __int64)tmp; return SafeIntNoError; } } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename E > class LargeIntRegMultiply< signed __int64, unsigned __int32, E >{public: static SafeIntError RegMultiply( const signed __int64& a, unsigned __int32 b, signed __int64& ret ) { bool aNegative = false; unsigned __int64 tmp; __int64 a1 = a;
if( a1 < 0 ) { aNegative = true; a1 = -a1; }
if( LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::RegMultiply( (unsigned __int64)a1, b, tmp ) == SafeIntNoError ) { // The unsigned multiplication didn't overflow if( aNegative ) { // Result must be negative if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) { ret = -(signed __int64)tmp; return SafeIntNoError; } } else { // Result must be positive if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) { ret = (signed __int64)tmp; return SafeIntNoError; } } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename E > class LargeIntRegMultiply< signed __int64, signed __int32, E >{public: static SafeIntError RegMultiply( const signed __int64& a, signed __int32 b, signed __int64& ret ) { bool aNegative = false; bool bNegative = false;
unsigned __int64 tmp; __int64 a1 = a; __int64 b1 = b;
if( a1 < 0 ) { aNegative = true; a1 = -a1; }
if( b1 < 0 ) { bNegative = true; b1 = -b1; }
if( LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >:: RegMultiply( (unsigned __int64)a1, (unsigned __int32)b1, tmp ) == SafeIntNoError ) { // The unsigned multiplication didn't overflow if( aNegative ^ bNegative ) { // Result must be negative if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) { ret = -(signed __int64)tmp; return SafeIntNoError; } } else { // Result must be positive if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) { ret = (signed __int64)tmp; return SafeIntNoError; } } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename E > class LargeIntRegMultiply< signed __int32, signed __int64, E >{public: static SafeIntError RegMultiply( signed __int32 a, const signed __int64& b, signed __int32& ret ) { bool aNegative = false; bool bNegative = false;
unsigned __int32 tmp; __int64 b1 = b;
if( a < 0 ) { aNegative = true; a = -a; }
if( b1 < 0 ) { bNegative = true; b1 = -b1; }
if( LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >:: RegMultiply( (unsigned __int32)a, (unsigned __int64)b1, tmp ) == SafeIntNoError ) { // The unsigned multiplication didn't overflow if( aNegative ^ bNegative ) { // Result must be negative if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt ) {#pragma warning(suppress:4146) ret = -tmp; return SafeIntNoError; } } else { // Result must be positive if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt ) { ret = (signed __int32)tmp; return SafeIntNoError; } } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename E > class LargeIntRegMultiply< signed __int64, unsigned __int64, E >{public: static SafeIntError RegMultiply( const signed __int64& a, const unsigned __int64& b, signed __int64& ret ) { bool aNegative = false;
unsigned __int64 tmp; __int64 a1 = a;
if( a1 < 0 ) { aNegative = true; a1 = -a1; }
if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >:: RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, tmp ) == SafeIntNoError ) { // The unsigned multiplication didn't overflow if( aNegative ) { // Result must be negative if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) { ret = -((signed __int64)tmp); return SafeIntNoError; } } else { // Result must be positive if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) { ret = (signed __int64)tmp; return SafeIntNoError; } } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename E > class MultiplicationHelper< unsigned __int64, unsigned __int64, E, MultiplicationState_Uint64Uint64 >{public: static SafeIntError Multiply( const unsigned __int64& t, const unsigned __int64& u, unsigned __int64& ret ) { return LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::RegMultiply( t, u, ret ); }};
template < typename U, typename E > class MultiplicationHelper<unsigned __int64, U, E, MultiplicationState_Uint64Uint >{public: //U is any unsigned int 32-bit or less static SafeIntError Multiply( const unsigned __int64& t, const U& u, unsigned __int64& ret ) { return LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::RegMultiply( t, (unsigned __int32)u, ret ); }};
// converse of the previous functiontemplate < typename T, typename E > class MultiplicationHelper< T, unsigned __int64, E, MultiplicationState_UintUint64 >{public: // T is any unsigned int up to 32-bit static SafeIntError Multiply( const T& t, const unsigned __int64& u, T& ret ) { unsigned __int32 tmp;
if( LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >::RegMultiply( t, u, tmp ) == SafeIntNoError && SafeCastHelper< T, unsigned __int32, E >::Cast(tmp, ret) == SafeIntNoError ) { return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename U, typename E > class MultiplicationHelper< unsigned __int64, U, E, MultiplicationState_Uint64Int >{public: //U is any signed int, up to 64-bit static SafeIntError Multiply(const unsigned __int64& t, const U& u, unsigned __int64& ret) { return LargeIntRegMultiply< unsigned __int64, signed __int32, E >::RegMultiply(t, (signed __int32)u, ret); }};
template < typename E > class MultiplicationHelper<unsigned __int64, __int64, E, MultiplicationState_Uint64Int64 >{public: static SafeIntError Multiply(const unsigned __int64& t, const __int64& u, unsigned __int64& ret) { return LargeIntRegMultiply< unsigned __int64, __int64, E >::RegMultiply(t, u, ret); }};
template < typename T, typename E > class MultiplicationHelper< T, __int64, E, MultiplicationState_UintInt64 >{public: //T is unsigned up to 32-bit static SafeIntError Multiply( const T& t, const __int64& u, T& ret ) { unsigned __int32 tmp;
if( LargeIntRegMultiply< unsigned __int32, __int64, E >::RegMultiply( (unsigned __int32)t, u, tmp ) == SafeIntNoError && SafeCastHelper< T, unsigned __int32, E >::Cast( tmp, ret ) == SafeIntNoError ) { return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename U, typename E > class MultiplicationHelper<__int64, U, E, MultiplicationState_Int64Uint >{public: //U is unsigned up to 32-bit static SafeIntError Multiply( const __int64& t, const U& u, __int64& ret ) { return LargeIntRegMultiply< __int64, unsigned __int32, E >::RegMultiply( t, (unsigned __int32)u, ret ); }};
template < typename E > class MultiplicationHelper<__int64, __int64, E, MultiplicationState_Int64Int64 >{public: static SafeIntError Multiply( const __int64& t, const __int64& u, __int64& ret ) { return LargeIntRegMultiply< __int64, __int64, E >::RegMultiply( t, u, ret ); }};
template < typename U, typename E > class MultiplicationHelper<__int64, U, E, MultiplicationState_Int64Int>{public: //U is signed up to 32-bit static SafeIntError Multiply( const __int64& t, U u, __int64& ret ) { return LargeIntRegMultiply< __int64, __int32, E >::RegMultiply( t, (__int32)u, ret ); }};
template < typename T, typename E > class MultiplicationHelper< T, unsigned __int64, E, MultiplicationState_IntUint64 >{public: //T is signed up to 32-bit static SafeIntError Multiply(T t, const unsigned __int64& u, T& ret) { __int32 tmp;
if( LargeIntRegMultiply< __int32, unsigned __int64, E >::RegMultiply( (__int32)t, u, tmp ) == SafeIntNoError && SafeCastHelper< T, __int32, E >::Cast( tmp, ret ) == SafeIntNoError ) { return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename E > class MultiplicationHelper<__int64, unsigned __int64, E, MultiplicationState_Int64Uint64>{public: //U is signed up to 32-bit static SafeIntError Multiply( const __int64& t, const unsigned __int64& u, __int64& ret ) { return LargeIntRegMultiply< __int64, unsigned __int64, E >::RegMultiply( t, u, ret ); }};
template < typename T, typename E > class MultiplicationHelper< T, __int64, E, MultiplicationState_IntInt64>{public: //T is signed, up to 32-bit static SafeIntError Multiply( T t, const __int64& u, T& ret ) { __int32 tmp;
if( LargeIntRegMultiply< __int32, __int64, E >::RegMultiply( (__int32)t, u, tmp ) == SafeIntNoError && SafeCastHelper< T, __int32, E >::Cast( tmp, ret ) == SafeIntNoError ) { return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
enum DivisionState{ DivisionState_OK, DivisionState_UnsignedSigned, DivisionState_SignedUnsigned32, DivisionState_SignedUnsigned64, DivisionState_SignedUnsigned, DivisionState_SignedSigned};
template < typename T, typename U > class DivisionMethod{public: enum { method = (SafeIntCompare< T, U >::isBothUnsigned ? DivisionState_OK : (!IntTraits< T >::isSigned && IntTraits< U >::isSigned) ? DivisionState_UnsignedSigned : (IntTraits< T >::isSigned && IntTraits< U >::isUint32 && IntTraits< T >::isLT64Bit) ? DivisionState_SignedUnsigned32 : (IntTraits< T >::isSigned && IntTraits< U >::isUint64) ? DivisionState_SignedUnsigned64 : (IntTraits< T >::isSigned && !IntTraits< U >::isSigned) ? DivisionState_SignedUnsigned : DivisionState_SignedSigned) };};
template < typename T, typename U, typename E, int Method = DivisionMethod< T, U >::method > class DivisionHelper;
template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_OK >{public: static SafeIntError Divide( const T& t, const U& u, T& result ) { if( u == 0 ) { E::SafeIntOnDivZero(); return SafeIntDivideByZero; }
result = (T)( t/u ); return SafeIntNoError; }};
template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_UnsignedSigned>{public: static SafeIntError Divide( const T& t, const U& u, T& result ) { if( u > 0 ) { result = (T)( t/u ); return SafeIntNoError; }
if( u == 0 ) { E::SafeIntOnDivZero(); return SafeIntDivideByZero; }
// it is always an error to try and divide an unsigned number by a negative signed number // unless u is bigger than t if( AbsValueHelper< U >::Abs( u ) > t ) { result = 0; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedUnsigned32 >{public: static SafeIntError Divide( const T& t, const U& u, T& result ) { if( u == 0 ) { E::SafeIntOnDivZero(); return SafeIntDivideByZero; }
// Test for t > 0 // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional if( t > 0 ) result = (T)( t/u ); else result = (T)( (__int64)t/(__int64)u );
return SafeIntNoError; }};
template < typename T, typename E > class DivisionHelper< T, unsigned __int64, E, DivisionState_SignedUnsigned64 >{public: static SafeIntError Divide( const T& t, const unsigned __int64& u, T& result ) { if( u == 0 ) { E::SafeIntOnDivZero(); return SafeIntDivideByZero; }
if( u <= (unsigned __int64)IntTraits< T >::maxInt ) { // Else u can safely be cast to T#pragma warning(suppress:4127) if( sizeof( T ) < sizeof( __int64 ) ) result = (T)( (int)t/(int)u ); else result = (T)((__int64)t/(__int64)u); } else // Corner case if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt ) { // Min int divided by its own magnitude is -1 result = -1; } else { result = 0; } return SafeIntNoError; }};
template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedUnsigned>{public: // T is any signed, U is unsigned and smaller than 32-bit // In this case, standard operator casting is correct static SafeIntError Divide( const T& t, const U& u, T& result ) { if( u == 0 ) { E::SafeIntOnDivZero(); return SafeIntDivideByZero; }
result = (T)( t/u ); return SafeIntNoError; }};
template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedSigned>{public: static SafeIntError Divide( const T& t, const U& u, T& result ) { if( u == 0 ) { E::SafeIntOnDivZero(); return SafeIntDivideByZero; }
// Must test for corner case if( t == IntTraits< T >::minInt && u == -1 ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
result = (T)( t/u ); return SafeIntNoError; }};
enum AdditionState{ AdditionState_CastIntCheckMax, AdditionState_CastUintCheckOverflow, AdditionState_CastUintCheckOverflowMax, AdditionState_CastUint64CheckOverflow, AdditionState_CastUint64CheckOverflowMax, AdditionState_CastIntCheckMinMax, AdditionState_CastInt64CheckMinMax, AdditionState_CastInt64CheckMax, AdditionState_CastUint64CheckMinMax, AdditionState_CastUint64CheckMinMax2, AdditionState_CastInt64CheckOverflow, AdditionState_CastInt64CheckOverflowMinMax, AdditionState_CastInt64CheckOverflowMax, AdditionState_ManualCheckInt64Uint64, AdditionState_ManualCheck, AdditionState_Error};
template< typename T, typename U >class AdditionMethod{public: enum { //unsigned-unsigned method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? AdditionState_CastIntCheckMax : (IntRegion< T,U >::IntZone_Uint32_UintLT64) ? AdditionState_CastUintCheckOverflow : (IntRegion< T,U >::IntZone_UintLT32_Uint32) ? AdditionState_CastUintCheckOverflowMax : (IntRegion< T,U >::IntZone_Uint64_Uint) ? AdditionState_CastUint64CheckOverflow : (IntRegion< T,U >::IntZone_UintLT64_Uint64) ? AdditionState_CastUint64CheckOverflowMax : //unsigned-signed (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? AdditionState_CastIntCheckMinMax : (IntRegion< T,U >::IntZone_Uint32_IntLT64 || IntRegion< T,U >::IntZone_UintLT32_Int32) ? AdditionState_CastInt64CheckMinMax : (IntRegion< T,U >::IntZone_Uint64_Int || IntRegion< T,U >::IntZone_Uint64_Int64) ? AdditionState_CastUint64CheckMinMax : (IntRegion< T,U >::IntZone_UintLT64_Int64) ? AdditionState_CastUint64CheckMinMax2 : //signed-signed (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? AdditionState_CastIntCheckMinMax : (IntRegion< T,U >::IntZone_Int32_IntLT64 || IntRegion< T,U >::IntZone_IntLT32_Int32) ? AdditionState_CastInt64CheckMinMax : (IntRegion< T,U >::IntZone_Int64_Int || IntRegion< T,U >::IntZone_Int64_Int64) ? AdditionState_CastInt64CheckOverflow : (IntRegion< T,U >::IntZone_IntLT64_Int64) ? AdditionState_CastInt64CheckOverflowMinMax : //signed-unsigned (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? AdditionState_CastIntCheckMax : (IntRegion< T,U >::IntZone_Int32_UintLT32 || IntRegion< T,U >::IntZone_IntLT64_Uint32) ? AdditionState_CastInt64CheckMax : (IntRegion< T,U >::IntZone_Int64_UintLT64) ? AdditionState_CastInt64CheckOverflowMax : (IntRegion< T,U >::IntZone_Int64_Uint64) ? AdditionState_ManualCheckInt64Uint64 : (IntRegion< T,U >::IntZone_Int_Uint64) ? AdditionState_ManualCheck : AdditionState_Error) };};
template < typename T, typename U, typename E, int Method = AdditionMethod< T, U >::method > class AdditionHelper;
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastIntCheckMax >{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { //16-bit or less unsigned addition __int32 tmp = lhs + rhs;
if( tmp <= (__int32)IntTraits< T >::maxInt ) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUintCheckOverflow >{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { // 32-bit or less - both are unsigned unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;
//we added didn't get smaller if( tmp >= lhs ) { result = (T)tmp; return SafeIntNoError; } E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUintCheckOverflowMax>{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { // 32-bit or less - both are unsigned unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;
// We added and it didn't get smaller or exceed maxInt if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return SafeIntNoError; } E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckOverflow>{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { // lhs unsigned __int64, rhs unsigned unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
// We added and it didn't get smaller if(tmp >= lhs) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckOverflowMax >{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { //lhs unsigned __int64, rhs unsigned unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
// We added and it didn't get smaller if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastIntCheckMinMax >{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { // 16-bit or less - one or both are signed __int32 tmp = lhs + rhs;
if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt ) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
#pragma warning(push)#pragma warning(disable:4702)template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckMinMax >{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { // 32-bit or less - one or both are signed __int64 tmp = (__int64)lhs + (__int64)rhs;
if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt ) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; // return E::SafeIntOnOverflow2(); }};#pragma warning(pop)
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckMax >{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { // 32-bit or less - lhs signed, rhs unsigned __int64 tmp = (__int64)lhs + (__int64)rhs;
if( tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckMinMax >{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { // lhs is unsigned __int64, rhs signed unsigned __int64 tmp;
if( rhs < 0 ) { // So we're effectively subtracting tmp = AbsValueHelper< U >::Abs( rhs );
if( tmp <= lhs ) { result = lhs - tmp; return SafeIntNoError; } } else { // now we know that rhs can be safely cast into an unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
// We added and it did not become smaller if( tmp >= lhs ) { result = (T)tmp; return SafeIntNoError; } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckMinMax2>{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { // lhs is unsigned and < 64-bit, rhs signed __int64 if( rhs < 0 ) { if( lhs >= (unsigned __int64)( -rhs ) )//negation is safe, since rhs is 64-bit { result = (T)( lhs + rhs ); return SafeIntNoError; } } else { // now we know that rhs can be safely cast into an unsigned __int64 unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
// special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff // it is not possible for the operation above to overflow, so just check max if( tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return SafeIntNoError; } } E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflow>{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { // lhs is signed __int64, rhs signed __int64 tmp = (__int64)lhs + (__int64)rhs;
if( lhs >= 0 ) { // mixed sign cannot overflow if( rhs >= 0 && tmp < lhs ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; } } else { // lhs negative if( rhs < 0 && tmp > lhs ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; } }
result = (T)tmp; return SafeIntNoError; }};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflowMinMax>{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { //rhs is signed __int64, lhs signed __int64 tmp;
if( AdditionHelper< __int64, __int64, E, AdditionState_CastInt64CheckOverflow >:: Addition( (__int64)lhs, (__int64)rhs, tmp ) == SafeIntNoError && tmp <= IntTraits< T >::maxInt && tmp >= IntTraits< T >::minInt ) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflowMax >{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { //lhs is signed __int64, rhs unsigned < 64-bit __int64 tmp = lhs + (__int64)rhs;
if( tmp >= lhs ) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename E > class AdditionHelper < __int64, unsigned __int64, E, AdditionState_ManualCheckInt64Uint64 >{public: static SafeIntError Addition( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) { // rhs is unsigned __int64, lhs __int64 __int64 tmp = lhs + (__int64)rhs;
if( tmp >= lhs ) { result = tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_ManualCheck >{public: static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) { // rhs is unsigned __int64, lhs signed, 32-bit or less
if( (unsigned __int32)( rhs >> 32 ) == 0 ) { // Now it just happens to work out that the standard behavior does what we want // Adding explicit casts to show exactly what's happening here __int32 tmp = (__int32)( (unsigned __int32)rhs + (unsigned __int32)lhs );
if( tmp >= lhs && SafeCastHelper< T, __int32, E >::Cast( tmp, result ) == SafeIntNoError ) return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
enum SubtractionState{ SubtractionState_BothUnsigned, SubtractionState_CastIntCheckMinMax, SubtractionState_CastIntCheckMin, SubtractionState_CastInt64CheckMinMax, SubtractionState_CastInt64CheckMin, SubtractionState_Uint64Int, SubtractionState_UintInt64, SubtractionState_Int64Int, SubtractionState_IntInt64, SubtractionState_Int64Uint, SubtractionState_IntUint64, SubtractionState_Int64Uint64, // states for SubtractionMethod2 SubtractionState_BothUnsigned2, SubtractionState_CastIntCheckMinMax2, SubtractionState_CastInt64CheckMinMax2, SubtractionState_Uint64Int2, SubtractionState_UintInt642, SubtractionState_Int64Int2, SubtractionState_IntInt642, SubtractionState_Int64Uint2, SubtractionState_IntUint642, SubtractionState_Int64Uint642, SubtractionState_Error};
template < typename T, typename U > class SubtractionMethod{public: enum { // unsigned-unsigned method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 || (IntRegion< T,U >::IntZone_Uint32_UintLT64) || (IntRegion< T,U >::IntZone_UintLT32_Uint32) || (IntRegion< T,U >::IntZone_Uint64_Uint) || (IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned : // unsigned-signed (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax : (IntRegion< T,U >::IntZone_Uint32_IntLT64 || IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckMinMax : (IntRegion< T,U >::IntZone_Uint64_Int || IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int : (IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt64 : // signed-signed (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax : (IntRegion< T,U >::IntZone_Int32_IntLT64 || IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckMinMax : (IntRegion< T,U >::IntZone_Int64_Int || IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int : (IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt64 : // signed-unsigned (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckMin : (IntRegion< T,U >::IntZone_Int32_UintLT32 || IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckMin : (IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint : (IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint64 : (IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint64 : SubtractionState_Error) };};
// this is for the case of U - SafeInt< T, E >template < typename T, typename U > class SubtractionMethod2{public: enum { // unsigned-unsigned method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 || (IntRegion< T,U >::IntZone_Uint32_UintLT64) || (IntRegion< T,U >::IntZone_UintLT32_Uint32) || (IntRegion< T,U >::IntZone_Uint64_Uint) || (IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned2 : // unsigned-signed (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax2 : (IntRegion< T,U >::IntZone_Uint32_IntLT64 || IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckMinMax2 : (IntRegion< T,U >::IntZone_Uint64_Int || IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int2 : (IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt642 : // signed-signed (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax2 : (IntRegion< T,U >::IntZone_Int32_IntLT64 || IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckMinMax2 : (IntRegion< T,U >::IntZone_Int64_Int || IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int2 : (IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt642 : // signed-unsigned (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckMinMax2 : (IntRegion< T,U >::IntZone_Int32_UintLT32 || IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckMinMax2 : (IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint2 : (IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint642 : (IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint642 : SubtractionState_Error) };};
template < typename T, typename U, typename E, int Method = SubtractionMethod< T, U >::method > class SubtractionHelper;
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_BothUnsigned >{public: static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) { // both are unsigned - easy case if( rhs <= lhs ) { result = (T)( lhs - rhs ); return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_BothUnsigned2 >{public: static SafeIntError Subtract( const T& lhs, const U& rhs, U& result ) { // both are unsigned - easy case // Except we do have to check for overflow - lhs could be larger than result can hold if( rhs <= lhs ) { T tmp = (T)(lhs - rhs); return SafeCastHelper< U, T, E>::Cast( tmp, result); }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastIntCheckMinMax >{public: static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) { // both values are 16-bit or less // rhs is signed, so could end up increasing or decreasing __int32 tmp = lhs - rhs;
if( SafeCastHelper< T, __int32, E >::Cast( tmp, result ) == SafeIntNoError ) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_CastIntCheckMinMax2 >{public: static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) { // both values are 16-bit or less // rhs is signed, so could end up increasing or decreasing __int32 tmp = lhs - rhs;
return SafeCastHelper< T, __int32, E >::Cast( tmp, result ); }};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastIntCheckMin >{public: static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) { // both values are 16-bit or less // rhs is unsigned - check only minimum __int32 tmp = lhs - rhs;
if( tmp >= (__int32)IntTraits< T >::minInt ) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastInt64CheckMinMax >{public: static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) { // both values are 32-bit or less // rhs is signed, so could end up increasing or decreasing __int64 tmp = (__int64)lhs - (__int64)rhs;
return SafeCastHelper< T, __int64, E >::Cast( tmp, result ); }};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_CastInt64CheckMinMax2 >{public: static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) { // both values are 32-bit or less // rhs is signed, so could end up increasing or decreasing __int64 tmp = (__int64)lhs - (__int64)rhs;
return SafeCastHelper< T, __int64, E >::Cast( tmp, result ); }};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastInt64CheckMin >{public: static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) { // both values are 32-bit or less // rhs is unsigned - check only minimum __int64 tmp = (__int64)lhs - (__int64)rhs;
if( tmp >= (__int64)IntTraits< T >::minInt ) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Uint64Int >{public: static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) { // lhs is an unsigned __int64, rhs signed // must first see if rhs is positive or negative if( rhs >= 0 ) { if( (unsigned __int64)rhs <= lhs ) { result = (T)( lhs - (unsigned __int64)rhs ); return SafeIntNoError; } } else { // we're now effectively adding T tmp = lhs + AbsValueHelper< U >::Abs( rhs );
if(tmp >= lhs) { result = tmp; return SafeIntNoError; } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Uint64Int2 >{public: static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) { // U is unsigned __int64, T is signed if( rhs < 0 ) { // treat this as addition unsigned __int64 tmp;
tmp = lhs + (unsigned __int64)AbsValueHelper< T >::Abs( rhs );
// must check for addition overflow and max if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return SafeIntNoError; } } else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works { // result is negative // implies that lhs must fit into T, and result cannot overflow // Also allows us to drop to 32-bit math, which is faster on a 32-bit system result = (T)lhs - (T)rhs; return SafeIntNoError; } else { // result is positive unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;
if( tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return SafeIntNoError; } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_UintInt64 >{public: static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) { // lhs is an unsigned int32 or smaller, rhs signed __int64 // must first see if rhs is positive or negative if( rhs >= 0 ) { if( (unsigned __int64)rhs <= lhs ) { result = (T)( lhs - (T)rhs ); return SafeIntNoError; } } else { // we're now effectively adding // since lhs is 32-bit, and rhs cannot exceed 2^63 // this addition cannot overflow unsigned __int64 tmp = lhs + (unsigned __int64)( -rhs ); // negation safe
// but we could exceed MaxInt if(tmp <= IntTraits< T >::maxInt) { result = (T)tmp; return SafeIntNoError; } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_UintInt642 >{public: static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) { // U unsigned 32-bit or less, T __int64 if( rhs >= 0 ) { // overflow not possible result = (T)( (__int64)lhs - rhs ); return SafeIntNoError; } else { // we effectively have an addition // which cannot overflow internally unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs );
if( tmp <= (unsigned __int64)IntTraits< T >::maxInt ) { result = (T)tmp; return SafeIntNoError; } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Int64Int >{public: static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) { // lhs is an __int64, rhs signed (up to 64-bit) // we have essentially 4 cases: // // 1) lhs positive, rhs positive - overflow not possible // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error // 3) lhs negative, rhs positive - check result <= lhs // 4) lhs negative, rhs negative - overflow not possible
__int64 tmp = lhs - rhs;
// Note - ideally, we can order these so that true conditionals // lead to success, which enables better pipelining // It isn't practical here if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2 ( rhs >= 0 && tmp > lhs ) ) // condition 3 { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }
result = (T)tmp; return SafeIntNoError; }};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Int64Int2 >{public: static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) { // lhs __int64, rhs any signed int (including __int64) __int64 tmp = lhs - rhs;
// we have essentially 4 cases: // // 1) lhs positive, rhs positive - overflow not possible in tmp // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error // 3) lhs negative, rhs positive - check result <= lhs // 4) lhs negative, rhs negative - overflow not possible in tmp
if( lhs >= 0 ) { // if both positive, overflow to negative not possible // which is why we'll explicitly check maxInt, and not call SafeCast#pragma warning(suppress:4127) if( ( IntTraits< T >::isLT64Bit && tmp > IntTraits< T >::maxInt ) || ( rhs < 0 && tmp < lhs ) ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; } } else { // lhs negative#pragma warning(suppress:4127) if( ( IntTraits< T >::isLT64Bit && tmp < IntTraits< T >::minInt) || ( rhs >=0 && tmp > lhs ) ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; } }
result = (T)tmp; return SafeIntNoError; }};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_IntInt64 >{public: static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) { // lhs is a 32-bit int or less, rhs __int64 // we have essentially 4 cases: // // lhs positive, rhs positive - rhs could be larger than lhs can represent // lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int // lhs negative, rhs positive - check tmp <= lhs and tmp < min int // lhs negative, rhs negative - addition cannot internally overflow, check against max
__int64 tmp = (__int64)lhs - rhs;
if( lhs >= 0 ) { // first case if( rhs >= 0 ) { if( tmp >= IntTraits< T >::minInt ) { result = (T)tmp; return SafeIntNoError; } } else { // second case if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return SafeIntNoError; } } } else { // lhs < 0 // third case if( rhs >= 0 ) { if( tmp <= lhs && tmp >= IntTraits< T >::minInt ) { result = (T)tmp; return SafeIntNoError; } } else { // fourth case if( tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return SafeIntNoError; } } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_IntInt642 >{public: static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) { // lhs is any signed int32 or smaller, rhs is int64 __int64 tmp = (__int64)lhs - rhs;
if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || ( rhs > 0 && tmp > lhs ) ) { E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; //else OK }
result = (T)tmp; return SafeIntNoError; }};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Int64Uint >{public: static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) { // lhs is a 64-bit int, rhs unsigned int32 or smaller
__int64 tmp = lhs - (__int64)rhs;
if( tmp <= lhs ) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Int64Uint2 >{public: // lhs is __int64, rhs is unsigned 32-bit or smaller static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) { __int64 tmp = lhs - (__int64)rhs;
if( tmp <= IntTraits< T >::maxInt && tmp >= IntTraits< T >::minInt ) { result = (T)tmp; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_IntUint64 >{public: static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) { // lhs is any signed int, rhs unsigned int64 // check against available range
// We need the absolute value of IntTraits< T >::minInt // This will give it to us without extraneous compiler warnings const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1;
if( lhs < 0 ) { if( rhs <= AbsMinIntT - AbsValueHelper< T >::Abs( lhs ) ) { result = (T)( lhs - rhs ); return SafeIntNoError; } } else { if( rhs <= AbsMinIntT + (unsigned __int64)lhs ) { result = (T)( lhs - rhs ); return SafeIntNoError; } }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_IntUint642 >{public: static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) { // We run into upcasting problems on comparison - needs 2 checks if( lhs >= 0 && (T)lhs >= rhs ) { result = (T)((U)lhs - (U)rhs); return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename E > class SubtractionHelper< __int64, unsigned __int64, E, SubtractionState_Int64Uint64 >{public: static SafeIntError Subtract( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) { // if we subtract, and it gets larger, there's a problem __int64 tmp = lhs - (__int64)rhs;
if( tmp <= lhs ) { result = tmp; return SafeIntNoError; } E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
template < typename E > class SubtractionHelper< __int64, unsigned __int64, E, SubtractionState_Int64Uint642 >{public: // If lhs is negative, immediate problem - return must be positive, and subtracting only makes it // get smaller. If rhs > lhs, then it would also go negative, which is the other case static SafeIntError Subtract( const __int64& lhs, const unsigned __int64& rhs, unsigned __int64& result ) { if( lhs >= 0 && (unsigned __int64)lhs >= rhs ) { result = (unsigned __int64)lhs - rhs; return SafeIntNoError; }
E::SafeIntOnOverflow(); return SafeIntArithmeticOverflow; }};
enum BinaryState{ BinaryState_OK, BinaryState_Int8, BinaryState_Int16, BinaryState_Int32};
template < typename T, typename U > class BinaryMethod{public: enum { // If both operands are unsigned OR // return type is smaller than rhs OR // return type is larger and rhs is unsigned // Then binary operations won't produce unexpected results method = ( sizeof( T ) <= sizeof( U ) || SafeIntCompare< T, U >::isBothUnsigned || !IntTraits< U >::isSigned ) ? BinaryState_OK : IntTraits< U >::isInt8 ? BinaryState_Int8 : IntTraits< U >::isInt16 ? BinaryState_Int16 : BinaryState_Int32 };};
template < typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryAndHelper;
template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_OK >{public: static T And( T lhs, U rhs ){ return (T)( lhs & rhs ); }};
template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int8 >{public: static T And( T lhs, U rhs ) { // cast forces sign extension to be zeros _SAFEINT_BINARY_ASSERT( ( lhs & rhs ) == ( lhs & (unsigned __int8)rhs ) ); return (T)( lhs & (unsigned __int8)rhs ); }};
template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int16 >{public: static T And( T lhs, U rhs ) { //cast forces sign extension to be zeros _SAFEINT_BINARY_ASSERT( ( lhs & rhs ) == ( lhs & (unsigned __int16)rhs ) ); return (T)( lhs & (unsigned __int16)rhs ); }};
template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int32 >{public: static T And( T lhs, U rhs ) { //cast forces sign extension to be zeros _SAFEINT_BINARY_ASSERT( ( lhs & rhs ) == ( lhs & (unsigned __int32)rhs ) ); return (T)( lhs & (unsigned __int32)rhs ); }};
template < typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryOrHelper;
template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_OK >{public: static T Or( T lhs, U rhs ){ return (T)( lhs | rhs ); }};
template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int8 >{public: static T Or( T lhs, U rhs ) { //cast forces sign extension to be zeros _SAFEINT_BINARY_ASSERT( ( lhs | rhs ) == ( lhs | (unsigned __int8)rhs ) ); return (T)( lhs | (unsigned __int8)rhs ); }};
template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int16 >{public: static T Or( T lhs, U rhs ) { //cast forces sign extension to be zeros _SAFEINT_BINARY_ASSERT( ( lhs | rhs ) == ( lhs | (unsigned __int16)rhs ) ); return (T)( lhs | (unsigned __int16)rhs ); }};
template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int32 >{public: static T Or( T lhs, U rhs ) { //cast forces sign extension to be zeros _SAFEINT_BINARY_ASSERT( ( lhs | rhs ) == ( lhs | (unsigned __int32)rhs ) ); return (T)( lhs | (unsigned __int32)rhs ); }};
template <typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryXorHelper;
template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_OK >{public: static T Xor( T lhs, U rhs ){ return (T)( lhs ^ rhs ); }};
template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int8 >{public: static T Xor( T lhs, U rhs ) { // cast forces sign extension to be zeros _SAFEINT_BINARY_ASSERT( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int8)rhs ) ); return (T)( lhs ^ (unsigned __int8)rhs ); }};
template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int16 >{public: static T Xor( T lhs, U rhs ) { // cast forces sign extension to be zeros _SAFEINT_BINARY_ASSERT( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int16)rhs ) ); return (T)( lhs ^ (unsigned __int16)rhs ); }};
template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int32 >{public: static T Xor( T lhs, U rhs ) { // cast forces sign extension to be zeros _SAFEINT_BINARY_ASSERT( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int32)rhs ) ); return (T)( lhs ^ (unsigned __int32)rhs ); }};
#pragma warning(pop)} // namespace details
} // namespace utilities
} // namespace msl
#pragma pack(pop)