File indexing completed on 2025-12-11 10:26:10
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef GOO_CHECKED_OPS_H
0014 #define GOO_CHECKED_OPS_H
0015
0016 #include <limits>
0017 #include <type_traits>
0018
0019 template<typename T>
0020 inline bool checkedAssign(long long lz, T *z)
0021 {
0022 static_assert((std::numeric_limits<long long>::max)() > (std::numeric_limits<T>::max)(), "The max of long long type must be larger to perform overflow checks.");
0023 static_assert((std::numeric_limits<long long>::min)() < (std::numeric_limits<T>::min)(), "The min of long long type must be smaller to perform overflow checks.");
0024
0025 if (lz > (std::numeric_limits<T>::max)() || lz < (std::numeric_limits<T>::min)()) {
0026 return true;
0027 }
0028
0029 *z = static_cast<T>(lz);
0030 return false;
0031 }
0032
0033 #ifndef __has_builtin
0034 # define __has_builtin(x) 0
0035 #endif
0036
0037 template<typename T>
0038 inline bool checkedAdd(T x, T y, T *z)
0039 {
0040
0041
0042 #if __GNUC__ >= 5 || __has_builtin(__builtin_add_overflow)
0043 return __builtin_add_overflow(x, y, z);
0044 #else
0045 const auto lz = static_cast<long long>(x) + static_cast<long long>(y);
0046 return checkedAssign(lz, z);
0047 #endif
0048 }
0049
0050 template<>
0051 inline bool checkedAdd<long long>(long long x, long long y, long long *z)
0052 {
0053 #if __GNUC__ >= 5 || __has_builtin(__builtin_add_overflow)
0054 return __builtin_add_overflow(x, y, z);
0055 #else
0056 if (x > 0 && y > 0) {
0057 if (x > (std::numeric_limits<long long>::max)() - y) {
0058 return true;
0059 }
0060 } else if (x < 0 && y < 0) {
0061 if (x < (std::numeric_limits<long long>::min)() - y) {
0062 return true;
0063 }
0064 }
0065 *z = x + y;
0066 return false;
0067 #endif
0068 }
0069
0070 template<typename T>
0071 inline bool checkedSubtraction(T x, T y, T *z)
0072 {
0073 #if __GNUC__ >= 5 || __has_builtin(__builtin_sub_overflow)
0074 return __builtin_sub_overflow(x, y, z);
0075 #else
0076 const auto lz = static_cast<long long>(x) - static_cast<long long>(y);
0077 return checkedAssign(lz, z);
0078 #endif
0079 }
0080
0081 template<typename T>
0082 inline bool checkedMultiply(T x, T y, T *z)
0083 {
0084 #if __GNUC__ >= 5 || __has_builtin(__builtin_mul_overflow)
0085 return __builtin_mul_overflow(x, y, z);
0086 #else
0087 const auto lz = static_cast<long long>(x) * static_cast<long long>(y);
0088 return checkedAssign(lz, z);
0089 #endif
0090 }
0091
0092 template<>
0093 inline bool checkedMultiply<long long>(long long x, long long y, long long *z)
0094 {
0095 #if __GNUC__ >= 5 || __has_builtin(__builtin_mul_overflow)
0096 return __builtin_mul_overflow(x, y, z);
0097 #else
0098 if (x != 0 && (std::numeric_limits<long long>::max)() / x < y) {
0099 return true;
0100 }
0101
0102 *z = x * y;
0103 return false;
0104 #endif
0105 }
0106
0107 template<typename T>
0108 inline T safeAverage(T a, T b)
0109 {
0110 static_assert((std::numeric_limits<long long>::max)() > (std::numeric_limits<T>::max)(), "The max of long long type must be larger to perform overflow checks.");
0111 static_assert((std::numeric_limits<long long>::min)() < (std::numeric_limits<T>::min)(), "The min of long long type must be smaller to perform overflow checks.");
0112
0113 return static_cast<T>((static_cast<long long>(a) + static_cast<long long>(b)) / 2);
0114 }
0115
0116 #endif