Bug 1039924 part 3 - Templatize TimeDuration so it can support different behaviors with regards to tick count arithmetic; r=froydnj
authorBrian Birtles <birtles@gmail.com>
Thu, 25 Sep 2014 14:25:49 +0900
changeset 230366 af942cc33a8385e684ecc850f74af424482211b3
parent 230365 cef7118a25cb3dfb378eb46eb7e01201e44948e0
child 230367 82fbeb45b3d6bb6560ca4ee15138dcc46a2982bf
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1039924
milestone35.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 1039924 part 3 - Templatize TimeDuration so it can support different behaviors with regards to tick count arithmetic; r=froydnj This patch prepares the way for having a separate StickyTimeDuration class by factoring TimeDuration into a templated base class: BaseTimeDuration. BaseTimeDuration takes a templated parameter, ValueCalculator, which is a helper object that defines how various arithmetic operations are performed on its mValue member (an int64_t count of ticks). This patch does not actually define or use the ValueCalculator parameter yet but simply performs the renaming and templatization. With regards to the templatization, arithmetic operators are defined to take objects with the same ValueCalculator template parameter (so that we don't, for example, apply non-safe arithmetic to a StickyTimeDuration). However, comparison operators are defined to also operate on objects with a different ValueCalculator template parameter since comparison should be independent of the type of arithmetic used. Likewise, the constructor and assignment operator are defined to operate on objects with a different ValueCalculator template parameter so that objects can be converted from TimeDuration to StickyTimeDuration and vice-versa. The constructor is marked as explicit, however, so that we don't silently convert a StickyTimeDuration to a TimeDuration and unwittingly apply non-safe arithmetic to a StickyTimeDuration. TimeDuration is defined as a specialization of BaseTimeDuration that uses TimeDurationValueCalculator as its ValueCalculator type. TimeDurationValueCalculator is filled-in in a subsequent patch.
xpcom/ds/TimeStamp.h
xpcom/ds/TimeStamp_darwin.cpp
xpcom/ds/TimeStamp_posix.cpp
xpcom/ds/TimeStamp_windows.cpp
--- a/xpcom/ds/TimeStamp.h
+++ b/xpcom/ds/TimeStamp.h
@@ -28,19 +28,19 @@ namespace mozilla {
 
 #ifndef XP_WIN
 typedef uint64_t TimeStampValue;
 #endif
 
 class TimeStamp;
 
 /**
- * Platform-specific implementation details of TimeDuration.
+ * Platform-specific implementation details of BaseTimeDuration.
  */
-class TimeDurationPlatformUtils
+class BaseTimeDurationPlatformUtils
 {
 public:
   static double ToSeconds(int64_t aTicks);
   static double ToSecondsSigDigits(int64_t aTicks);
   static int64_t TicksFromMilliseconds(double aMilliseconds);
   static int64_t ResolutionInTicks();
 };
 
@@ -48,221 +48,252 @@ public:
  * Instances of this class represent the length of an interval of time.
  * Negative durations are allowed, meaning the end is before the start.
  *
  * Internally the duration is stored as a int64_t in units of
  * PR_TicksPerSecond() when building with NSPR interval timers, or a
  * system-dependent unit when building with system clocks.  The
  * system-dependent unit must be constant, otherwise the semantics of
  * this class would be broken.
+ *
+ * The ValueCalculator template parameter determines how arithmetic
+ * operations are performed on the integer count of ticks (mValue).
  */
-class TimeDuration
+template <typename ValueCalculator>
+class BaseTimeDuration
 {
 public:
   // The default duration is 0.
-  MOZ_CONSTEXPR TimeDuration() : mValue(0) {}
+  MOZ_CONSTEXPR BaseTimeDuration() : mValue(0) {}
   // Allow construction using '0' as the initial value, for readability,
   // but no other numbers (so we don't have any implicit unit conversions).
   struct _SomethingVeryRandomHere;
-  MOZ_IMPLICIT TimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0)
+  MOZ_IMPLICIT BaseTimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0)
   {
     MOZ_ASSERT(!aZero, "Who's playing funny games here?");
   }
   // Default copy-constructor and assignment are OK
 
+  // Converting copy-constructor and assignment operator
+  template <typename E>
+  explicit BaseTimeDuration(const BaseTimeDuration<E>& aOther)
+    : mValue(aOther.mValue)
+  { }
+
+  template <typename E>
+  BaseTimeDuration& operator=(const BaseTimeDuration<E>& aOther)
+  {
+    mValue = aOther.mValue;
+    return *this;
+  }
+
   double ToSeconds() const
   {
     if (mValue == INT64_MAX) {
       return PositiveInfinity<double>();
     }
     if (mValue == INT64_MIN) {
       return NegativeInfinity<double>();
     }
-    return TimeDurationPlatformUtils::ToSeconds(mValue);
+    return BaseTimeDurationPlatformUtils::ToSeconds(mValue);
   }
   // Return a duration value that includes digits of time we think to
   // be significant.  This method should be used when displaying a
   // time to humans.
   double ToSecondsSigDigits() const
   {
     if (mValue == INT64_MAX) {
       return PositiveInfinity<double>();
     }
     if (mValue == INT64_MIN) {
       return NegativeInfinity<double>();
     }
-    return TimeDurationPlatformUtils::ToSecondsSigDigits(mValue);
+    return BaseTimeDurationPlatformUtils::ToSecondsSigDigits(mValue);
   }
   double ToMilliseconds() const { return ToSeconds() * 1000.0; }
   double ToMicroseconds() const { return ToMilliseconds() * 1000.0; }
 
   // Using a double here is safe enough; with 53 bits we can represent
   // durations up to over 280,000 years exactly.  If the units of
   // mValue do not allow us to represent durations of that length,
   // long durations are clamped to the max/min representable value
   // instead of overflowing.
-  static inline TimeDuration FromSeconds(double aSeconds)
+  static inline BaseTimeDuration FromSeconds(double aSeconds)
   {
     return FromMilliseconds(aSeconds * 1000.0);
   }
-  static TimeDuration FromMilliseconds(double aMilliseconds)
+  static BaseTimeDuration FromMilliseconds(double aMilliseconds)
   {
     if (aMilliseconds == PositiveInfinity<double>()) {
       return Forever();
     }
     if (aMilliseconds == NegativeInfinity<double>()) {
       return FromTicks(INT64_MIN);
     }
     return FromTicks(
-      TimeDurationPlatformUtils::TicksFromMilliseconds(aMilliseconds));
+      BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aMilliseconds));
   }
-  static inline TimeDuration FromMicroseconds(double aMicroseconds)
+  static inline BaseTimeDuration FromMicroseconds(double aMicroseconds)
   {
     return FromMilliseconds(aMicroseconds / 1000.0);
   }
 
-  static TimeDuration Forever()
+  static BaseTimeDuration Forever()
   {
     return FromTicks(INT64_MAX);
   }
 
-  TimeDuration operator+(const TimeDuration& aOther) const
+  BaseTimeDuration operator+(const BaseTimeDuration& aOther) const
   {
-    return TimeDuration::FromTicks(mValue + aOther.mValue);
+    return FromTicks(mValue + aOther.mValue);
   }
-  TimeDuration operator-(const TimeDuration& aOther) const
+  BaseTimeDuration operator-(const BaseTimeDuration& aOther) const
   {
-    return TimeDuration::FromTicks(mValue - aOther.mValue);
+    return FromTicks(mValue - aOther.mValue);
   }
-  TimeDuration& operator+=(const TimeDuration& aOther)
+  BaseTimeDuration& operator+=(const BaseTimeDuration& aOther)
   {
     mValue += aOther.mValue;
     return *this;
   }
-  TimeDuration& operator-=(const TimeDuration& aOther)
+  BaseTimeDuration& operator-=(const BaseTimeDuration& aOther)
   {
     mValue -= aOther.mValue;
     return *this;
   }
 
 private:
   // Block double multiplier (slower, imprecise if long duration) - Bug 853398.
   // If required, use MultDouble explicitly and with care.
-  TimeDuration operator*(const double aMultiplier) const MOZ_DELETE;
+  BaseTimeDuration operator*(const double aMultiplier) const MOZ_DELETE;
 
 public:
-  TimeDuration MultDouble(double aMultiplier) const
+  BaseTimeDuration MultDouble(double aMultiplier) const
   {
-    return TimeDuration::FromTicks(static_cast<int64_t>(mValue * aMultiplier));
+    return FromTicks(static_cast<int64_t>(mValue * aMultiplier));
   }
-  TimeDuration operator*(const int32_t aMultiplier) const
+  BaseTimeDuration operator*(const int32_t aMultiplier) const
   {
-    return TimeDuration::FromTicks(mValue * int64_t(aMultiplier));
+    return FromTicks(mValue * int64_t(aMultiplier));
   }
-  TimeDuration operator*(const uint32_t aMultiplier) const
+  BaseTimeDuration operator*(const uint32_t aMultiplier) const
   {
-    return TimeDuration::FromTicks(mValue * int64_t(aMultiplier));
+    return FromTicks(mValue * int64_t(aMultiplier));
   }
-  TimeDuration operator*(const int64_t aMultiplier) const
+  BaseTimeDuration operator*(const int64_t aMultiplier) const
   {
-    return TimeDuration::FromTicks(mValue * aMultiplier);
+    return FromTicks(mValue * aMultiplier);
   }
-  TimeDuration operator*(const uint64_t aMultiplier) const
+  BaseTimeDuration operator*(const uint64_t aMultiplier) const
   {
     if (aMultiplier > INT64_MAX) {
-      NS_WARNING("Out-of-range multiplier when multiplying TimeDuration");
-      return TimeDuration::Forever();
+      NS_WARNING("Out-of-range multiplier when multiplying BaseTimeDuration");
+      return Forever();
     }
-    return TimeDuration::FromTicks(mValue * int64_t(aMultiplier));
+    return FromTicks(mValue * int64_t(aMultiplier));
   }
-  TimeDuration operator/(const int64_t aDivisor) const
+  BaseTimeDuration operator/(const int64_t aDivisor) const
   {
-    return TimeDuration::FromTicks(mValue / aDivisor);
+    return FromTicks(mValue / aDivisor);
   }
-  double operator/(const TimeDuration& aOther) const
+  double operator/(const BaseTimeDuration& aOther) const
   {
     return static_cast<double>(mValue) / aOther.mValue;
   }
-  TimeDuration operator%(const TimeDuration& aOther) const
+  BaseTimeDuration operator%(const BaseTimeDuration& aOther) const
   {
     MOZ_ASSERT(aOther.mValue != 0, "Division by zero");
-    return TimeDuration::FromTicks(mValue % aOther.mValue);
+    return FromTicks(mValue % aOther.mValue);
   }
 
-  bool operator<(const TimeDuration& aOther) const
+  template<typename E>
+  bool operator<(const BaseTimeDuration<E>& aOther) const
   {
     return mValue < aOther.mValue;
   }
-  bool operator<=(const TimeDuration& aOther) const
+  template<typename E>
+  bool operator<=(const BaseTimeDuration<E>& aOther) const
   {
     return mValue <= aOther.mValue;
   }
-  bool operator>=(const TimeDuration& aOther) const
+  template<typename E>
+  bool operator>=(const BaseTimeDuration<E>& aOther) const
   {
     return mValue >= aOther.mValue;
   }
-  bool operator>(const TimeDuration& aOther) const
+  template<typename E>
+  bool operator>(const BaseTimeDuration<E>& aOther) const
   {
     return mValue > aOther.mValue;
   }
-  bool operator==(const TimeDuration& aOther) const
+  template<typename E>
+  bool operator==(const BaseTimeDuration<E>& aOther) const
   {
     return mValue == aOther.mValue;
   }
-  bool operator!=(const TimeDuration& aOther) const
+  template<typename E>
+  bool operator!=(const BaseTimeDuration<E>& aOther) const
   {
     return mValue != aOther.mValue;
   }
 
   // Return a best guess at the system's current timing resolution,
-  // which might be variable.  TimeDurations below this order of
+  // which might be variable.  BaseTimeDurations below this order of
   // magnitude are meaningless, and those at the same order of
   // magnitude or just above are suspect.
-  static TimeDuration Resolution() {
-    return FromTicks(TimeDurationPlatformUtils::ResolutionInTicks());
+  static BaseTimeDuration Resolution() {
+    return FromTicks(BaseTimeDurationPlatformUtils::ResolutionInTicks());
   }
 
   // We could define additional operators here:
   // -- convert to/from other time units
   // -- scale duration by a float
   // but let's do that on demand.
   // Comparing durations for equality will only lead to bugs on
   // platforms with high-resolution timers.
 
 private:
   friend class TimeStamp;
-  friend struct IPC::ParamTraits<mozilla::TimeDuration>;
+  friend struct IPC::ParamTraits<mozilla::BaseTimeDuration<ValueCalculator>>;
+  template <typename>
+  friend class BaseTimeDuration;
 
-  static TimeDuration FromTicks(int64_t aTicks)
+  static BaseTimeDuration FromTicks(int64_t aTicks)
   {
-    TimeDuration t;
+    BaseTimeDuration t;
     t.mValue = aTicks;
     return t;
   }
 
-  static TimeDuration FromTicks(double aTicks)
+  static BaseTimeDuration FromTicks(double aTicks)
   {
     // NOTE: this MUST be a >= test, because int64_t(double(INT64_MAX))
     // overflows and gives INT64_MIN.
     if (aTicks >= double(INT64_MAX)) {
-      return TimeDuration::FromTicks(INT64_MAX);
+      return FromTicks(INT64_MAX);
     }
 
     // This MUST be a <= test.
     if (aTicks <= double(INT64_MIN)) {
-      return TimeDuration::FromTicks(INT64_MIN);
+      return FromTicks(INT64_MIN);
     }
 
-    return TimeDuration::FromTicks(int64_t(aTicks));
+    return FromTicks(int64_t(aTicks));
   }
 
   // Duration, result is implementation-specific difference of two TimeStamps
   int64_t mValue;
 };
 
+// FIXME: To be filled-in a subsequent patch in this series.
+class TimeDurationValueCalculator
+{ };
+
+typedef BaseTimeDuration<TimeDurationValueCalculator> TimeDuration;
+
 /**
  * Instances of this class represent moments in time, or a special
  * "null" moment. We do not use the non-monotonic system clock or
  * local time, since they can be reset, causing apparent backward
  * travel in time, which can confuse algorithms. Instead we measure
  * elapsed time according to the system.  This time can never go
  * backwards (i.e. it never wraps around, at least not in less than
  * five million years of system elapsed time). It might not advance
--- a/xpcom/ds/TimeStamp_darwin.cpp
+++ b/xpcom/ds/TimeStamp_darwin.cpp
@@ -77,42 +77,42 @@ ClockResolutionNs()
   }
 
   return minres;
 }
 
 namespace mozilla {
 
 double
-TimeDurationPlatformUtils::ToSeconds(int64_t aTicks)
+BaseTimeDurationPlatformUtils::ToSeconds(int64_t aTicks)
 {
   NS_ABORT_IF_FALSE(gInitialized, "calling TimeDuration too early");
   return (aTicks * sNsPerTick) / kNsPerSecd;
 }
 
 double
-TimeDurationPlatformUtils::ToSecondsSigDigits(int64_t aTicks)
+BaseTimeDurationPlatformUtils::ToSecondsSigDigits(int64_t aTicks)
 {
   NS_ABORT_IF_FALSE(gInitialized, "calling TimeDuration too early");
   // don't report a value < mResolution ...
   int64_t valueSigDigs = sResolution * (aTicks / sResolution);
   // and chop off insignificant digits
   valueSigDigs = sResolutionSigDigs * (valueSigDigs / sResolutionSigDigs);
   return (valueSigDigs * sNsPerTick) / kNsPerSecd;
 }
 
 int64_t
-TimeDurationPlatformUtils::TicksFromMilliseconds(double aMilliseconds)
+BaseTimeDurationPlatformUtils::TicksFromMilliseconds(double aMilliseconds)
 {
   NS_ABORT_IF_FALSE(gInitialized, "calling TimeDuration too early");
   return (aMilliseconds * kNsPerMsd) / sNsPerTick;
 }
 
 int64_t
-TimeDurationPlatformUtils::ResolutionInTicks()
+BaseTimeDurationPlatformUtils::ResolutionInTicks()
 {
   NS_ABORT_IF_FALSE(gInitialized, "calling TimeDuration too early");
   return static_cast<int64_t>(sResolution);
 }
 
 nsresult
 TimeStamp::Startup()
 {
--- a/xpcom/ds/TimeStamp_posix.cpp
+++ b/xpcom/ds/TimeStamp_posix.cpp
@@ -129,39 +129,39 @@ ClockResolutionNs()
   }
 
   return minres;
 }
 
 namespace mozilla {
 
 double
-TimeDurationPlatformUtils::ToSeconds(int64_t aTicks)
+BaseTimeDurationPlatformUtils::ToSeconds(int64_t aTicks)
 {
   return double(aTicks) / kNsPerSecd;
 }
 
 double
-TimeDurationPlatformUtils::ToSecondsSigDigits(int64_t aTicks)
+BaseTimeDurationPlatformUtils::ToSecondsSigDigits(int64_t aTicks)
 {
   // don't report a value < mResolution ...
   int64_t valueSigDigs = sResolution * (aTicks / sResolution);
   // and chop off insignificant digits
   valueSigDigs = sResolutionSigDigs * (valueSigDigs / sResolutionSigDigs);
   return double(valueSigDigs) / kNsPerSecd;
 }
 
 int64_t
-TimeDurationPlatformUtils::TicksFromMilliseconds(double aMilliseconds)
+BaseTimeDurationPlatformUtils::TicksFromMilliseconds(double aMilliseconds)
 {
   return aMilliseconds * kNsPerMsd;
 }
 
 int64_t
-TimeDurationPlatformUtils::ResolutionInTicks()
+BaseTimeDurationPlatformUtils::ResolutionInTicks()
 {
   return static_cast<int64_t>(sResolution);
 }
 
 static bool gInitialized = false;
 
 nsresult
 TimeStamp::Startup()
--- a/xpcom/ds/TimeStamp_windows.cpp
+++ b/xpcom/ds/TimeStamp_windows.cpp
@@ -408,42 +408,42 @@ TimeStampValue::operator-(const TimeStam
   return CheckQPC(aOther);
 }
 
 // ----------------------------------------------------------------------------
 // TimeDuration and TimeStamp implementation
 // ----------------------------------------------------------------------------
 
 double
-TimeDurationPlatformUtils::ToSeconds(int64_t aTicks)
+BaseTimeDurationPlatformUtils::ToSeconds(int64_t aTicks)
 {
   // Converting before arithmetic avoids blocked store forward
   return double(aTicks) / (double(sFrequencyPerSec) * 1000.0);
 }
 
 double
-TimeDurationPlatformUtils::ToSecondsSigDigits(int64_t aTicks)
+BaseTimeDurationPlatformUtils::ToSecondsSigDigits(int64_t aTicks)
 {
   // don't report a value < mResolution ...
   LONGLONG resolution = sResolution;
   LONGLONG resolutionSigDigs = sResolutionSigDigs;
   LONGLONG valueSigDigs = resolution * (aTicks / resolution);
   // and chop off insignificant digits
   valueSigDigs = resolutionSigDigs * (valueSigDigs / resolutionSigDigs);
   return double(valueSigDigs) / kNsPerSecd;
 }
 
 int64_t
-TimeDurationPlatformUtils::TicksFromMilliseconds(double aMilliseconds)
+BaseTimeDurationPlatformUtils::TicksFromMilliseconds(double aMilliseconds)
 {
   return ms2mt(aMilliseconds);
 }
 
 int64_t
-TimeDurationPlatformUtils::ResolutionInTicks()
+BaseTimeDurationPlatformUtils::ResolutionInTicks()
 {
   return static_cast<int64_t>(sResolution);
 }
 
 static bool
 HasStableTSC()
 {
   union