diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/sat_arith/sat_arith.h | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/include/sat_arith/sat_arith.h b/include/sat_arith/sat_arith.h new file mode 100644 index 0000000..a05e57f --- /dev/null +++ b/include/sat_arith/sat_arith.h @@ -0,0 +1,142 @@ +#ifndef SAT_ARITH_H +#define SAT_ARITH_H + +#include <limits.h> + +#define ADD_SAT(T, n, l) \ +static inline T add_sat_##n(T x, T y) \ +{ \ + T z; \ + if (!__builtin_add_overflow(x, y, &z)) \ + return z; \ + \ + SAT_ARITH_UNSIGNED( \ + return l##_MAX, \ + \ + if (x < 0) \ + return l##_MIN; \ + else \ + return l##_MAX; \ + ); \ +} + +#define SUB_SAT(T, n, l) \ +static inline T sub_sat_##n(T x, T y) \ +{ \ + T z; \ + if (!__builtin_sub_overflow(x, y, &z)) \ + return z; \ + \ + SAT_ARITH_UNSIGNED( \ + return 0, \ + \ + if (x < 0) \ + return l##_MIN; \ + else \ + return l##_MAX; \ + ); \ +} + +#define MUL_SAT(T, n, l) \ +static inline T mul_sat_##n(T x, T y) \ +{ \ + T z; \ + if (!__builtin_mul_overflow(x, y, &z)) \ + return z; \ + \ + SAT_ARITH_UNSIGNED( \ + return l##_MAX, \ + \ + if ((x < 0) != (y < 0)) \ + return l##_MIN; \ + else \ + return l##_MAX; \ + ); \ +} + +#define SAT_ARITH_UNSIGNED(x, y) y + +ADD_SAT(signed char , char , SCHAR); +ADD_SAT(signed short , short, SHRT); +ADD_SAT(signed int , int , INT); +ADD_SAT(signed long , long , LONG); +ADD_SAT(signed long long, llong, LLONG); + +SUB_SAT(signed char , char , SCHAR); +SUB_SAT(signed short , short, SHRT); +SUB_SAT(signed int , int , INT); +SUB_SAT(signed long , long , LONG); +SUB_SAT(signed long long, llong, LLONG); + +MUL_SAT(signed char , char , SCHAR); +MUL_SAT(signed short , short, SHRT); +MUL_SAT(signed int , int , INT); +MUL_SAT(signed long , long , LONG); +MUL_SAT(signed long long, llong, LLONG); + +#undef SAT_ARITH_UNSIGNED +#define SAT_ARITH_UNSIGNED(x, y) x + +ADD_SAT(unsigned char , uchar , UCHAR); +ADD_SAT(unsigned short , ushort, USHRT); +ADD_SAT(unsigned int , uint , UINT); +ADD_SAT(unsigned long , ulong , ULONG); +ADD_SAT(unsigned long long, ullong, ULLONG); + +SUB_SAT(unsigned char , uchar , UCHAR); +SUB_SAT(unsigned short , ushort, USHRT); +SUB_SAT(unsigned int , uint , UINT); +SUB_SAT(unsigned long , ulong , ULONG); +SUB_SAT(unsigned long long, ullong, ULLONG); + +MUL_SAT(unsigned char , uchar , UCHAR); +MUL_SAT(unsigned short , ushort, USHRT); +MUL_SAT(unsigned int , uint , UINT); +MUL_SAT(unsigned long , ulong , ULONG); +MUL_SAT(unsigned long long, ullong, ULLONG); + +#undef SAT_ARITH_UNSIGNED + +#define add_sat(x, y) \ + _Generic((x), \ + signed char : add_sat_char,\ + signed short : add_sat_short,\ + signed int : add_sat_short,\ + signed long : add_sat_long,\ + signed long long : add_sat_llong,\ + unsigned char : add_sat_uchar,\ + unsigned short : add_sat_ushort,\ + unsigned int : add_sat_ushort,\ + unsigned long : add_sat_ulong,\ + unsigned long long: add_sat_ullong\ + )(x, y) + +#define sub_sat(x, y) \ + _Generic((x), \ + signed char : sub_sat_char,\ + signed short : sub_sat_short,\ + signed int : sub_sat_short,\ + signed long : sub_sat_long,\ + signed long long : sub_sat_llong,\ + unsigned char : sub_sat_uchar,\ + unsigned short : sub_sat_ushort,\ + unsigned int : sub_sat_ushort,\ + unsigned long : sub_sat_ulong,\ + unsigned long long: sub_sat_ullong\ + )(x, y) + +#define mul_sat(x, y) \ + _Generic((x), \ + signed char : mul_sat_char,\ + signed short : mul_sat_short,\ + signed int : mul_sat_short,\ + signed long : mul_sat_long,\ + signed long long : mul_sat_llong,\ + unsigned char : mul_sat_uchar,\ + unsigned short : mul_sat_ushort,\ + unsigned int : mul_sat_ushort,\ + unsigned long : mul_sat_ulong,\ + unsigned long long: mul_sat_ullong\ + )(x, y) + +#endif /* SAT_ARITH_H */ |