From de7aadca8c8ae8a4bdddc3197b1ddc850f64bdec Mon Sep 17 00:00:00 2001
From: Dale Curtis <dalecurtis@chromium.org>
Date: Thu, 30 Apr 2020 15:16:31 -0700
Subject: [PATCH] Add saturated add/sub operations for int64_t.

Many places are using their own custom code for handling overflow
around timestamps or other int64_t values. There are enough of these
now that having some common saturated math functions seems sound.

This adds implementations that just use the builtin functions for
recent gcc, clang when available or implements its own version for
older compilers.

Signed-off-by: Dale Curtis <dalecurtis@chromium.org>
---
 libavutil/common.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/libavutil/common.h b/libavutil/common.h
index 142ff9abe7..1fcbfbc03a 100644
--- a/libavutil/common.h
+++ b/libavutil/common.h
@@ -291,6 +291,46 @@ static av_always_inline int av_sat_dsub32_c(int a, int b)
     return av_sat_sub32(a, av_sat_add32(b, b));
 }
 
+/**
+ * Add two signed 64-bit values with saturation.
+ *
+ * @param  a one value
+ * @param  b another value
+ * @return sum with signed saturation
+ */
+static int64_t av_sat_add64_c(int64_t a, int64_t b) {
+#if AV_GCC_VERSION_AT_LEAST(5,0) || defined(__clang__)
+  int64_t tmp;
+  return !__builtin_add_overflow(a, b, &tmp) ? tmp : (tmp < 0 ? INT64_MAX : INT64_MIN);
+#else
+  if (b >= 0 && a >= INT64_MAX - b)
+    return INT64_MAX;
+  if (b <= 0 && a <= INT64_MIN - b)
+    return INT64_MIN;
+  return a + b;
+#endif
+}
+
+/**
+ * Subtract two signed 64-bit values with saturation.
+ *
+ * @param  a one value
+ * @param  b another value
+ * @return difference with signed saturation
+ */
+static int64_t av_sat_sub64_c(int64_t a, int64_t b) {
+#if AV_GCC_VERSION_AT_LEAST(5,0) || defined(__clang__)
+  int64_t tmp;
+  return !__builtin_sub_overflow(a, b, &tmp) ? tmp : (tmp < 0 ? INT64_MAX : INT64_MIN);
+#else
+  if (b <= 0 && a >= INT64_MAX + b) {
+    return INT64_MAX;
+  if (b >= 0 && a <= INT64_MIN + b) {
+    return INT64_MIN;
+  return a - b;
+#endif
+}
+
 /**
  * Clip a float value into the amin-amax range.
  * @param a value to clip
@@ -545,6 +585,12 @@ static av_always_inline av_const int av_parity_c(uint32_t v)
 #ifndef av_sat_dsub32
 #   define av_sat_dsub32    av_sat_dsub32_c
 #endif
+#ifndef av_sat_add64
+#   define av_sat_add64     av_sat_add64_c
+#endif
+#ifndef av_sat_sub64
+#   define av_sat_sub64     av_sat_sub64_c
+#endif
 #ifndef av_clipf
 #   define av_clipf         av_clipf_c
 #endif
-- 
2.24.1.windows.2

