ML Reference
|
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