piranha  0.10
safe_integral_adder.hpp
1 /* Copyright 2009-2017 Francesco Biscani (bluescarni@gmail.com)
2 
3 This file is part of the Piranha library.
4 
5 The Piranha library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8  * the GNU Lesser General Public License as published by the Free
9  Software Foundation; either version 3 of the License, or (at your
10  option) any later version.
11 
12 or
13 
14  * the GNU General Public License as published by the Free Software
15  Foundation; either version 3 of the License, or (at your option) any
16  later version.
17 
18 or both in parallel, as here.
19 
20 The Piranha library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the Piranha library. If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #ifndef PIRANHA_DETAIL_SAFE_INTEGRAL_ADDER_HPP
30 #define PIRANHA_DETAIL_SAFE_INTEGRAL_ADDER_HPP
31 
32 #include <limits>
33 #include <stdexcept>
34 #include <type_traits>
35 
36 #include <piranha/config.hpp>
37 #include <piranha/exceptions.hpp>
38 
39 namespace piranha
40 {
41 
42 namespace detail
43 {
44 
45 // NOTE: recent GCCs have builtins for these, we should probably use them:
46 // https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html
47 // Apparently from GCC 5 onwards:
48 // https://software.intel.com/en-us/forums/intel-c-compiler/topic/720757
49 // And clang from 3.4:
50 // http://releases.llvm.org/3.4/tools/clang/docs/LanguageExtensions.html
51 
52 // An overloaded helper function to perform safely the addition in-place of two integral values. It will throw
53 // std::overflow_error in case of out-of-range conditions.
54 template <typename T, typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, int>::type = 0>
55 inline void safe_integral_adder(T &a, const T &b)
56 {
57  if (b >= T(0)) {
58  if (unlikely(a > std::numeric_limits<T>::max() - b)) {
59  piranha_throw(std::overflow_error, "overflow in the addition of two signed integrals");
60  }
61  } else {
62  if (unlikely(a < std::numeric_limits<T>::min() - b)) {
63  piranha_throw(std::overflow_error, "overflow in the addition of two signed integrals");
64  }
65  }
66  a = static_cast<T>(a + b);
67 }
68 
69 template <typename T, typename std::enable_if<std::is_integral<T>::value && !std::is_signed<T>::value, int>::type = 0>
70 inline void safe_integral_adder(T &a, const T &b)
71 {
72  if (unlikely(a > std::numeric_limits<T>::max() - b)) {
73  piranha_throw(std::overflow_error, "overflow in the addition of two unsigned integrals");
74  }
75  a = static_cast<T>(a + b);
76 }
77 
78 template <typename T, typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, int>::type = 0>
79 inline void safe_integral_subber(T &a, const T &b)
80 {
81  if (b <= T(0)) {
82  if (unlikely(a > std::numeric_limits<T>::max() + b)) {
83  piranha_throw(std::overflow_error, "overflow in the subtraction of two signed integrals");
84  }
85  } else {
86  if (unlikely(a < std::numeric_limits<T>::min() + b)) {
87  piranha_throw(std::overflow_error, "overflow in the subtraction of two signed integrals");
88  }
89  }
90  a = static_cast<T>(a - b);
91 }
92 
93 template <typename T, typename std::enable_if<std::is_integral<T>::value && !std::is_signed<T>::value, int>::type = 0>
94 inline void safe_integral_subber(T &a, const T &b)
95 {
96  if (unlikely(a < b)) {
97  piranha_throw(std::overflow_error, "overflow in the subtraction of two unsigned integrals");
98  }
99  a = static_cast<T>(a - b);
100 }
101 }
102 }
103 
104 #endif
Exceptions.
#define piranha_throw(exception_type,...)
Exception-throwing macro.
Definition: exceptions.hpp:118
Root piranha namespace.
Definition: array_key.hpp:52