//======================================================================== // // GooCheckedOps.h // // This file is licensed under the GPLv2 or later // // Copyright (C) 2018 Adam Reichold // Copyright (C) 2019 LE GARREC Vincent // //======================================================================== #ifndef GOO_CHECKED_OPS_H #define GOO_CHECKED_OPS_H #include #include inline bool checkedAssign(long long lz, int *z) { static_assert(LLONG_MAX > INT_MAX, "Need type larger than int to perform overflow checks."); if (lz > INT_MAX || lz < INT_MIN) { return true; } *z = static_cast(lz); return false; } #ifndef __has_builtin #define __has_builtin(x) 0 #endif inline bool checkedAdd(int x, int y, int *z) { #if __GNUC__ >= 5 || __has_builtin(__builtin_sadd_overflow) return __builtin_sadd_overflow(x, y, z); #else const auto lz = static_cast(x) + static_cast(y); return checkedAssign(lz, z); #endif } inline bool checkedMultiply(int x, int y, int *z) { #if __GNUC__ >= 5 || __has_builtin(__builtin_smul_overflow) return __builtin_smul_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