 Chromium Code Reviews
 Chromium Code Reviews Issue 1952843002:
  Create TimeBase for time related classes.  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master
    
  
    Issue 1952843002:
  Create TimeBase for time related classes.  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master| Index: src/base/platform/time.h | 
| diff --git a/src/base/platform/time.h b/src/base/platform/time.h | 
| index c8140efe4a50ba9a23802267adeba271400f20b0..c720a138da4a25476fb7c30ddcd0764ea26107eb 100644 | 
| --- a/src/base/platform/time.h | 
| +++ b/src/base/platform/time.h | 
| @@ -10,6 +10,7 @@ | 
| #include <limits> | 
| #include "src/base/macros.h" | 
| +#include "src/base/safe_math.h" | 
| // Forward declarations. | 
| extern "C" { | 
| @@ -23,8 +24,22 @@ namespace v8 { | 
| namespace base { | 
| class Time; | 
| +class TimeDelta; | 
| class TimeTicks; | 
| +namespace time_internal { | 
| + | 
| +// Add or subtract |value| from a TimeDelta. The int64_t argument and return | 
| +// value are in terms of a microsecond timebase. | 
| +int64_t SaturatedAdd(TimeDelta delta, int64_t value); | 
| 
Benedikt Meurer
2016/05/06 04:15:06
Can you move these to base/bits.{h,cc} instead as
 
lpy
2016/05/06 05:09:08
Done.
 | 
| +int64_t SaturatedSub(TimeDelta delta, int64_t value); | 
| + | 
| +// Clamp |value| on overflow and underflow conditions. The int64_t argument and | 
| +// return value are in terms of a microsecond timebase. | 
| +int64_t FromCheckedNumeric(const CheckedNumeric<int64_t> value); | 
| + | 
| +} // namespace time_internal | 
| + | 
| // ----------------------------------------------------------------------------- | 
| // TimeDelta | 
| // | 
| @@ -143,6 +158,9 @@ class TimeDelta final { | 
| } | 
| private: | 
| + friend int64_t time_internal::SaturatedAdd(TimeDelta delta, int64_t value); | 
| + friend int64_t time_internal::SaturatedSub(TimeDelta delta, int64_t value); | 
| + | 
| // Constructs a delta given the duration in microseconds. This is private | 
| // to avoid confusion by callers with an integer constructor. Use | 
| // FromSeconds, FromMilliseconds, etc. instead. | 
| @@ -153,35 +171,123 @@ class TimeDelta final { | 
| }; | 
| -// ----------------------------------------------------------------------------- | 
| -// Time | 
| -// | 
| -// This class represents an absolute point in time, internally represented as | 
| -// microseconds (s/1,000,000) since 00:00:00 UTC, January 1, 1970. | 
| +namespace time_internal { | 
| + | 
| +// TimeBase-------------------------------------------------------------------- | 
| -class Time final { | 
| +// Provides value storage and comparison/math operations common to all time | 
| +// classes. Each subclass provides for strong type-checking to ensure | 
| +// semantically meaningful comparison/math of time values from the same clock | 
| +// source or timeline. | 
| +template<class TimeClass> | 
| +class TimeBase { | 
| public: | 
| + static const int64_t kHoursPerDay = 24; | 
| static const int64_t kMillisecondsPerSecond = 1000; | 
| + static const int64_t kMillisecondsPerDay = | 
| + kMillisecondsPerSecond * 60 * 60 * kHoursPerDay; | 
| static const int64_t kMicrosecondsPerMillisecond = 1000; | 
| - static const int64_t kMicrosecondsPerSecond = kMicrosecondsPerMillisecond * | 
| - kMillisecondsPerSecond; | 
| + static const int64_t kMicrosecondsPerSecond = | 
| + kMicrosecondsPerMillisecond * kMillisecondsPerSecond; | 
| static const int64_t kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60; | 
| static const int64_t kMicrosecondsPerHour = kMicrosecondsPerMinute * 60; | 
| - static const int64_t kMicrosecondsPerDay = kMicrosecondsPerHour * 24; | 
| + static const int64_t kMicrosecondsPerDay = | 
| + kMicrosecondsPerHour * kHoursPerDay; | 
| static const int64_t kMicrosecondsPerWeek = kMicrosecondsPerDay * 7; | 
| static const int64_t kNanosecondsPerMicrosecond = 1000; | 
| - static const int64_t kNanosecondsPerSecond = kNanosecondsPerMicrosecond * | 
| - kMicrosecondsPerSecond; | 
| - | 
| - // Contains the NULL time. Use Time::Now() to get the current time. | 
| - Time() : us_(0) {} | 
| + static const int64_t kNanosecondsPerSecond = | 
| + kNanosecondsPerMicrosecond * kMicrosecondsPerSecond; | 
| - // Returns true if the time object has not been initialized. | 
| - bool IsNull() const { return us_ == 0; } | 
| + // Returns true if this object has not been initialized. | 
| + // | 
| + // Warning: Be careful when writing code that performs math on time values, | 
| + // since it's possible to produce a valid "zero" result that should not be | 
| + // interpreted as a "null" value. | 
| + bool IsNull() const { | 
| + return us_ == 0; | 
| + } | 
| - // Returns true if the time object is the maximum time. | 
| + // Returns true if this object represents the maximum time. | 
| bool IsMax() const { return us_ == std::numeric_limits<int64_t>::max(); } | 
| + // For serializing only. Use FromInternalValue() to reconstitute. Please don't | 
| + // use this and do arithmetic on it, as it is more error prone than using the | 
| + // provided operators. | 
| + int64_t ToInternalValue() const { return us_; } | 
| + | 
| + TimeClass& operator=(TimeClass other) { | 
| + us_ = other.us_; | 
| + return *(static_cast<TimeClass*>(this)); | 
| + } | 
| + | 
| + // Compute the difference between two times. | 
| + TimeDelta operator-(TimeClass other) const { | 
| + return TimeDelta::FromMicroseconds(us_ - other.us_); | 
| + } | 
| + | 
| + // Return a new time modified by some delta. | 
| + TimeClass operator+(TimeDelta delta) const { | 
| + return TimeClass(time_internal::SaturatedAdd(delta, us_)); | 
| + } | 
| + TimeClass operator-(TimeDelta delta) const { | 
| + return TimeClass(-time_internal::SaturatedSub(delta, us_)); | 
| + } | 
| + | 
| + // Modify by some time delta. | 
| + TimeClass& operator+=(TimeDelta delta) { | 
| + return static_cast<TimeClass&>(*this = (*this + delta)); | 
| + } | 
| + TimeClass& operator-=(TimeDelta delta) { | 
| + return static_cast<TimeClass&>(*this = (*this - delta)); | 
| + } | 
| + | 
| + // Comparison operators | 
| + bool operator==(TimeClass other) const { | 
| + return us_ == other.us_; | 
| + } | 
| + bool operator!=(TimeClass other) const { | 
| + return us_ != other.us_; | 
| + } | 
| + bool operator<(TimeClass other) const { | 
| + return us_ < other.us_; | 
| + } | 
| + bool operator<=(TimeClass other) const { | 
| + return us_ <= other.us_; | 
| + } | 
| + bool operator>(TimeClass other) const { | 
| + return us_ > other.us_; | 
| + } | 
| + bool operator>=(TimeClass other) const { | 
| + return us_ >= other.us_; | 
| + } | 
| + | 
| + // Converts an integer value representing TimeClass to a class. This is used | 
| + // when deserializing a |TimeClass| structure, using a value known to be | 
| + // compatible. It is not provided as a constructor because the integer type | 
| + // may be unclear from the perspective of a caller. | 
| + static TimeClass FromInternalValue(int64_t us) { return TimeClass(us); } | 
| + | 
| + protected: | 
| + explicit TimeBase(int64_t us) : us_(us) {} | 
| + | 
| + // Time value in a microsecond timebase. | 
| + int64_t us_; | 
| +}; | 
| + | 
| +} // namespace time_internal | 
| + | 
| + | 
| +// ----------------------------------------------------------------------------- | 
| +// Time | 
| +// | 
| +// This class represents an absolute point in time, internally represented as | 
| +// microseconds (s/1,000,000) since 00:00:00 UTC, January 1, 1970. | 
| + | 
| +class Time final : public time_internal::TimeBase<Time> { | 
| + public: | 
| + // Contains the NULL time. Use Time::Now() to get the current time. | 
| + Time() : TimeBase(0) {} | 
| + | 
| // Returns the current time. Watch out, the system might adjust its clock | 
| // in which case time will actually go backwards. We don't guarantee that | 
| // times are increasing, or that two calls to Now() won't be the same. | 
| @@ -200,15 +306,6 @@ class Time final { | 
| // with which we might compare it. | 
| static Time Max() { return Time(std::numeric_limits<int64_t>::max()); } | 
| - // Converts to/from internal values. The meaning of the "internal value" is | 
| - // completely up to the implementation, so it should be treated as opaque. | 
| - static Time FromInternalValue(int64_t value) { | 
| - return Time(value); | 
| - } | 
| - int64_t ToInternalValue() const { | 
| - return us_; | 
| - } | 
| - | 
| // Converts to/from POSIX time specs. | 
| static Time FromTimespec(struct timespec ts); | 
| struct timespec ToTimespec() const; | 
| @@ -226,59 +323,9 @@ class Time final { | 
| static Time FromJsTime(double ms_since_epoch); | 
| double ToJsTime() const; | 
| - Time& operator=(const Time& other) { | 
| - us_ = other.us_; | 
| - return *this; | 
| - } | 
| - | 
| - // Compute the difference between two times. | 
| - TimeDelta operator-(const Time& other) const { | 
| - return TimeDelta::FromMicroseconds(us_ - other.us_); | 
| - } | 
| - | 
| - // Modify by some time delta. | 
| - Time& operator+=(const TimeDelta& delta) { | 
| - us_ += delta.InMicroseconds(); | 
| - return *this; | 
| - } | 
| - Time& operator-=(const TimeDelta& delta) { | 
| - us_ -= delta.InMicroseconds(); | 
| - return *this; | 
| - } | 
| - | 
| - // Return a new time modified by some delta. | 
| - Time operator+(const TimeDelta& delta) const { | 
| - return Time(us_ + delta.InMicroseconds()); | 
| - } | 
| - Time operator-(const TimeDelta& delta) const { | 
| - return Time(us_ - delta.InMicroseconds()); | 
| - } | 
| - | 
| - // Comparison operators | 
| - bool operator==(const Time& other) const { | 
| - return us_ == other.us_; | 
| - } | 
| - bool operator!=(const Time& other) const { | 
| - return us_ != other.us_; | 
| - } | 
| - bool operator<(const Time& other) const { | 
| - return us_ < other.us_; | 
| - } | 
| - bool operator<=(const Time& other) const { | 
| - return us_ <= other.us_; | 
| - } | 
| - bool operator>(const Time& other) const { | 
| - return us_ > other.us_; | 
| - } | 
| - bool operator>=(const Time& other) const { | 
| - return us_ >= other.us_; | 
| - } | 
| - | 
| private: | 
| - explicit Time(int64_t us) : us_(us) {} | 
| - | 
| - // Time in microseconds in UTC. | 
| - int64_t us_; | 
| + friend class time_internal::TimeBase<Time>; | 
| + explicit Time(int64_t us) : TimeBase(us) {} | 
| }; | 
| std::ostream& operator<<(std::ostream&, const Time&); | 
| @@ -298,9 +345,9 @@ inline Time operator+(const TimeDelta& delta, const Time& time) { | 
| // Time::Now() may actually decrease or jump). But note that TimeTicks may | 
| // "stand still", for example if the computer suspended. | 
| -class TimeTicks final { | 
| +class TimeTicks final : public time_internal::TimeBase<TimeTicks> { | 
| public: | 
| - TimeTicks() : ticks_(0) {} | 
| + TimeTicks() : TimeBase(0) {} | 
| // Platform-dependent tick count representing "right now." | 
| // The resolution of this clock is ~1-15ms. Resolution varies depending | 
| @@ -318,73 +365,12 @@ class TimeTicks final { | 
| // Returns true if the high-resolution clock is working on this system. | 
| static bool IsHighResolutionClockWorking(); | 
| - // Returns true if this object has not been initialized. | 
| - bool IsNull() const { return ticks_ == 0; } | 
| - | 
| - // Converts to/from internal values. The meaning of the "internal value" is | 
| - // completely up to the implementation, so it should be treated as opaque. | 
| - static TimeTicks FromInternalValue(int64_t value) { | 
| - return TimeTicks(value); | 
| - } | 
| - int64_t ToInternalValue() const { | 
| - return ticks_; | 
| - } | 
| - | 
| - TimeTicks& operator=(const TimeTicks other) { | 
| - ticks_ = other.ticks_; | 
| - return *this; | 
| - } | 
| - | 
| - // Compute the difference between two times. | 
| - TimeDelta operator-(const TimeTicks other) const { | 
| - return TimeDelta::FromMicroseconds(ticks_ - other.ticks_); | 
| - } | 
| - | 
| - // Modify by some time delta. | 
| - TimeTicks& operator+=(const TimeDelta& delta) { | 
| - ticks_ += delta.InMicroseconds(); | 
| - return *this; | 
| - } | 
| - TimeTicks& operator-=(const TimeDelta& delta) { | 
| - ticks_ -= delta.InMicroseconds(); | 
| - return *this; | 
| - } | 
| - | 
| - // Return a new TimeTicks modified by some delta. | 
| - TimeTicks operator+(const TimeDelta& delta) const { | 
| - return TimeTicks(ticks_ + delta.InMicroseconds()); | 
| - } | 
| - TimeTicks operator-(const TimeDelta& delta) const { | 
| - return TimeTicks(ticks_ - delta.InMicroseconds()); | 
| - } | 
| - | 
| - // Comparison operators | 
| - bool operator==(const TimeTicks& other) const { | 
| - return ticks_ == other.ticks_; | 
| - } | 
| - bool operator!=(const TimeTicks& other) const { | 
| - return ticks_ != other.ticks_; | 
| - } | 
| - bool operator<(const TimeTicks& other) const { | 
| - return ticks_ < other.ticks_; | 
| - } | 
| - bool operator<=(const TimeTicks& other) const { | 
| - return ticks_ <= other.ticks_; | 
| - } | 
| - bool operator>(const TimeTicks& other) const { | 
| - return ticks_ > other.ticks_; | 
| - } | 
| - bool operator>=(const TimeTicks& other) const { | 
| - return ticks_ >= other.ticks_; | 
| - } | 
| - | 
| private: | 
| + friend class time_internal::TimeBase<TimeTicks>; | 
| + | 
| // Please use Now() to create a new object. This is for internal use | 
| // and testing. Ticks is in microseconds. | 
| - explicit TimeTicks(int64_t ticks) : ticks_(ticks) {} | 
| - | 
| - // Tick count in microseconds. | 
| - int64_t ticks_; | 
| + explicit TimeTicks(int64_t ticks) : TimeBase(ticks) {} | 
| }; | 
| inline TimeTicks operator+(const TimeDelta& delta, const TimeTicks& ticks) { |