1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef util_CheckedArithmetic_h
8 #define util_CheckedArithmetic_h
10 #include "mozilla/Compiler.h"
11 #include "mozilla/MathAlgorithms.h"
15 // This macro is should be `one' if current compiler supports builtin functions
16 // like __builtin_sadd_overflow.
18 // GCC supports these functions.
19 # define BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(x) 1
21 // For CLANG, we use its own function to check for this.
23 # define BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(x) __has_builtin(x)
26 #ifndef BUILTIN_CHECKED_ARITHMETIC_SUPPORTED
27 # define BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(x) 0
32 [[nodiscard
]] inline bool SafeAdd(int32_t one
, int32_t two
, int32_t* res
) {
33 #if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_sadd_overflow)
34 // Using compiler's builtin function.
35 return !__builtin_sadd_overflow(one
, two
, res
);
37 // Use unsigned for the 32-bit operation since signed overflow gets
38 // undefined behavior.
39 *res
= uint32_t(one
) + uint32_t(two
);
40 int64_t ores
= (int64_t)one
+ (int64_t)two
;
41 return ores
== (int64_t)*res
;
45 [[nodiscard
]] inline bool SafeSub(int32_t one
, int32_t two
, int32_t* res
) {
46 #if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_ssub_overflow)
47 return !__builtin_ssub_overflow(one
, two
, res
);
49 *res
= uint32_t(one
) - uint32_t(two
);
50 int64_t ores
= (int64_t)one
- (int64_t)two
;
51 return ores
== (int64_t)*res
;
55 [[nodiscard
]] inline bool SafeMul(int32_t one
, int32_t two
, int32_t* res
) {
56 #if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_smul_overflow)
57 return !__builtin_smul_overflow(one
, two
, res
);
59 *res
= uint32_t(one
) * uint32_t(two
);
60 int64_t ores
= (int64_t)one
* (int64_t)two
;
61 return ores
== (int64_t)*res
;
65 [[nodiscard
]] inline bool SafeMul(uint64_t one
, uint64_t two
, uint64_t* res
) {
66 #if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_mul_overflow)
67 return !__builtin_mul_overflow(one
, two
, res
);
69 // Hacker's Delight, 2nd edition, 2-13 Overflow detection, Fig. 2-2.
71 mozilla::CountLeadingZeroes64(one
) + mozilla::CountLeadingZeroes64(two
);
75 uint64_t half
= one
* (two
>> 1);
76 if (int64_t(half
) < 0) {
92 #endif /* util_CheckedArithmetic_h */