1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
10 #ifndef INCLUDED_O3TL_SAFEINT_HXX
11 #define INCLUDED_O3TL_SAFEINT_HXX
13 #include <sal/config.h>
17 #include <type_traits>
23 # define __has_builtin(x) 0
30 template<typename T
> inline
31 typename
std::enable_if
<std::is_signed
<T
>::value
, T
>::type
saturating_add(
35 if (a
<= std::numeric_limits
<T
>::max() - b
) {
38 return std::numeric_limits
<T
>::max();
41 if (a
>= std::numeric_limits
<T
>::min() - b
) {
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(
53 if (a
<= std::numeric_limits
<T
>::max() - b
) {
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(
65 if (a
>= std::numeric_limits
<T
>::min() + b
) {
68 return std::numeric_limits
<T
>::min();
71 if (a
<= std::numeric_limits
<T
>::max() + b
) {
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(
83 if (a
>= std::numeric_limits
<T
>::min() + b
) {
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(
94 if (a
== std::numeric_limits
<T
>::min())
95 return std::numeric_limits
<T
>::max();
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
);
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 */
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 */
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
)))) {
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 */
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
)) {
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
)
230 template<typename T
> constexpr std::enable_if_t
<std::is_signed_v
<T
>, std::make_unsigned_t
<T
>>
231 make_unsigned(T value
)
241 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */