Exiv2
safe_op.hpp
Go to the documentation of this file.
1 // ********************************************************* -*- C++ -*-
2 /*
3  * Copyright (C) 2004-2018 Exiv2 authors
4  * This program is part of the Exiv2 distribution.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
19  */
28 #ifndef SAFE_OP_HPP_
29 #define SAFE_OP_HPP_
30 
31 #include <limits>
32 #include <stdexcept>
33 
34 #ifdef _MSC_VER
35 #include <Intsafe.h>
36 #endif
37 
41 namespace Safe
42 {
65  namespace Internal
66  {
74  template <typename T>
75  struct is_signed
76  {
77  enum
78  {
79  VALUE = T(-1) < T(0)
80  };
81  };
82 
89  template <bool B, class T = void>
90  struct enable_if
91  {
92  };
93 
97  template <class T>
98  struct enable_if<true, T>
99  {
100  typedef T type;
101  };
102 
120  template <typename T>
121  typename enable_if<is_signed<T>::VALUE && sizeof(T) >= sizeof(int), bool>::type fallback_add_overflow(
122  T summand_1, T summand_2, T& result)
123  {
124  if (((summand_2 >= 0) && (summand_1 > std::numeric_limits<T>::max() - summand_2)) ||
125  ((summand_2 < 0) && (summand_1 < std::numeric_limits<T>::min() - summand_2))) {
126  return true;
127  } else {
128  result = summand_1 + summand_2;
129  return false;
130  }
131  }
132 
152  template <typename T>
153  typename enable_if<is_signed<T>::VALUE && sizeof(T) < sizeof(int), bool>::type fallback_add_overflow(
154  T summand_1, T summand_2, T& result)
155  {
156  const int res = summand_1 + summand_2;
157  if ((res > std::numeric_limits<T>::max()) || (res < std::numeric_limits<T>::min())) {
158  return true;
159  } else {
160  result = static_cast<T>(res);
161  return false;
162  }
163  }
164 
181  template <typename T>
182  typename enable_if<!is_signed<T>::VALUE, bool>::type fallback_add_overflow(T summand_1, T summand_2, T& result)
183  {
184  result = summand_1 + summand_2;
185  return result < summand_1;
186  }
187 
201  template <typename T>
202  bool builtin_add_overflow(T summand_1, T summand_2, T& result)
203  {
204  return fallback_add_overflow(summand_1, summand_2, result);
205  }
206 
207 #if defined(__GNUC__) || defined(__clang__)
208 #if __GNUC__ >= 5 || __clang_major__ >= 3
209 
220 #define SPECIALIZE_builtin_add_overflow(type, builtin_name) \
221  /* Full specialization of builtin_add_overflow for type using the */ \
222  /* builtin_name intrinsic */ \
223  template <> \
224  inline bool builtin_add_overflow<type>(type summand_1, type summand_2, type & result) \
225  { \
226  return builtin_name(summand_1, summand_2, &result); \
227  }
228 
229  SPECIALIZE_builtin_add_overflow(int, __builtin_sadd_overflow);
230  SPECIALIZE_builtin_add_overflow(long, __builtin_saddl_overflow);
231  SPECIALIZE_builtin_add_overflow(long long, __builtin_saddll_overflow);
232 
233  SPECIALIZE_builtin_add_overflow(unsigned int, __builtin_uadd_overflow);
234  SPECIALIZE_builtin_add_overflow(unsigned long, __builtin_uaddl_overflow);
235  SPECIALIZE_builtin_add_overflow(unsigned long long, __builtin_uaddll_overflow);
236 
237 #undef SPECIALIZE_builtin_add_overflow
238 #endif // __GNUC__ >= 5 || __clang_major >= 3
239 
240 #elif defined(_MSC_VER)
241 // intrinsics are not in available in MSVC 2005 and earlier
242 #if _MSC_VER >= 1400
243 
257 #define SPECIALIZE_builtin_add_overflow_WIN(type, builtin_name) \
258  template <> \
259  inline bool builtin_add_overflow(type summand_1, type summand_2, type& result) \
260  { \
261  return builtin_name(summand_1, summand_2, &result) != S_OK; \
262  }
263 
264  SPECIALIZE_builtin_add_overflow_WIN(unsigned int, UIntAdd);
265  SPECIALIZE_builtin_add_overflow_WIN(unsigned long, ULongAdd);
266  SPECIALIZE_builtin_add_overflow_WIN(unsigned long long, ULongLongAdd);
267 
268 #undef SPECIALIZE_builtin_add_overflow_WIN
269 
270 #endif // _MSC_VER >= 1400
271 #endif // defined(_MSC_VER)
272 
273  } // namespace Internal
274 
294  template <typename T>
295  T add(T summand_1, T summand_2)
296  {
297  T res = 0;
298  if (Internal::builtin_add_overflow(summand_1, summand_2, res)) {
299  throw std::overflow_error("Overflow in addition");
300  }
301  return res;
302  }
303 
326  template <typename T>
327  typename Internal::enable_if<Internal::is_signed<T>::VALUE, T>::type abs(T num) throw()
328  {
329  if (num == std::numeric_limits<T>::min()) {
330  return std::numeric_limits<T>::max();
331  }
332  return num < 0 ? -num : num;
333  }
334 
335 } // namespace Safe
336 
337 #endif // SAFE_OP_HPP_
Arithmetic operations with overflow checks.
Definition: safe_op.hpp:41
Helper struct to determine whether a type is signed or unsigned.
Definition: safe_op.hpp:75
Helper struct for SFINAE, from C++11.
Definition: safe_op.hpp:90
T add(T summand_1, T summand_2)
Safe addition, throws an exception on overflow.
Definition: safe_op.hpp:295
Internal::enable_if< Internal::is_signed< T >::VALUE, T >::type abs(T num)
Calculates the absolute value of a number without producing negative values.
Definition: safe_op.hpp:327