ML Reference
MeVis/Foundation/Sources/MLUtilities/mlRangeCasts.h
Go to the documentation of this file.
00001 // **InsertLicense** code
00002 //-------------------------------------------------------------------------
00004 
00009 //-------------------------------------------------------------------------
00010 #ifndef __mlRangeCasts_H
00011 #define __mlRangeCasts_H
00012 
00013 #ifndef __mlTypeDefs_H
00014 #include "mlTypeDefs.h"
00015 #endif
00016 #ifndef __mlErrorMacros_H
00017 #include "mlErrorMacros.h"
00018 #endif
00019 #ifndef __mlErrorOutput_H
00020 #include "mlErrorOutput.h"
00021 #endif
00022 
00023 #include "mlSystemWarningsDisable.h"
00024 #include <limits.h>
00025 #include "mlSystemWarningsRestore.h"
00026 
00028   //#define _ML_COMPILE_RANGE_CASTS_ONLY_AS_CASTS
00029 
00031   #define _ML_COMPILE_RANGE_CASTS_WITH_CHECKS
00032 
00034   #define _ML_RANGE_ERROR_TYPE         ML_PRINT_FATAL_ERROR
00035 
00037   // The mininums are always returned with the equivalent signed type, while the
00038   // maximums are returned with the equivalent unsigned type. This is needed so
00039   // that comparisons of mins or maxs of types with the same size but different
00040   // signed-ness don't fail (the compiler would cast to one of the types).
00041   template <typename T>
00042   struct _ml_numeric_limits;
00043 
00044   template<>
00045   struct _ml_numeric_limits<unsigned char>
00046   {
00047     static const signed char MinValue = 0;
00048     static const unsigned char MaxValue = UCHAR_MAX;
00049   };
00050 
00051   template<>
00052   struct _ml_numeric_limits<signed char>
00053   {
00054     static const signed char MinValue = SCHAR_MIN;
00055     static const unsigned char MaxValue = SCHAR_MAX;
00056   };
00057 
00058   template<>
00059   struct _ml_numeric_limits<char>
00060   {
00061     static const signed char MinValue = CHAR_MIN;
00062     static const unsigned char MaxValue = CHAR_MAX;
00063   };
00064 
00065   template<>
00066   struct _ml_numeric_limits<unsigned short>
00067   {
00068     static const signed short MinValue = 0;
00069     static const unsigned short MaxValue = USHRT_MAX;
00070   };
00071 
00072   template<>
00073   struct _ml_numeric_limits<short>
00074   {
00075     static const short MinValue = SHRT_MIN;
00076     static const unsigned short MaxValue = SHRT_MAX;
00077   };
00078 
00079   template<>
00080   struct _ml_numeric_limits<unsigned int>
00081   {
00082     static const int MinValue = 0;
00083     static const unsigned int MaxValue = UINT_MAX;
00084   };
00085 
00086   template<>
00087   struct _ml_numeric_limits<int>
00088   {
00089     static const int MinValue = INT_MIN;
00090     static const unsigned int MaxValue = INT_MAX;
00091   };
00092 
00093   template<>
00094   struct _ml_numeric_limits<unsigned long>
00095   {
00096     static const long MinValue = 0;
00097     static const unsigned long MaxValue = ULONG_MAX;
00098   };
00099 
00100   template<>
00101   struct _ml_numeric_limits<long>
00102   {
00103     static const long MinValue = LONG_MIN;
00104     static const unsigned long MaxValue = LONG_MAX;
00105   };
00106 
00107   template<>
00108   struct _ml_numeric_limits<unsigned long long>
00109   {
00110     static const long long MinValue = 0;
00111     static const unsigned long long MaxValue = ULLONG_MAX;
00112   };
00113 
00114   template<>
00115   struct _ml_numeric_limits<long long>
00116   {
00117     static const long long MinValue = LLONG_MIN;
00118     static const unsigned long long MaxValue = LLONG_MAX;
00119   };
00120 
00122   #if defined(_ML_COMPILE_RANGE_CASTS_WITH_CHECKS)
00123 
00126     template <bool CheckLowerBounds, bool CheckUpperBounds, typename Target, typename Source>
00127     struct _MLIntegerRangeCheck;
00128 
00129     template <typename Target, typename Source>
00130     struct _MLIntegerRangeCheck<true, true, Target, Source>
00131     {
00132       static inline Target checked_cast(Source srcVal)
00133       {
00134         if ((srcVal < static_cast<Source>(_ml_numeric_limits<Target>::MinValue)) ||
00135             (srcVal > static_cast<Source>(_ml_numeric_limits<Target>::MaxValue)))
00136         {
00137           _ML_RANGE_ERROR_TYPE("_MLRangeCheck::checked_cast", ML_OUT_OF_RANGE, "Invalid numeric cast (range check failed).");
00138         }
00139         return static_cast<Target>(srcVal);
00140       }
00141     };
00142 
00143     template <typename Target, typename Source>
00144     struct _MLIntegerRangeCheck<false, true, Target, Source>
00145     {
00146       static inline Target checked_cast(Source srcVal)
00147       {
00148         if (srcVal > static_cast<Source>(_ml_numeric_limits<Target>::MaxValue))
00149         {
00150           _ML_RANGE_ERROR_TYPE("_MLRangeCheck::checked_cast", ML_OUT_OF_RANGE, "Invalid numeric cast (range check failed).");
00151         }
00152         return static_cast<Target>(srcVal);
00153       }
00154     };
00155 
00156     template <typename Target, typename Source>
00157     struct _MLIntegerRangeCheck<true, false, Target, Source>
00158     {
00159       static inline Target checked_cast(Source srcVal)
00160       {
00161         if (srcVal < static_cast<Source>(_ml_numeric_limits<Target>::MinValue))
00162         {
00163           _ML_RANGE_ERROR_TYPE("_MLRangeCheck::checked_cast", ML_OUT_OF_RANGE, "Invalid numeric cast (range check failed).");
00164         }
00165         return static_cast<Target>(srcVal);
00166       }
00167     };
00168 
00169     template <typename Target, typename Source>
00170     struct _MLIntegerRangeCheck<false, false, Target, Source>
00171     {
00172       static inline Target checked_cast(Source srcVal)
00173       {
00174         return static_cast<Target>(srcVal);
00175       }
00176     };
00177 
00178   #endif
00179 
00180 
00181   //----------------------------------------------
00183   //----------------------------------------------
00184   #if defined(_ML_COMPILE_RANGE_CASTS_ONLY_AS_CASTS) && defined(_ML_COMPILE_RANGE_CASTS_WITH_CHECKS)
00185     #error "_ML_COMPILE_RANGE_CASTS_ONLY_AS_CASTS and _ML_COMPILE_RANGE_CAST_FUNCTIONS_WITH_CHECKS must not be set both."
00186   #else
00187     #if !defined(_ML_COMPILE_RANGE_CASTS_ONLY_AS_CASTS) && !defined(_ML_COMPILE_RANGE_CASTS_WITH_CHECKS)
00188       // Compilation is disabled - so just insert original statements instead of function calls.
00189 
00190       template<Target, Source>
00191       inline Target mlrange_cast(Source arg) { return arg; }
00192 
00193     #else
00194 
00195       #if defined(_ML_COMPILE_RANGE_CASTS_ONLY_AS_CASTS)
00196         // Compilation is enabled, but checks are disabled for maximum performance. Just insert casts then.
00197 
00198         template<Target, Source>
00199         inline Target mlrange_cast(Source arg) { return static_cast<Target>(arg); }
00200 
00201       #else
00202         // Compilation is enabled with checks. Insert check function calls.
00203 
00207         template<typename Target, typename Source>
00208         inline Target mlrange_cast(Source arg)
00209         {
00210           return _MLIntegerRangeCheck<(_ml_numeric_limits<Target>::MinValue > _ml_numeric_limits<Source>::MinValue),
00211                                       (_ml_numeric_limits<Target>::MaxValue < _ml_numeric_limits<Source>::MaxValue),
00212                                       Target, Source>
00213                  ::checked_cast(arg);
00214         }
00215 
00216       #endif
00217     #endif
00218   #endif
00219 #endif
00220