Exiv2
Loading...
Searching...
No Matches
safe_op.hpp
1// SPDX-License-Identifier: GPL-2.0-or-later
2
3#ifndef SAFE_OP_HPP_
4#define SAFE_OP_HPP_
5
6#include <limits>
7#include <stdexcept>
8#include <type_traits>
9
10#ifdef _MSC_VER
11#include <Intsafe.h>
12#endif
13
17namespace Safe {
40namespace Internal {
61template <typename T>
62bool fallback_add_overflow(T summand_1, T summand_2, T& result) {
63 if constexpr (std::is_signed_v<T> && sizeof(T) >= sizeof(int)) {
64 if (((summand_2 >= 0) && (summand_1 > std::numeric_limits<T>::max() - summand_2)) ||
65 ((summand_2 < 0) && (summand_1 < std::numeric_limits<T>::min() - summand_2)))
66 return true;
67 result = summand_1 + summand_2;
68 return false;
69 } else if constexpr (std::is_signed_v<T> && sizeof(T) < sizeof(int)) {
70 const int res = summand_1 + summand_2;
71 if ((res > std::numeric_limits<T>::max()) || (res < std::numeric_limits<T>::min())) {
72 return true;
73 }
74 result = static_cast<T>(res);
75 return false;
76 } else {
77 result = summand_1 + summand_2;
78 return result < summand_1;
79 }
80}
81
95template <typename T>
96bool builtin_add_overflow(T summand_1, T summand_2, T& result) {
97 return fallback_add_overflow(summand_1, summand_2, result);
98}
99
100#if defined(__GNUC__) || defined(__clang__)
101#if __GNUC__ >= 5 || __clang_major__ >= 3
102
113#define SPECIALIZE_builtin_add_overflow(type, builtin_name) \
114 /* Full specialization of builtin_add_overflow for type using the */ \
115 /* builtin_name intrinsic */ \
116 template <> \
117 constexpr bool builtin_add_overflow<type>(type summand_1, type summand_2, type & result) { \
118 return builtin_name(summand_1, summand_2, &result); \
119 }
120
121SPECIALIZE_builtin_add_overflow(int, __builtin_sadd_overflow);
122SPECIALIZE_builtin_add_overflow(long, __builtin_saddl_overflow);
123SPECIALIZE_builtin_add_overflow(long long, __builtin_saddll_overflow);
124
125SPECIALIZE_builtin_add_overflow(unsigned int, __builtin_uadd_overflow);
126SPECIALIZE_builtin_add_overflow(unsigned long, __builtin_uaddl_overflow);
127SPECIALIZE_builtin_add_overflow(unsigned long long, __builtin_uaddll_overflow);
128
129#undef SPECIALIZE_builtin_add_overflow
130#endif // __GNUC__ >= 5 || __clang_major >= 3
131
132#endif
133
134} // namespace Internal
135
156template <typename T>
157T add(T summand_1, T summand_2) {
158 T res = 0;
159 if (Internal::builtin_add_overflow(summand_1, summand_2, res)) {
160 throw std::overflow_error("Overflow in addition");
161 }
162 return res;
163}
164
187template <typename T>
188T abs(T num) noexcept {
189 if constexpr (std::is_signed_v<T>) {
190 if (num == std::numeric_limits<T>::min())
191 return std::numeric_limits<T>::max();
192 return num < 0 ? -num : num;
193 }
194 return num;
195}
196
197} // namespace Safe
198
199#endif // SAFE_OP_HPP_
bool builtin_add_overflow(T summand_1, T summand_2, T &result)
Overflow addition check using compiler intrinsics.
Definition safe_op.hpp:96
bool fallback_add_overflow(T summand_1, T summand_2, T &result)
Check the addition of two numbers for overflows for signed integer types larger than int or with the ...
Definition safe_op.hpp:62
Arithmetic operations with overflow checks.
Definition safe_op.hpp:17
T add(T summand_1, T summand_2)
Safe addition, throws an exception on overflow.
Definition safe_op.hpp:157
T abs(T num) noexcept
Calculates the absolute value of a number without producing negative values.
Definition safe_op.hpp:188