Bug 1163445: Part2. Add TimeUnit infinity concept. r=mattwoodrow
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 18 May 2015 16:13:20 +1000
changeset 244319 d71d9f13a37d709817041b66e1fd782084a6de4c
parent 244318 4c86cc335c316f190a3b1dc1807f8b6d23cfb86c
child 244320 7cc62c82bb10460da898ddcc7bd904b6838c5440
push id28773
push usercbook@mozilla.com
push dateMon, 18 May 2015 11:43:50 +0000
treeherdermozilla-central@f578b845c4b8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1163445
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1163445: Part2. Add TimeUnit infinity concept. r=mattwoodrow We use the value INT64_MAX as meaning infinity. This allows to avoid taking more storage space than necessary but may result in unpredictable behaviour when performing calculations.
dom/media/TimeUnits.h
dom/media/gtest/TestIntervalSet.cpp
--- a/dom/media/TimeUnits.h
+++ b/dom/media/TimeUnits.h
@@ -56,21 +56,26 @@ struct Microseconds {
   }
   bool operator <= (const Microseconds& aOther) const {
     return mValue <= aOther.mValue;
   }
 
   int64_t mValue;
 };
 
+// TimeUnit at present uses a CheckedInt64 as storage.
+// INT64_MAX has the special meaning of being +oo.
 class TimeUnit final {
 public:
   static TimeUnit FromSeconds(double aValue) {
     MOZ_ASSERT(!IsNaN(aValue));
 
+    if (mozilla::IsInfinite<double>(aValue)) {
+      return FromInfinity();
+    }
     double val = aValue * USECS_PER_S;
     if (val >= double(INT64_MAX)) {
       return FromMicroseconds(INT64_MAX);
     } else if (val <= double(INT64_MIN)) {
       return FromMicroseconds(INT64_MIN);
     } else {
       return FromMicroseconds(int64_t(val));
     }
@@ -79,24 +84,35 @@ public:
   static TimeUnit FromMicroseconds(int64_t aValue) {
     return TimeUnit(aValue);
   }
 
   static TimeUnit FromMicroseconds(Microseconds aValue) {
     return TimeUnit(aValue.mValue);
   }
 
+  static TimeUnit FromInfinity() {
+    return TimeUnit(INT64_MAX);
+  }
+
   int64_t ToMicroseconds() const {
     return mValue.value();
   }
 
   double ToSeconds() const {
+    if (IsInfinite()) {
+      return PositiveInfinity<double>();
+    }
     return double(mValue.value()) / USECS_PER_S;
   }
 
+  bool IsInfinite() const {
+    return mValue.value() == INT64_MAX;
+  }
+
   bool operator == (const TimeUnit& aOther) const {
     MOZ_ASSERT(IsValid() && aOther.IsValid());
     return mValue.value() == aOther.mValue.value();
   }
   bool operator >= (const TimeUnit& aOther) const {
     MOZ_ASSERT(IsValid() && aOther.IsValid());
     return mValue.value() >= aOther.mValue.value();
   }
@@ -106,19 +122,26 @@ public:
   bool operator <= (const TimeUnit& aOther) const {
     MOZ_ASSERT(IsValid() && aOther.IsValid());
     return mValue.value() <= aOther.mValue.value();
   }
   bool operator < (const TimeUnit& aOther) const {
     return !(*this >= aOther);
   }
   TimeUnit operator + (const TimeUnit& aOther) const {
+    if (IsInfinite() || aOther.IsInfinite()) {
+      return FromInfinity();
+    }
     return TimeUnit(mValue + aOther.mValue);
   }
   TimeUnit operator - (const TimeUnit& aOther) const {
+    if (IsInfinite() && !aOther.IsInfinite()) {
+      return FromInfinity();
+    }
+    MOZ_ASSERT(!IsInfinite() && !aOther.IsInfinite());
     return TimeUnit(mValue - aOther.mValue);
   }
 
   bool IsValid() const
   {
     return mValue.isValid();
   }
 
--- a/dom/media/gtest/TestIntervalSet.cpp
+++ b/dom/media/gtest/TestIntervalSet.cpp
@@ -510,16 +510,30 @@ TEST(IntervalSet, TimeRangesMicroseconds
   EXPECT_EQ(tr->Length(), i.Length());
   for (dom::TimeRanges::index_type index = 0; index < tr->Length(); index++) {
     ErrorResult rv;
     EXPECT_EQ(tr->Start(index, rv), i[index].mStart.ToSeconds());
     EXPECT_EQ(tr->Start(index, rv), i.Start(index).ToSeconds());
     EXPECT_EQ(tr->End(index, rv), i[index].mEnd.ToSeconds());
     EXPECT_EQ(tr->End(index, rv), i.End(index).ToSeconds());
   }
+
+  // Check infinity values aren't lost in the conversion.
+  tr = new dom::TimeRanges();
+  tr->Add(0, 30);
+  tr->Add(50, std::numeric_limits<double>::infinity());
+  media::TimeIntervals i_oo{media::TimeIntervals::FromTimeRanges(tr)};
+  nsRefPtr<dom::TimeRanges> tr2 = new dom::TimeRanges();
+  i_oo.ToTimeRanges(tr2);
+  EXPECT_EQ(tr->Length(), tr2->Length());
+  for (dom::TimeRanges::index_type index = 0; index < tr->Length(); index++) {
+    ErrorResult rv;
+    EXPECT_EQ(tr->Start(index, rv), tr2->Start(index, rv));
+    EXPECT_EQ(tr->End(index, rv), tr2->End(index, rv));
+  }
 }
 
 template<typename T>
 class Foo
 {
 public:
   Foo()
     : mArg1(1)