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: