Skip to content

Commit

Permalink
Add checked_add method to Instant time type
Browse files Browse the repository at this point in the history
  • Loading branch information
faern committed Dec 11, 2018
1 parent 4c0116e commit 8839f15
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 74 deletions.
19 changes: 6 additions & 13 deletions src/libstd/sys/cloudabi/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ pub struct Instant {

fn checked_dur2intervals(dur: &Duration) -> Option<abi::timestamp> {
dur.as_secs()
.checked_mul(NSEC_PER_SEC)
.and_then(|nanos| nanos.checked_add(dur.subsec_nanos() as abi::timestamp))
.checked_mul(NSEC_PER_SEC)?
.checked_add(dur.subsec_nanos() as abi::timestamp)
}

pub fn dur2intervals(dur: &Duration) -> abi::timestamp {
Expand All @@ -47,12 +47,10 @@ impl Instant {
Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32)
}

pub fn add_duration(&self, other: &Duration) -> Instant {
Instant {
t: self.t
.checked_add(dur2intervals(other))
.expect("overflow when adding duration to instant"),
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
checked_dur2intervals(other)?
.checked_add(self.t)
.map(|t| Instant {t})
}

pub fn sub_duration(&self, other: &Duration) -> Instant {
Expand Down Expand Up @@ -95,11 +93,6 @@ impl SystemTime {
}
}

pub fn add_duration(&self, other: &Duration) -> SystemTime {
self.checked_add_duration(other)
.expect("overflow when adding duration to instant")
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
checked_dur2intervals(other)
.and_then(|d| self.t.checked_add(d))
Expand Down
12 changes: 2 additions & 10 deletions src/libstd/sys/redox/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ impl Timespec {
}
}

fn add_duration(&self, other: &Duration) -> Timespec {
self.checked_add_duration(other).expect("overflow when adding duration to time")
}

fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = other
.as_secs()
Expand Down Expand Up @@ -150,8 +146,8 @@ impl Instant {
})
}

pub fn add_duration(&self, other: &Duration) -> Instant {
Instant { t: self.t.add_duration(other) }
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
self.t.checked_add_duration(other).map(|t| Instant { t })
}

pub fn sub_duration(&self, other: &Duration) -> Instant {
Expand All @@ -178,10 +174,6 @@ impl SystemTime {
self.t.sub_timespec(&other.t)
}

pub fn add_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.add_duration(other) }
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
self.t.checked_add_duration(other).map(|t| SystemTime { t })
}
Expand Down
36 changes: 13 additions & 23 deletions src/libstd/sys/unix/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ impl Timespec {
}
}

fn add_duration(&self, other: &Duration) -> Timespec {
self.checked_add_duration(other).expect("overflow when adding duration to time")
}

fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = other
.as_secs()
Expand Down Expand Up @@ -165,11 +161,8 @@ mod inner {
Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32)
}

pub fn add_duration(&self, other: &Duration) -> Instant {
Instant {
t: self.t.checked_add(dur2intervals(other))
.expect("overflow when adding duration to instant"),
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
checked_dur2intervals(other)?.checked_add(self.t).map(|t| Instant {t})
}

pub fn sub_duration(&self, other: &Duration) -> Instant {
Expand Down Expand Up @@ -199,10 +192,6 @@ mod inner {
self.t.sub_timespec(&other.t)
}

pub fn add_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.add_duration(other) }
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
self.t.checked_add_duration(other).map(|t| SystemTime { t })
}
Expand Down Expand Up @@ -237,11 +226,16 @@ mod inner {
}

fn dur2intervals(dur: &Duration) -> u64 {
checked_dur2intervals(dur)
.expect("overflow converting duration to nanoseconds")
}

fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
let nanos = dur.as_secs()
.checked_mul(NSEC_PER_SEC)?
.checked_add(dur.subsec_nanos() as u64)?;
let info = info();
let nanos = dur.as_secs().checked_mul(NSEC_PER_SEC).and_then(|nanos| {
nanos.checked_add(dur.subsec_nanos() as u64)
}).expect("overflow converting duration to nanoseconds");
mul_div_u64(nanos, info.denom as u64, info.numer as u64)
Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
}

fn info() -> &'static libc::mach_timebase_info {
Expand Down Expand Up @@ -299,8 +293,8 @@ mod inner {
})
}

pub fn add_duration(&self, other: &Duration) -> Instant {
Instant { t: self.t.add_duration(other) }
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
self.t.checked_add_duration(other).map(|t| Instant { t })
}

pub fn sub_duration(&self, other: &Duration) -> Instant {
Expand All @@ -327,10 +321,6 @@ mod inner {
self.t.sub_timespec(&other.t)
}

pub fn add_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.add_duration(other) }
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
self.t.checked_add_duration(other).map(|t| SystemTime { t })
}
Expand Down
8 changes: 2 additions & 6 deletions src/libstd/sys/wasm/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ impl Instant {
self.0 - other.0
}

pub fn add_duration(&self, other: &Duration) -> Instant {
Instant(self.0 + *other)
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
self.0.checked_add(*other).map(|d| Instant(d))
}

pub fn sub_duration(&self, other: &Duration) -> Instant {
Expand All @@ -47,10 +47,6 @@ impl SystemTime {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
}

pub fn add_duration(&self, other: &Duration) -> SystemTime {
SystemTime(self.0 + *other)
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
self.0.checked_add(*other).map(|d| SystemTime(d))
}
Expand Down
34 changes: 14 additions & 20 deletions src/libstd/sys/windows/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,26 +68,23 @@ impl Instant {
Duration::new(nanos / NANOS_PER_SEC, (nanos % NANOS_PER_SEC) as u32)
}

pub fn add_duration(&self, other: &Duration) -> Instant {
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
let freq = frequency() as u64;
let t = other.as_secs().checked_mul(freq).and_then(|i| {
(self.t as u64).checked_add(i)
}).and_then(|i| {
i.checked_add(mul_div_u64(other.subsec_nanos() as u64, freq,
NANOS_PER_SEC))
}).expect("overflow when adding duration to time");
Instant {
let t = other.as_secs()
.checked_mul(freq)?
.checked_add(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC))?
.checked_add(self.t as u64)?;
Some(Instant {
t: t as c::LARGE_INTEGER,
}
})
}

pub fn sub_duration(&self, other: &Duration) -> Instant {
let freq = frequency() as u64;
let t = other.as_secs().checked_mul(freq).and_then(|i| {
(self.t as u64).checked_sub(i)
}).and_then(|i| {
i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq,
NANOS_PER_SEC))
i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC))
}).expect("overflow when subtracting duration from time");
Instant {
t: t as c::LARGE_INTEGER,
Expand Down Expand Up @@ -127,10 +124,6 @@ impl SystemTime {
}
}

pub fn add_duration(&self, other: &Duration) -> SystemTime {
self.checked_add_duration(other).expect("overflow when adding duration to time")
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
checked_dur2intervals(other)
.and_then(|d| self.intervals().checked_add(d))
Expand Down Expand Up @@ -184,11 +177,12 @@ impl Hash for SystemTime {
}
}

fn checked_dur2intervals(d: &Duration) -> Option<i64> {
d.as_secs()
.checked_mul(INTERVALS_PER_SEC)
.and_then(|i| i.checked_add(d.subsec_nanos() as u64 / 100))
.and_then(|i| i.try_into().ok())
fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
dur.as_secs()
.checked_mul(INTERVALS_PER_SEC)?
.checked_add(dur.subsec_nanos() as u64 / 100)?
.try_into()
.ok()
}

fn dur2intervals(d: &Duration) -> i64 {
Expand Down
27 changes: 25 additions & 2 deletions src/libstd/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,14 +208,23 @@ impl Instant {
pub fn elapsed(&self) -> Duration {
Instant::now() - *self
}

/// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
/// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
/// otherwise.
#[unstable(feature = "time_checked_add", issue = "55940")]
pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
self.0.checked_add_duration(&duration).map(|t| Instant(t))
}
}

#[stable(feature = "time2", since = "1.8.0")]
impl Add<Duration> for Instant {
type Output = Instant;

fn add(self, other: Duration) -> Instant {
Instant(self.0.add_duration(&other))
self.checked_add(other)
.expect("overflow when adding duration to instant")
}
}

Expand Down Expand Up @@ -372,7 +381,8 @@ impl Add<Duration> for SystemTime {
type Output = SystemTime;

fn add(self, dur: Duration) -> SystemTime {
SystemTime(self.0.add_duration(&dur))
self.checked_add(dur)
.expect("overflow when adding duration to instant")
}
}

Expand Down Expand Up @@ -521,6 +531,19 @@ mod tests {

let second = Duration::new(1, 0);
assert_almost_eq!(a - second + second, a);

// checked_add_duration will not panic on overflow
let mut maybe_t = Some(Instant::now());
let max_duration = Duration::from_secs(u64::max_value());
// in case `Instant` can store `>= now + max_duration`.
for _ in 0..2 {
maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
}
assert_eq!(maybe_t, None);

// checked_add_duration calculates the right time and will work for another year
let year = Duration::from_secs(60 * 60 * 24 * 365);
assert_eq!(a + year, a.checked_add(year).unwrap());
}

#[test]
Expand Down

0 comments on commit 8839f15

Please sign in to comment.