[main]    [up]  

WxExtLib - safecast.h

00001: // -*- c++ -*-
00002: 
00003: //-------------------------------------------------------------------------
00004: // Author: Daniel Käps, created 2004. Extended 2005, 2006.
00005: // This file is public domain.
00006: //-------------------------------------------------------------------------
00007: 
00008: #ifndef _INCLUDED_safecast_h  
00009: #define _INCLUDED_safecast_h  
00010: 
00011: //-------------------------------------------------------------------------
00012: // typesafer casts
00013: //
00014: // Idea:
00015: // - centralize cast operators in functions, avoid
00016: //   using C casts (or reinterpret_cast<>) directly 
00017: //   in the rest of the code
00018: // - provide overloads if necessary for required parameter types
00019: //   (the right overloaded function should be selected automatically
00020: //   by the compiler if available, if not, the compiler should give
00021: //   an error) - a change of a parameter by the calling code to a greater 
00022: //   value range should be detected
00023: // - note that since the C++ overload mechanism only considers parameters
00024: //   (not the function's return value), a (polymorph) return value must 
00025: //   be returned using a non-const parameter reference (or maybe pointer) 
00026: //   (cf. e.g. cast_approx_assign(), cast_ptr_from_voidptr())
00027: // - the purpose of using the cast is made explicit by the cast-function
00028: //   name (e.g. cast_round_assign(), cast_approx_assign()), which
00029: //   may improve readability of code using casts
00030: //
00031: // Notes:
00032: // - use of overloading mechanism makes these functions different from
00033: //   static_cast<>, const_cast<> (which also provide more safety than
00034: //   C-style casts) in that the right cast is choosen by overload 
00035: //   resolution, instead of having to specify desired output type 
00036: //   explicitly
00037: // - these functions are supposed to work on older compilers which have
00038: //   no support for reinterpret_cast<>, static_cast<>
00039: // - this is experimental
00040: //
00041: //-------------------------------------------------------------------------
00042: 
00043: // WARN maybe should return equality==false if signed value is lower than zero
00044: inline bool cast_is_equal(unsigned int LeftUInt, int RightInt)
00045: {
00046:     return LeftUInt == (unsigned int) RightInt;
00047: }
00048: 
00049: inline bool cast_is_equal(int LeftInt, unsigned int RightUInt)
00050: {
00051:     return ((unsigned int) LeftInt) == RightUInt;
00052: }
00053: 
00054: inline bool cast_is_not_equal(unsigned int LeftUInt, int RightInt)
00055: {
00056:     return LeftUInt != (unsigned int) RightInt;
00057: }
00058: 
00059: inline bool cast_is_not_equal(int LeftInt, unsigned int RightUInt)
00060: {
00061:     return ((unsigned int) LeftInt) != RightUInt;
00062: }
00063: 
00064: inline bool cast_is_smaller(int LeftInt, unsigned int RightUInt)
00065: {
00066:     return ((unsigned int) LeftInt) < RightUInt;
00067: }
00068: 
00069: inline bool cast_is_equal_smaller(int LeftInt, unsigned int RightUInt)
00070: {
00071:     return ((unsigned int) LeftInt) <= RightUInt;
00072: }
00073: 
00074: inline bool cast_is_greater(unsigned int LeftUInt, int RightInt)
00075: {
00076:     return LeftUInt > (unsigned int) RightInt;
00077: }
00078: 
00079: inline bool cast_is_equal_greater(unsigned int LeftUInt, int RightInt)
00080: {
00081:     return LeftUInt >= (unsigned int) RightInt;
00082: }
00083: 
00084: //-------------------------------------------------------------------------
00085: 
00086: // casts with purpose of rounding to some integer value
00087: // - actually, this is more truncation/clip (e.g. 4.6 is 
00088: //   rounded down to 4)
00089: inline void  cast_round_assign (int & Int, double Double)
00090: {
00091:     Int = (int) Double;
00092: }
00093: 
00094: // cast with purpose to extract some character contained in an
00095: // 'int'-type value (as returned by fgetc(), toupper() etc.) to 
00096: // a variable of type 'char'
00097: inline void  cast_char_assign (char & Char, int Int)
00098: {
00099:     // WARN: correct conversion for e.g. character contained in
00100:     //   integer value?
00101:     // TODO: check if conversion works with different settings
00102:     //   for signedness of char-type, different char-conversion
00103:     //   options of compilers
00104:     // - Char = (char) Int;
00105:     // - Char = (unsigned char) Int;
00106:     //
00107:     // TODO: handle errors (e.g. Int==-1 which indicates an error)
00108:     //   condition
00109:     //
00110:     Char = (unsigned char) (((unsigned int) Int) & 0xff);
00111: }
00112: 
00113: //-------------------------------------------------------------------------
00114: 
00115: // safe, loseless conversion from types to int:
00116: inline int cast_extend_to_int(bool Bool)
00117: {
00118:     return (int) Bool;
00119: }
00120: 
00121: inline int cast_extend_to_int(signed char Char)
00122: {
00123:     return (int) Char;
00124: }
00125: 
00126: inline int cast_extend_to_int(unsigned char Char)
00127: {
00128:     return (int) Char;
00129: }
00130: 
00131: //-------------------------------------------------------------------------
00132: 
00133: #ifdef M_SafeCast_IsUseStxInt64
00134: 
00135: // purpose: type conversions which may lead to inaccuracies
00136: // caused by representation/resolution limitations
00137: inline void  cast_approx_assign (double & Double, stxInt64 Int64)
00138: {
00139:     Double = (double) Int64;
00140: }
00141: 
00142: #endif
00143: 
00144: //-------------------------------------------------------------------------
00145: 
00146: // cast_enum() is used to avoid overload ambiguity error related to 'enum'
00147: // type with some compilers
00148: inline int cast_enum(int Int)
00149: {
00150:     return Int;
00151: }
00152: 
00153: //-------------------------------------------------------------------------
00154: 
00155: // declare and implement signedness casts for (char)
00156:     #define M_Type char
00157:     #define M_SafecastSignedness_IsAddConstOverloads 0
00158:     #define M_SafecastSignedness_IsUseDefaultSignedness 1
00159:     #include "safecast_signedness.h"
00160:     #undef M_SafecastSignedness_IsAddConstOverloads
00161:     #undef M_SafecastSignedness_IsUseDefaultSignedness
00162:     #undef M_Type
00163: 
00164: // declare and implement signedness casts for (char *)
00165:     #define M_Type char *
00166:     #define M_SafecastSignedness_IsAddConstOverloads 1
00167:     #define M_SafecastSignedness_IsUseDefaultSignedness 1
00168:     #include "safecast_signedness.h"
00169:     #undef M_SafecastSignedness_IsAddConstOverloads
00170:     #undef M_SafecastSignedness_IsUseDefaultSignedness
00171:     #undef M_Type
00172: 
00173: // declare and implement signedness casts for (int)
00174:     #define M_Type int
00175:     #define M_SafecastSignedness_IsAddConstOverloads 0
00176:     #define M_SafecastSignedness_IsUseDefaultSignedness 0
00177:     #include "safecast_signedness.h"
00178:     #undef M_SafecastSignedness_IsAddConstOverloads
00179:     #undef M_SafecastSignedness_IsUseDefaultSignedness
00180:     #undef M_Type
00181: 
00182: // declare and implement signedness casts for (int *)
00183:     #define M_Type int *
00184:     #define M_SafecastSignedness_IsAddConstOverloads 1
00185:     #define M_SafecastSignedness_IsUseDefaultSignedness 0
00186:     #include "safecast_signedness.h"
00187:     #undef M_SafecastSignedness_IsAddConstOverloads
00188:     #undef M_SafecastSignedness_IsUseDefaultSignedness
00189:     #undef M_Type
00190: 
00191: //=========================================================================
00192: 
00193: // (void)-pointer to pointer-to-type conversions
00194: //
00195: // - this group is similar to static_cast<>(), but uses 
00196: //   overloading mechanism to automatically choose the right
00197: //   conversion (unlike static_cast<>(), where this needs to
00198: //   be specified as "template" argument additionally)
00199: // - it is somewhat less safe than static_cast<> because the
00200: //   the VoidPtr argument will convert from any pointer
00201: // - unlike static_cast, however, it is restricted to the
00202: //   builtin-types here (but additional overloads may be added
00203: //   anywhere as required)
00204: 
00205: inline void cast_ptr_assign(bool * & BoolPtr, void * VoidPtr)
00206: {
00207:     BoolPtr = (bool *) VoidPtr;
00208: }
00209: inline void cast_ptr_assign(char * & CharPtr, void * VoidPtr)
00210: {
00211:     CharPtr = (char *) VoidPtr;
00212: }
00213: inline void cast_ptr_assign(signed char * & UCharPtr, void * VoidPtr)
00214: {
00215:     UCharPtr = (signed char *) VoidPtr;
00216: }
00217: inline void cast_ptr_assign(unsigned char * & UCharPtr, void * VoidPtr)
00218: {
00219:     UCharPtr = (unsigned char *) VoidPtr;
00220: }
00221: inline void cast_ptr_assign(short * & ShortPtr, void * VoidPtr)
00222: {
00223:     ShortPtr = (short *) VoidPtr;
00224: }
00225: inline void cast_ptr_assign(unsigned short * & UShortPtr, void * VoidPtr)
00226: {
00227:     UShortPtr = (unsigned short *) VoidPtr;
00228: }
00229: inline void cast_ptr_assign(int * & IntPtr, void * VoidPtr)
00230: {
00231:     IntPtr = (int *) VoidPtr;
00232: }
00233: inline void cast_ptr_assign(unsigned int * & UIntPtr, void * VoidPtr)
00234: {
00235:     UIntPtr = (unsigned int *) VoidPtr;
00236: }
00237: inline void cast_ptr_assign(long * & LongPtr, void * VoidPtr)
00238: {
00239:     LongPtr = (long *) VoidPtr;
00240: }
00241: inline void cast_ptr_assign(unsigned long * & ULongPtr, void * VoidPtr)
00242: {
00243:     ULongPtr = (unsigned long *) VoidPtr;
00244: }
00245: inline void cast_ptr_assign(float * & FloatPtr, void * VoidPtr)
00246: {
00247:     FloatPtr = (float *) VoidPtr;
00248: }
00249: inline void cast_ptr_assign(double * & DoublePtr, void * VoidPtr)
00250: {
00251:     DoublePtr = (double *) VoidPtr;
00252: }
00253: 
00254: //-------------------------------------------------------------------------
00255: 
00256: inline void cast_ptr_assign(const bool * & BoolPtr, const void * VoidPtr)
00257: {
00258:     BoolPtr = (const bool *) VoidPtr;
00259: }
00260: inline void cast_ptr_assign(const char * & CharPtr, const void * VoidPtr)
00261: {
00262:     CharPtr = (const char *) VoidPtr;
00263: }
00264: inline void cast_ptr_assign(const signed char * & UCharPtr, const void * VoidPtr)
00265: {
00266:     UCharPtr = (const signed char *) VoidPtr;
00267: }
00268: inline void cast_ptr_assign(const unsigned char * & UCharPtr, const void * VoidPtr)
00269: {
00270:     UCharPtr = (const unsigned char *) VoidPtr;
00271: }
00272: inline void cast_ptr_assign(const short * & ShortPtr, const void * VoidPtr)
00273: {
00274:     ShortPtr = (const short *) VoidPtr;
00275: }
00276: inline void cast_ptr_assign(const unsigned short * & UShortPtr, const void * VoidPtr)
00277: {
00278:     UShortPtr = (const unsigned short *) VoidPtr;
00279: }
00280: inline void cast_ptr_assign(const int * & IntPtr, const void * VoidPtr)
00281: {
00282:     IntPtr = (const int *) VoidPtr;
00283: }
00284: inline void cast_ptr_assign(const unsigned int * & UIntPtr, const void * VoidPtr)
00285: {
00286:     UIntPtr = (const unsigned int *) VoidPtr;
00287: }
00288: inline void cast_ptr_assign(const long * & LongPtr, const void * VoidPtr)
00289: {
00290:     LongPtr = (const long *) VoidPtr;
00291: }
00292: inline void cast_ptr_assign(const unsigned long * & ULongPtr, const void * VoidPtr)
00293: {
00294:     ULongPtr = (const unsigned long *) VoidPtr;
00295: }
00296: inline void cast_ptr_assign(const float * & FloatPtr, const void * VoidPtr)
00297: {
00298:     FloatPtr = (const float *) VoidPtr;
00299: }
00300: inline void cast_ptr_assign(const double * & DoublePtr, const void * VoidPtr)
00301: {
00302:     DoublePtr = (const double *) VoidPtr;
00303: }
00304: 
00305: //-------------------------------------------------------------------------
00306: 
00307: // memory related functions like to work on bytes, not on void-pointer
00308: // - note: cast_byteptr() is generic for all pointer types
00309: // - TODO check that sizeof(char) == 1 (8 Bit)
00310: 
00311: inline unsigned char * cast_byteptr(void * VoidPtr)
00312: {
00313:     return (unsigned char *) VoidPtr;
00314: }
00315: 
00316: inline const unsigned char * cast_byteptr(const void * VoidPtr)
00317: {
00318:     return (const unsigned char *) VoidPtr;
00319: }
00320: 
00321: //-------------------------------------------------------------------------
00322: 
00323: // one of the few functions which will accept only void-pointer
00324: // (instead of any pointer type) is static_cast<>(), so
00325: // there may be some use for cast_voidptr()
00326: 
00327: inline void * cast_voidptr(void * VoidPtr)
00328: {
00329:     return (void *) VoidPtr;
00330: }
00331: 
00332: inline const void * cast_voidptr(const void * VoidPtr)
00333: {
00334:     return (const void *) VoidPtr;
00335: }
00336: 
00337: 
00338: //=========================================================================
00339: 
00340: // packing of void-pointer into integer representation conversions
00341: //
00342: // - reinterpret_cast is not as strict as we would want:
00343: //     VoidPtrFromChar = reinterpret_cast<void *> (Char);
00344: //   seems to be valid statement (scope: g++ 3.3.3, maybe others)
00345: // - TODO add checks that (sizeof(void *) <= sizeof(long))
00346: //   and provide overloads for (unsigned) int if 
00347: //     sizeof(long) >= sizeof(int) >= sizeof(void *)
00348: 
00349: inline void cast_pack_ptr(long & Long, void * VoidPtr)
00350: {
00351:     Long = (long) VoidPtr;
00352: }
00353: 
00354: inline void cast_pack_ptr(unsigned long & ULong, void * VoidPtr)
00355: {
00356:     ULong = (unsigned long) VoidPtr;
00357: }
00358: 
00359: //inline long cast_pack_ptr(void * VoidPtr);
00360: //inline unsigned long cast_pack_ptr(void * VoidPtr);
00361: 
00362: //-------------------------------------------------------------------------
00363: 
00364: inline void cast_unpack_ptr(void * & VoidPtr, long Long)
00365: {
00366:     VoidPtr = (void *) Long;
00367: }
00368: 
00369: inline void cast_unpack_ptr(void * & VoidPtr, unsigned long ULong)
00370: {
00371:     VoidPtr = (void *) ULong;
00372: }
00373: 
00374: inline void * cast_unpack_ptr(unsigned long ULong)
00375: {
00376:     return (void *) ULong;
00377: }
00378: 
00379: //=========================================================================
00380: 
00381: // packing of long into void-pointer representation conversions
00382: //
00383: // - reinterpret_cast is not as strict as we would want:
00384: //     (...)
00385: // - TODO add checks that (sizeof(void *) >= sizeof(long))
00386: //   and provide overloads for (unsigned) int if 
00387: //     sizeof(void *) >= sizeof(long) >= sizeof(int)
00388: 
00389: inline void cast_pack_int(void * & VoidPtr, long Long)
00390: {
00391:     VoidPtr = (void *) Long;
00392: }
00393: 
00394: inline void cast_pack_int(void * VoidPtr, unsigned long ULong)
00395: {
00396:     VoidPtr = (void *) ULong;
00397: }
00398: 
00399: inline void * cast_pack_int(unsigned long ULong)
00400: {
00401:     return (void *) ULong;
00402: }
00403: 
00404: inline void * cast_pack_int(long Long)
00405: {
00406:     return (void *) Long;
00407: }
00408: 
00409: //-------------------------------------------------------------------------
00410: 
00411: inline void cast_unpack_ptr(long & Long, void * VoidPtr)
00412: {
00413:     Long = (long) VoidPtr;
00414: }
00415: 
00416: inline void cast_unpack_ptr(unsigned long & ULong, void * VoidPtr)
00417: {
00418:     ULong = (long) VoidPtr;
00419: }
00420: 
00421: //=========================================================================
00422: 
00423: #ifndef M_SafeCast_IsNoCxxTemplates
00424: 
00425: // cast_nonconst()
00426: // - similar to const_cast<>, but doesn't require explicit
00427: //   specification of desired output type (template function 
00428: //   auto-instantiation does this job well)
00429: template <class Type>
00430: Type & cast_nonconst (const Type & TypeVar)
00431: {
00432:     return const_cast <Type &> (TypeVar);
00433:     // return (Type &) TypeVar;
00434: }
00435: 
00436: template <class Type>
00437: Type & cast_nonconst (const Type * TypeVarPtr)
00438: {
00439:     return const_cast <Type *> (TypeVarPtr);
00440:     // return (Type *) TypeVar;
00441: }
00442: 
00443: // cast_const(): explicit cast from non-const (or const) to const
00444: // - this may be useful in cases where the compiler insists in
00445: //   using a non-const overload when we would like to having
00446: //   the const overload choosen
00447: // - note that the argument is const as well which means both,
00448: //   const and non-const argument can be specified
00449: template <class Type>
00450: const Type & cast_const (const Type & TypeVar)
00451: {
00452:     return TypeVar;
00453: }
00454: 
00455: template <class Type>
00456: const Type * cast_const (const Type * TypeVarPtr)
00457: {
00458:     return TypeVarPtr;
00459: }
00460: 
00461: #endif // M_SafeCast_IsNoCxxTemplates
00462: 
00463: //-------------------------------------------------------------------------
00464: 
00465: #endif
00466: 
  [main]    [up]  
DaicasWeb v.1.50.0102  //   Daniel Käps  //   April 12, 2007  //   Impressum / Imprint 
http://www.daicas.net/WxExtLib/src/safecast.h.html