nss: upgrade to release 3.73
[LibreOffice.git] / include / o3tl / safeint.hxx
blob6d8d1304fdf363c27ac6d7c97e9818cee96a98f4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #ifndef INCLUDED_O3TL_SAFEINT_HXX
11 #define INCLUDED_O3TL_SAFEINT_HXX
13 #include <sal/config.h>
15 #include <cassert>
16 #include <limits>
17 #include <type_traits>
19 #if defined(_MSC_VER)
20 #include <safeint.h>
21 #else
22 #ifndef __has_builtin
23 # define __has_builtin(x) 0
24 #endif
25 #endif
27 namespace o3tl
30 template<typename T> inline
31 typename std::enable_if<std::is_signed<T>::value, T>::type saturating_add(
32 T a, T b)
34 if (b >= 0) {
35 if (a <= std::numeric_limits<T>::max() - b) {
36 return a + b;
37 } else {
38 return std::numeric_limits<T>::max();
40 } else {
41 if (a >= std::numeric_limits<T>::min() - b) {
42 return a + b;
43 } else {
44 return std::numeric_limits<T>::min();
49 template<typename T> inline
50 typename std::enable_if<std::is_unsigned<T>::value, T>::type saturating_add(
51 T a, T b)
53 if (a <= std::numeric_limits<T>::max() - b) {
54 return a + b;
55 } else {
56 return std::numeric_limits<T>::max();
60 template<typename T> inline
61 typename std::enable_if<std::is_signed<T>::value, T>::type saturating_sub(
62 T a, T b)
64 if (b >= 0) {
65 if (a >= std::numeric_limits<T>::min() + b) {
66 return a - b;
67 } else {
68 return std::numeric_limits<T>::min();
70 } else {
71 if (a <= std::numeric_limits<T>::max() + b) {
72 return a - b;
73 } else {
74 return std::numeric_limits<T>::max();
79 template<typename T> inline
80 typename std::enable_if<std::is_unsigned<T>::value, T>::type saturating_sub(
81 T a, T b)
83 if (a >= std::numeric_limits<T>::min() + b) {
84 return a - b;
85 } else {
86 return std::numeric_limits<T>::min();
90 template<typename T> inline
91 typename std::enable_if<std::is_signed<T>::value, T>::type saturating_toggle_sign(
92 T a)
94 if (a == std::numeric_limits<T>::min())
95 return std::numeric_limits<T>::max();
96 return a * -1;
99 #if defined(_MSC_VER)
101 template<typename T> inline bool checked_multiply(T a, T b, T& result)
103 return !msl::utilities::SafeMultiply(a, b, result);
106 template<typename T> inline bool checked_add(T a, T b, T& result)
108 return !msl::utilities::SafeAdd(a, b, result);
111 template<typename T> inline bool checked_sub(T a, T b, T& result)
113 return !msl::utilities::SafeSubtract(a, b, result);
116 #elif (defined __GNUC__ && !defined __clang__) || (__has_builtin(__builtin_mul_overflow) && !(defined ANDROID && defined __clang__) && !(defined(__clang__) && defined(__i386__)))
117 // 32-bit clang fails with undefined reference to `__mulodi4'
119 template<typename T> inline bool checked_multiply(T a, T b, T& result)
121 return __builtin_mul_overflow(a, b, &result);
124 template<typename T> inline bool checked_add(T a, T b, T& result)
126 return __builtin_add_overflow(a, b, &result);
129 template<typename T> inline bool checked_sub(T a, T b, T& result)
131 return __builtin_sub_overflow(a, b, &result);
134 #else
136 //https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
137 template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_multiply(T a, T b, T& result)
139 if (a > 0) { /* a is positive */
140 if (b > 0) { /* a and b are positive */
141 if (a > (std::numeric_limits<T>::max() / b)) {
142 return true; /* Handle error */
144 } else { /* a positive, b nonpositive */
145 if (b < (std::numeric_limits<T>::min() / a)) {
146 return true; /* Handle error */
148 } /* a positive, b nonpositive */
149 } else { /* a is nonpositive */
150 if (b > 0) { /* a is nonpositive, b is positive */
151 if (a < (std::numeric_limits<T>::min() / b)) {
152 return true; /* Handle error */
154 } else { /* a and b are nonpositive */
155 if ( (a != 0) && (b < (std::numeric_limits<T>::max() / a))) {
156 return true; /* Handle error */
158 } /* End if a and b are nonpositive */
159 } /* End if a is nonpositive */
161 result = a * b;
163 return false;
166 //https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
167 template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_multiply(T a, T b, T& result)
169 if (b && a > std::numeric_limits<T>::max() / b) {
170 return true;/* Handle error */
173 result = a * b;
175 return false;
178 //https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
179 template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_add(T a, T b, T& result)
181 if (((b > 0) && (a > (std::numeric_limits<T>::max() - b))) ||
182 ((b < 0) && (a < (std::numeric_limits<T>::min() - b)))) {
183 return true;
186 result = a + b;
188 return false;
191 //https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
192 template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_add(T a, T b, T& result)
194 if (std::numeric_limits<T>::max() - a < b) {
195 return true;/* Handle error */
198 result = a + b;
200 return false;
203 //https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
204 template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_sub(T a, T b, T& result)
206 if ((b > 0 && a < std::numeric_limits<T>::min() + b) ||
207 (b < 0 && a > std::numeric_limits<T>::max() + b)) {
208 return true;
211 result = a - b;
213 return false;
216 //https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
217 template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_sub(T a, T b, T& result)
219 if (a < b) {
220 return true;
223 result = a - b;
225 return false;
228 #endif
230 template<typename T> constexpr std::enable_if_t<std::is_signed_v<T>, std::make_unsigned_t<T>>
231 make_unsigned(T value)
233 assert(value >= 0);
234 return value;
239 #endif
241 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */