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
41namespace 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>
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:42
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
Helper struct for SFINAE, from C++11.
Definition: safe_op.hpp:91
Helper struct to determine whether a type is signed or unsigned.
Definition: safe_op.hpp:76