//======================================================================== // // GooCheckedOps.h // // This file is licensed under the GPLv2 or later // // Copyright (C) 2018 Adam Reichold // Copyright (C) 2019 LE GARREC Vincent // Copyright (C) 2019, 2020 Albert Astals Cid // //======================================================================== #ifndef GOO_CHECKED_OPS_H #define GOO_CHECKED_OPS_H #include #include template inline bool checkedAssign(long long lz, T *z) { static_assert((std::numeric_limits::max)() > (std::numeric_limits::max)(), "The max of long long type must be larger to perform overflow checks."); static_assert((std::numeric_limits::min)() < (std::numeric_limits::min)(), "The min of long long type must be smaller to perform overflow checks."); if (lz > (std::numeric_limits::max)() || lz < (std::numeric_limits::min)()) { return true; } *z = static_cast(lz); return false; } #ifndef __has_builtin # define __has_builtin(x) 0 #endif template inline bool checkedAdd(T x, T y, T *z) { #if __GNUC__ >= 5 || __has_builtin(__builtin_add_overflow) return __builtin_add_overflow(x, y, z); #else const auto lz = static_cast(x) + static_cast(y); return checkedAssign(lz, z); #endif } template inline bool checkedSubtraction(T x, T y, T *z) { #if __GNUC__ >= 5 || __has_builtin(__builtin_sub_overflow) return __builtin_sub_overflow(x, y, z); #else const auto lz = static_cast(x) - static_cast(y); return checkedAssign(lz, z); #endif } template inline bool checkedMultiply(T x, T y, T *z) { #if __GNUC__ >= 5 || __has_builtin(__builtin_mul_overflow) return __builtin_mul_overflow(x, y, z); #else const auto lz = static_cast(x) * static_cast(y); return checkedAssign(lz, z); #endif } template inline T safeAverage(T a, T b) { static_assert((std::numeric_limits::max)() > (std::numeric_limits::max)(), "The max of long long type must be larger to perform overflow checks."); static_assert((std::numeric_limits::min)() < (std::numeric_limits::min)(), "The min of long long type must be smaller to perform overflow checks."); return static_cast((static_cast(a) + static_cast(b)) / 2); } #endif // GOO_CHECKED_OPS_H