ML Reference
mlRangeCasts.h
Go to the documentation of this file.
1/*************************************************************************************
2**
3** Copyright 2011, MeVis Medical Solutions AG
4**
5** The user may use this file in accordance with the license agreement provided with
6** the Software or, alternatively, in accordance with the terms contained in a
7** written agreement between the user and MeVis Medical Solutions AG.
8**
9** For further information use the contact form at https://www.mevislab.de/contact
10**
11**************************************************************************************/
12
13#ifndef ML_RANGE_CASTS_H
14#define ML_RANGE_CASTS_H
15
17
18#include "mlTypeDefs.h"
19#include "mlErrorMacros.h"
20#include "mlErrorOutput.h"
21
22#include <ThirdPartyWarningsDisable.h>
23#include <climits>
24#include <ThirdPartyWarningsRestore.h>
25
27 //#define _ML_COMPILE_RANGE_CASTS_ONLY_AS_CASTS
28
30 #define _ML_COMPILE_RANGE_CASTS_WITH_CHECKS
31
33 #define _ML_RANGE_ERROR_TYPE ML_PRINT_FATAL_ERROR
34
36 #define _ML_OUTPUT_RANGE_ERROR \
37 _ML_RANGE_ERROR_TYPE("_MLRangeCheck::checked_cast", ML_OUT_OF_RANGE, "Invalid numeric cast (range check failed).");
38
39//= _ml_numeric_limits ==========================================================================
40
42 // The mininums are always returned with the equivalent signed type, while the
43 // maximums are returned with the equivalent unsigned type. This is needed so
44 // that comparisons of mins or maxs of types with the same size but different
45 // signed-ness don't fail (the compiler would cast to one of the types).
46 template <typename T>
48
49 template<>
50 struct _ml_numeric_limits<unsigned char>
51 {
52 static const signed char MinValue = 0;
53 static const unsigned char MaxValue = UCHAR_MAX;
54 static const bool isFloat = false;
55 };
56
57 template<>
58 struct _ml_numeric_limits<signed char>
59 {
60 static const signed char MinValue = SCHAR_MIN;
61 static const unsigned char MaxValue = SCHAR_MAX;
62 static const bool isFloat = false;
63 };
64
65 template<>
66 struct _ml_numeric_limits<char>
67 {
68 static const signed char MinValue = CHAR_MIN;
69 static const unsigned char MaxValue = CHAR_MAX;
70 static const bool isFloat = false;
71 };
72
73 template<>
74 struct _ml_numeric_limits<unsigned short>
75 {
76 static const signed short MinValue = 0;
77 static const unsigned short MaxValue = USHRT_MAX;
78 static const bool isFloat = false;
79 };
80
81 template<>
82 struct _ml_numeric_limits<short>
83 {
84 static const short MinValue = SHRT_MIN;
85 static const unsigned short MaxValue = SHRT_MAX;
86 static const bool isFloat = false;
87 };
88
89 template<>
90 struct _ml_numeric_limits<unsigned int>
91 {
92 static const int MinValue = 0;
93 static const unsigned int MaxValue = UINT_MAX;
94 static const bool isFloat = false;
95 };
96
97 template<>
99 {
100 static const int MinValue = INT_MIN;
101 static const unsigned int MaxValue = INT_MAX;
102 static const bool isFloat = false;
103 };
104
105 template<>
106 struct _ml_numeric_limits<unsigned long>
107 {
108 static const long MinValue = 0;
109 static const unsigned long MaxValue = ULONG_MAX;
110 static const bool isFloat = false;
111 };
112
113 template<>
115 {
116 static const long MinValue = LONG_MIN;
117 static const unsigned long MaxValue = LONG_MAX;
118 static const bool isFloat = false;
119 };
120
121 template<>
122 struct _ml_numeric_limits<unsigned long long>
123 {
124 static const long long MinValue = 0;
125 static const unsigned long long MaxValue = ULLONG_MAX;
126 static const bool isFloat = false;
127 };
128
129 template<>
130 struct _ml_numeric_limits<long long>
131 {
132 static const long long MinValue = LLONG_MIN;
133 static const unsigned long long MaxValue = LLONG_MAX;
134 static const bool isFloat = false;
135 };
136
137 template<>
138 struct _ml_numeric_limits<float>
139 {
140 // float values can't be compile time constants:
141 // static const double MinValue = -FLT_MAX;
142 // static const double MaxValue = FLT_MAX;
143 static const bool isFloat = true;
144 };
145
146 template<>
147 struct _ml_numeric_limits<double>
148 {
149 // float values can't be compile time constants:
150 // static const double MinValue = -DBL_MAX;
151 // static const double MaxValue = DBL_MAX;
152 static const bool isFloat = true;
153 };
154
155
157 #if defined(_ML_COMPILE_RANGE_CASTS_WITH_CHECKS)
158
159//= _MLIntegerRangeCheck ========================================================================
160
163 template <bool CheckLowerBounds, bool CheckUpperBounds, typename Target, typename Source>
165
166 template <typename Target, typename Source>
167 struct _MLIntegerRangeCheck<true, true, Target, Source>
168 {
169 static inline Target checked_cast(Source srcVal)
170 {
171 if ((srcVal < static_cast<Source>(_ml_numeric_limits<Target>::MinValue)) ||
172 (srcVal > static_cast<Source>(_ml_numeric_limits<Target>::MaxValue)))
173 {
175 }
176 return static_cast<Target>(srcVal);
177 }
178 };
179
180 template <typename Target, typename Source>
181 struct _MLIntegerRangeCheck<false, true, Target, Source>
182 {
183 static inline Target checked_cast(Source srcVal)
184 {
185 if (srcVal > static_cast<Source>(_ml_numeric_limits<Target>::MaxValue))
186 {
188 }
189 return static_cast<Target>(srcVal);
190 }
191 };
192
193 template <typename Target, typename Source>
194 struct _MLIntegerRangeCheck<true, false, Target, Source>
195 {
196 static inline Target checked_cast(Source srcVal)
197 {
198 if (srcVal < static_cast<Source>(_ml_numeric_limits<Target>::MinValue))
199 {
201 }
202 return static_cast<Target>(srcVal);
203 }
204 };
205
206 template <typename Target, typename Source>
207 struct _MLIntegerRangeCheck<false, false, Target, Source>
208 {
209 static inline Target checked_cast(Source srcVal)
210 {
211 return static_cast<Target>(srcVal);
212 }
213 };
214
215//= _MLFloatRangeCheck ==========================================================================
216
217 // The default float range check does nothing
218 template <typename Target, typename Source>
220 {
221 static inline Target checked_cast(Source arg)
222 {
223 return static_cast<Target>(arg);
224 }
225 };
226
227 // Only when casting from double to float a range check is applied
228 template<>
229 struct _MLFloatRangeCheck<float, double>
230 {
231 static inline float checked_cast(double arg)
232 {
233 if ((arg < static_cast<double>(-FLT_MAX)) ||
234 (arg > static_cast<double>(FLT_MAX)))
235 {
237 }
238 return static_cast<float>(arg);
239 }
240 };
241
242//= _MLRangeCheck ===============================================================================
243
246 template <bool isTargetFloat, bool isSourceFloat, typename Target, typename Source>
248
249 // casting integer to integer does (only the necessary) range checks
250 template <typename Target, typename Source>
251 struct _MLRangeCheck<false, false, Target, Source>
252 {
253 static inline Target checked_cast(Source arg)
254 {
257 Target, Source>
258 ::checked_cast(arg);
259 }
260 };
261
262 // casting integer to float does no range checks
263 template <typename Target, typename Source>
264 struct _MLRangeCheck<true, false, Target, Source>
265 {
266 static inline Target checked_cast(Source arg)
267 {
268 return static_cast<Target>(arg);
269 }
270 };
271
272 // casting float to integer does range checks
273 template <typename Target, typename Source>
274 struct _MLRangeCheck<false, true, Target, Source>
275 {
276 static inline Target checked_cast(Source arg)
277 {
278 arg = floor(arg + 0.5f);
279 if ((arg < static_cast<Source>(_ml_numeric_limits<Target>::MinValue)) ||
280 (arg > static_cast<Source>(_ml_numeric_limits<Target>::MaxValue)))
281 {
283 }
284 return static_cast<Target>(arg);
285 }
286 };
287
288 template <typename Target, typename Source>
289 struct _MLRangeCheck<true, true, Target, Source>
290 {
291 static inline Target checked_cast(Source arg)
292 {
294 }
295 };
296
297 #endif
298
299//===============================================================================================
300
301 //----------------------------------------------
303 //----------------------------------------------
304 #if defined(_ML_COMPILE_RANGE_CASTS_ONLY_AS_CASTS) && defined(_ML_COMPILE_RANGE_CASTS_WITH_CHECKS)
305 #error "_ML_COMPILE_RANGE_CASTS_ONLY_AS_CASTS and _ML_COMPILE_RANGE_CAST_FUNCTIONS_WITH_CHECKS must not be set both."
306 #else
307 #if !defined(_ML_COMPILE_RANGE_CASTS_ONLY_AS_CASTS) && !defined(_ML_COMPILE_RANGE_CASTS_WITH_CHECKS)
308 // Compilation is disabled - so just insert original statements instead of function calls.
309
310 template<Target, Source>
311 inline Target mlrange_cast(Source arg) { return arg; }
312
313 #else
314
315 #if defined(_ML_COMPILE_RANGE_CASTS_ONLY_AS_CASTS)
316 // Compilation is enabled, but checks are disabled for maximum performance. Just insert casts then.
317
318 template<Target, Source>
319 inline Target mlrange_cast(Source arg) { return static_cast<Target>(arg); }
320
321 #else
322 // Compilation is enabled with checks. Insert check function calls.
323
331 template<typename Target, typename Source>
332 inline Target mlrange_cast(Source arg)
333 {
336 Target, Source>
337 ::checked_cast(arg);
338 }
339
340 #endif
341 #endif
342 #endif
343#endif
344
#define _ML_OUTPUT_RANGE_ERROR
To avoid duplication...
Target mlrange_cast(Source arg)
Generic version of checked ML casts.
static float checked_cast(double arg)
static Target checked_cast(Source arg)
Compile check functions only if needed.
Utility template that multiplexes between the different combinations of casting between integer and f...
Define a template to get the min and max values for each basic integer type.