Adds infinite addition and subtraction to time units.

This prepares for allowing use making arithmetic operators constexpr.

This also makes it easier to use for comparisons with offsets.
Now a > b + 10 ms works even if b is infinite.

Bug: webrtc:9574
Change-Id: Ie36092b72c2ec0f0c541641199a39155f5a796f3
Reviewed-on: https://webrtc-review.googlesource.com/96820
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24530}
diff --git a/api/units/time_delta.h b/api/units/time_delta.h
index b820472..6e69333 100644
--- a/api/units/time_delta.h
+++ b/api/units/time_delta.h
@@ -188,17 +188,35 @@
     return microseconds_ == timedelta_impl::kMinusInfinityVal;
   }
   TimeDelta operator+(const TimeDelta& other) const {
+    if (IsPlusInfinity() || other.IsPlusInfinity()) {
+      RTC_DCHECK(!IsMinusInfinity());
+      RTC_DCHECK(!other.IsMinusInfinity());
+      return PlusInfinity();
+    } else if (IsMinusInfinity() || other.IsMinusInfinity()) {
+      RTC_DCHECK(!IsPlusInfinity());
+      RTC_DCHECK(!other.IsPlusInfinity());
+      return MinusInfinity();
+    }
     return TimeDelta::us(us() + other.us());
   }
   TimeDelta operator-(const TimeDelta& other) const {
+    if (IsPlusInfinity() || other.IsMinusInfinity()) {
+      RTC_DCHECK(!IsMinusInfinity());
+      RTC_DCHECK(!other.IsPlusInfinity());
+      return PlusInfinity();
+    } else if (IsMinusInfinity() || other.IsPlusInfinity()) {
+      RTC_DCHECK(!IsPlusInfinity());
+      RTC_DCHECK(!other.IsMinusInfinity());
+      return MinusInfinity();
+    }
     return TimeDelta::us(us() - other.us());
   }
   TimeDelta& operator-=(const TimeDelta& other) {
-    microseconds_ -= other.us();
+    *this = *this - other;
     return *this;
   }
   TimeDelta& operator+=(const TimeDelta& other) {
-    microseconds_ += other.us();
+    *this = *this + other;
     return *this;
   }
   constexpr double operator/(const TimeDelta& other) const {
diff --git a/api/units/time_delta_unittest.cc b/api/units/time_delta_unittest.cc
index 9eddee7..e5906bf 100644
--- a/api/units/time_delta_unittest.cc
+++ b/api/units/time_delta_unittest.cc
@@ -164,6 +164,26 @@
 
   EXPECT_EQ(TimeDelta::us(-kValueA).Abs().us(), kValueA);
   EXPECT_EQ(TimeDelta::us(kValueA).Abs().us(), kValueA);
+
+  TimeDelta mutable_delta = TimeDelta::ms(kValueA);
+  mutable_delta += TimeDelta::ms(kValueB);
+  EXPECT_EQ(mutable_delta, TimeDelta::ms(kValueA + kValueB));
+  mutable_delta -= TimeDelta::ms(kValueB);
+  EXPECT_EQ(mutable_delta, TimeDelta::ms(kValueA));
+}
+
+TEST(TimeDeltaTest, InfinityOperations) {
+  const int64_t kValue = 267;
+  const TimeDelta finite = TimeDelta::ms(kValue);
+  EXPECT_TRUE((TimeDelta::PlusInfinity() + finite).IsPlusInfinity());
+  EXPECT_TRUE((TimeDelta::PlusInfinity() - finite).IsPlusInfinity());
+  EXPECT_TRUE((finite + TimeDelta::PlusInfinity()).IsPlusInfinity());
+  EXPECT_TRUE((finite - TimeDelta::MinusInfinity()).IsPlusInfinity());
+
+  EXPECT_TRUE((TimeDelta::MinusInfinity() + finite).IsMinusInfinity());
+  EXPECT_TRUE((TimeDelta::MinusInfinity() - finite).IsMinusInfinity());
+  EXPECT_TRUE((finite + TimeDelta::MinusInfinity()).IsMinusInfinity());
+  EXPECT_TRUE((finite - TimeDelta::PlusInfinity()).IsMinusInfinity());
 }
 }  // namespace test
 }  // namespace webrtc
diff --git a/api/units/timestamp.h b/api/units/timestamp.h
index 6e5e392..d7e6a8d 100644
--- a/api/units/timestamp.h
+++ b/api/units/timestamp.h
@@ -162,17 +162,23 @@
     return TimeDelta::us(us() - other.us());
   }
   Timestamp operator-(const TimeDelta& delta) const {
+    RTC_DCHECK(!delta.IsPlusInfinity());
+    if (IsInfinite() || delta.IsMinusInfinity())
+      return Infinity();
     return Timestamp::us(us() - delta.us());
   }
   Timestamp operator+(const TimeDelta& delta) const {
+    RTC_DCHECK(!delta.IsMinusInfinity());
+    if (IsInfinite() || delta.IsPlusInfinity())
+      return Infinity();
     return Timestamp::us(us() + delta.us());
   }
   Timestamp& operator-=(const TimeDelta& other) {
-    microseconds_ -= other.us();
+    *this = *this - other;
     return *this;
   }
   Timestamp& operator+=(const TimeDelta& other) {
-    microseconds_ += other.us();
+    *this = *this + other;
     return *this;
   }
   constexpr bool operator==(const Timestamp& other) const {
diff --git a/api/units/timestamp_unittest.cc b/api/units/timestamp_unittest.cc
index db894cc..ff0c79e 100644
--- a/api/units/timestamp_unittest.cc
+++ b/api/units/timestamp_unittest.cc
@@ -118,10 +118,27 @@
   const Timestamp time_a = Timestamp::ms(kValueA);
   const Timestamp time_b = Timestamp::ms(kValueB);
   const TimeDelta delta_a = TimeDelta::ms(kValueA);
+  const TimeDelta delta_b = TimeDelta::ms(kValueB);
 
   EXPECT_EQ((time_a - time_b), TimeDelta::ms(kValueA - kValueB));
   EXPECT_EQ((time_b - delta_a), Timestamp::ms(kValueB - kValueA));
   EXPECT_EQ((time_b + delta_a), Timestamp::ms(kValueB + kValueA));
+
+  Timestamp mutable_time = time_a;
+  mutable_time += delta_b;
+  EXPECT_EQ(mutable_time, time_a + delta_b);
+  mutable_time -= delta_b;
+  EXPECT_EQ(mutable_time, time_a);
+}
+
+TEST(UnitConversionTest, InfinityOperations) {
+  const int64_t kValue = 267;
+  const Timestamp finite_time = Timestamp::ms(kValue);
+  const TimeDelta finite_delta = TimeDelta::ms(kValue);
+  EXPECT_TRUE((Timestamp::Infinity() + finite_delta).IsInfinite());
+  EXPECT_TRUE((Timestamp::Infinity() - finite_delta).IsInfinite());
+  EXPECT_TRUE((finite_time + TimeDelta::PlusInfinity()).IsInfinite());
+  EXPECT_TRUE((finite_time - TimeDelta::MinusInfinity()).IsInfinite());
 }
 }  // namespace test
 }  // namespace webrtc