aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/sat_arith/sat_arith.h142
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 */