MeVisLab Toolbox 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<>
98  struct _ml_numeric_limits<int>
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<>
114  struct _ml_numeric_limits<long>
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...
Definition: mlRangeCasts.h:36
Target mlrange_cast(Source arg)
Generic version of checked ML casts.
Definition: mlRangeCasts.h:332
static float checked_cast(double arg)
Definition: mlRangeCasts.h:231
static Target checked_cast(Source arg)
Definition: mlRangeCasts.h:221
Compile check functions only if needed.
Definition: mlRangeCasts.h:164
static Target checked_cast(Source arg)
Definition: mlRangeCasts.h:291
Utility template that multiplexes between the different combinations of casting between integer and f...
Definition: mlRangeCasts.h:247
Define a template to get the min and max values for each basic integer type.
Definition: mlRangeCasts.h:47