#ifndef UC_SATMATH_H_ #define UC_SATMATH_H_ #include /** @file * Implementation of saturated operation on uintxx_t. * * Operations are clamped between 0 and UINTxx_MAX instead of * wrapping around. * * multiplication, subtraction and addition operations are provided.*/ //Use gcc builtins, supported since GCC 5 #if __GNUC__ >= 5 #define UC_SAT_ADD(a, b, type, max_val)\ ({type res ;\ if (__builtin_add_overflow(a, b, &res)) {\ res = max_val;}\ res;}) #define UC_SAT_SUB(a, b, type)\ ({type res ;\ if (__builtin_sub_overflow(a, b, &res)) {\ res = 0;}\ res;}) #define UC_SAT_MULT(a, b, type, max_val)\ ({type res ;\ if (__builtin_mul_overflow(a, b, &res)) {\ res = max_val;}\ res;}) #else #define UC_SAT_ADD(a, b, type, max_val)\ ((type)((a) + (b)) >= (a) ? (a) + (b) : (max_val)) #define UC_SAT_SUB(a, b, type)\ ((a) >= (b) ? (a) - (b) : 0) #define UC_SAT_MULT(a, b, type, max_val)\ ((b) == 0 ? 0 :\ (a) <= (max_val) / (b) ? (type) (a) * (type) (b) \ : (max_val)) #endif static inline uint8_t uc_sat_addu8(uint8_t a, uint8_t b) { return UC_SAT_ADD(a, b, uint8_t, UINT8_MAX); } static inline uint8_t uc_sat_subu8(uint8_t a, uint8_t b) { return UC_SAT_SUB(a, b, uint8_t); } static inline uint8_t uc_sat_multu8(uint8_t a, uint8_t b) { return UC_SAT_MULT(a, b, uint8_t, UINT8_MAX); } static inline uint16_t uc_sat_addu16(uint16_t a, uint16_t b) { return UC_SAT_ADD(a, b, uint16_t, UINT16_MAX); } static inline uint16_t uc_sat_subu16(uint16_t a, uint16_t b) { return UC_SAT_SUB(a, b, uint16_t); } static inline uint16_t uc_sat_multu16(uint16_t a, uint16_t b) { return UC_SAT_MULT(a, b, uint16_t, UINT16_MAX); } static inline uint32_t uc_sat_addu32(uint32_t a, uint32_t b) { return UC_SAT_ADD(a, b, uint32_t, UINT32_MAX); } static inline uint32_t uc_sat_subu32(uint32_t a, uint32_t b) { return UC_SAT_SUB(a, b, uint32_t); } static inline uint32_t uc_sat_multu32(uint32_t a, uint32_t b) { return UC_SAT_MULT(a, b, uint32_t, UINT32_MAX); } static inline uint64_t uc_sat_addu64(uint64_t a, uint64_t b) { return UC_SAT_ADD(a, b, uint64_t, UINT64_MAX); } static inline uint64_t uc_sat_subu64(uint64_t a, uint64_t b) { return UC_SAT_SUB(a, b, uint64_t); } static inline uint64_t uc_sat_multu64(uint64_t a, uint64_t b) { return UC_SAT_MULT(a, b, uint64_t, UINT64_MAX); } #endif