From 86665d0a7fddd10188235493809510f9d9f77b22 Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Mon, 24 Nov 2014 14:49:13 +0900 Subject: [PATCH] 0.1.2: no more `num` dependency, multidispatched addition. - `num` dependency is gone. It was only used for floored division and it is not hard to copy only that portion from num. - `Duration + Date` (or so) was blocked by rust-lang/rust#7590, which has been subsequently fixed. - Removed unused `unsafe` checks. --- Cargo.toml | 5 +--- src/date.rs | 3 -- src/datetime.rs | 3 -- src/div.rs | 70 +++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 +- src/naive/date.rs | 31 +++++++++---------- src/naive/datetime.rs | 7 ++--- src/naive/time.rs | 11 +++---- src/offset.rs | 6 ++-- src/time.rs | 3 -- 10 files changed, 95 insertions(+), 46 deletions(-) create mode 100644 src/div.rs diff --git a/Cargo.toml b/Cargo.toml index 6a0cd81..1f374a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chrono" -version = "0.1.1" +version = "0.1.2" authors = ["Kang Seonghoon "] description = "Date and time library for Rust" @@ -13,9 +13,6 @@ license = "MIT/Apache-2.0" [lib] name = "chrono" -[dependencies.num] -git = "https://github.com/rust-lang/num" - [dependencies.time] git = "https://github.com/rust-lang/time" diff --git a/src/date.rs b/src/date.rs index 665450c..9dc4d12 100644 --- a/src/date.rs +++ b/src/date.rs @@ -263,13 +263,10 @@ impl Add> for Date { } } -/* -// Rust issue #7590, the current coherence checker can't handle multiple Add impls impl Add,Date> for Duration { #[inline] fn add(&self, rhs: &Date) -> Date { rhs.add(self) } } -*/ impl Sub,Duration> for Date { fn sub(&self, rhs: &Date) -> Duration { diff --git a/src/datetime.rs b/src/datetime.rs index a52691d..e0b6ad0 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -185,13 +185,10 @@ impl Add> for DateTime { } } -/* -// Rust issue #7590, the current coherence checker can't handle multiple Add impls impl Add,DateTime> for Duration { #[inline] fn add(&self, rhs: &DateTime) -> DateTime { rhs.add(self) } } -*/ impl Sub,Duration> for DateTime { fn sub(&self, rhs: &DateTime) -> Duration { diff --git a/src/div.rs b/src/div.rs new file mode 100644 index 0000000..cc5d600 --- /dev/null +++ b/src/div.rs @@ -0,0 +1,70 @@ +// This is a part of rust-chrono. +// Copyright (c) 2014, Kang Seonghoon. +// Copyright 2013-2014 The Rust Project Developers. +// See README.md and LICENSE.txt for details. + +//! Integer division utilities. (Shamelessly copied from [num](https://github.com/rust-lang/num/)) + +// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, +// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) + +use std::num::Int; + +/// Same as `(a / b, a % b)`. +#[inline] +pub fn div_rem(a: T, b: T) -> (T, T) { + (a / b, a % b) +} + +/// Same as `let (q, r) = div_mod_floor(a, b); r`. +#[inline] +pub fn mod_floor(a: T, b: T) -> T { + let zero = Int::zero(); + match a % b { + r if (r > zero && b < zero) || (r < zero && b > zero) => r + b, + r => r, + } +} + +/// Calculates a floored integer quotient and modulo. +#[inline] +pub fn div_mod_floor(a: T, b: T) -> (T, T) { + let zero = Int::zero(); + let one = Int::one(); + match (a / b, a % b) { + (d, r) if (r > zero && b < zero) || (r < zero && b > zero) => (d - one, r + b), + (d, r) => (d, r), + } +} + +#[cfg(test)] +mod tests { + use super::{mod_floor, div_mod_floor}; + + #[test] + fn test_mod_floor() { + assert_eq!(mod_floor( 8i, 3), 2); + assert_eq!(mod_floor( 8i, -3), -1); + assert_eq!(mod_floor(-8i, 3), 1); + assert_eq!(mod_floor(-8i, -3), -2); + + assert_eq!(mod_floor( 1i, 2), 1); + assert_eq!(mod_floor( 1i, -2), -1); + assert_eq!(mod_floor(-1i, 2), 1); + assert_eq!(mod_floor(-1i, -2), -1); + } + + #[test] + fn test_div_mod_floor() { + assert_eq!(div_mod_floor( 8i, 3), ( 2, 2)); + assert_eq!(div_mod_floor( 8i, -3), (-3, -1)); + assert_eq!(div_mod_floor(-8i, 3), (-3, 1)); + assert_eq!(div_mod_floor(-8i, -3), ( 2, -2)); + + assert_eq!(div_mod_floor( 1i, 2), ( 0, 1)); + assert_eq!(div_mod_floor( 1i, -2), (-1, -1)); + assert_eq!(div_mod_floor(-1i, 2), (-1, 1)); + assert_eq!(div_mod_floor(-1i, -2), ( 0, -1)); + } +} + diff --git a/src/lib.rs b/src/lib.rs index 632fc41..4ad8948 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,6 @@ Experimental date and time handling for Rust. #![feature(macro_rules)] #![deny(missing_docs)] -extern crate num; extern crate "time" as stdtime; pub use duration::Duration; @@ -26,6 +25,7 @@ pub use date::Date; pub use time::Time; pub use datetime::DateTime; +mod div; pub mod duration { //! ISO 8601 duration. //! diff --git a/src/naive/date.rs b/src/naive/date.rs index 425f6b2..1375306 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -8,9 +8,9 @@ use std::fmt; use std::num::Int; -use num::Integer; use {Weekday, Datelike}; +use div::div_mod_floor; use duration::Duration; use naive::time::NaiveTime; use naive::datetime::NaiveDateTime; @@ -148,9 +148,9 @@ impl NaiveDate { /// Returns `None` on the out-of-range date. pub fn from_num_days_from_ce_opt(days: i32) -> Option { let days = days + 365; // make January 1, 1 BCE equal to day 0 - let (year_div_400, cycle) = days.div_mod_floor(&146097); + let (year_div_400, cycle) = div_mod_floor(days, 146097); let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); - let flags = unsafe { YearFlags::from_year_mod_400(year_mod_400 as i32) }; + let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)) } @@ -382,33 +382,30 @@ impl Add for NaiveDate { // TODO overflow currently fails let year = self.year(); - let (mut year_div_400, year_mod_400) = year.div_mod_floor(&400); + let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal()); let cycle = (cycle as i32).checked_add(rhs.num_days().to_i32().unwrap()).unwrap(); - let (cycle_div_400y, cycle) = cycle.div_mod_floor(&146097); + let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146097); year_div_400 += cycle_div_400y; let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); - let flags = unsafe { YearFlags::from_year_mod_400(year_mod_400 as i32) }; + let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)).unwrap() } } -/* -// Rust issue #7590, the current coherence checker can't handle multiple Add impls impl Add for Duration { #[inline] fn add(&self, rhs: &NaiveDate) -> NaiveDate { rhs.add(self) } } -*/ impl Sub for NaiveDate { fn sub(&self, rhs: &NaiveDate) -> Duration { let year1 = self.year(); let year2 = rhs.year(); - let (year1_div_400, year1_mod_400) = year1.div_mod_floor(&400); - let (year2_div_400, year2_mod_400) = year2.div_mod_floor(&400); + let (year1_div_400, year1_mod_400) = div_mod_floor(year1, 400); + let (year2_div_400, year2_mod_400) = div_mod_floor(year2, 400); let cycle1 = internals::yo_to_cycle(year1_mod_400 as u32, self.of().ordinal()) as i64; let cycle2 = internals::yo_to_cycle(year2_mod_400 as u32, rhs.of().ordinal()) as i64; Duration::days((year1_div_400 as i64 - year2_div_400 as i64) * 146097 + (cycle1 - cycle2)) @@ -698,7 +695,7 @@ mod tests { let lhs = NaiveDate::from_ymd(y1, m1, d1); let sum = NaiveDate::from_ymd(y, m, d); assert_eq!(lhs + rhs, sum); - //assert_eq!(rhs + lhs, sum); + assert_eq!(rhs + lhs, sum); } check((2014, 1, 1), Duration::zero(), (2014, 1, 1)); @@ -780,8 +777,8 @@ mod tests { #[allow(dead_code)] // some internal methods have been left for consistency mod internals { use std::{i32, num, fmt}; - use num::Integer; use Weekday; + use div::{div_rem, mod_floor}; /// The internal date representation. This also includes the packed `Mdf` value. pub type DateImpl = i32; @@ -855,7 +852,7 @@ mod internals { ]; pub fn cycle_to_yo(cycle: u32) -> (u32, u32) { - let (mut year_mod_400, mut ordinal0) = cycle.div_rem(&365); + let (mut year_mod_400, mut ordinal0) = div_rem(cycle, 365); let delta = YEAR_DELTAS[year_mod_400 as uint] as u32; if ordinal0 < delta { year_mod_400 -= 1; @@ -873,12 +870,12 @@ mod internals { impl YearFlags { #[inline] pub fn from_year(year: i32) -> YearFlags { - let year = year.mod_floor(&400); - unsafe { YearFlags::from_year_mod_400(year) } + let year = mod_floor(year, 400); + YearFlags::from_year_mod_400(year) } #[inline] - pub unsafe fn from_year_mod_400(year: i32) -> YearFlags { + pub fn from_year_mod_400(year: i32) -> YearFlags { YEAR_TO_FLAGS[year as uint] } diff --git a/src/naive/datetime.rs b/src/naive/datetime.rs index 4ac8221..c6fd427 100644 --- a/src/naive/datetime.rs +++ b/src/naive/datetime.rs @@ -8,9 +8,9 @@ use std::fmt; use std::num::Int; -use num::Integer; use {Weekday, Timelike, Datelike}; +use div::div_mod_floor; use duration::Duration; use naive::time::NaiveTime; use naive::date::NaiveDate; @@ -49,7 +49,7 @@ impl NaiveDateTime { /// Returns `None` on the out-of-range number of seconds and/or invalid nanosecond. #[inline] pub fn from_num_seconds_from_unix_epoch_opt(secs: i64, nsecs: u32) -> Option { - let (days, secs) = secs.div_mod_floor(&86400); + let (days, secs) = div_mod_floor(secs, 86400); let date = days.to_i32().and_then(|days| days.checked_add(719163)) .and_then(|days_ce| NaiveDate::from_num_days_from_ce_opt(days_ce)); let time = NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, nsecs); @@ -183,13 +183,10 @@ impl Add for NaiveDateTime { } } -/* -// Rust issue #7590, the current coherence checker can't handle multiple Add impls impl Add for Duration { #[inline] fn add(&self, rhs: &NaiveDateTime) -> NaiveDateTime { rhs.add(self) } } -*/ impl Sub for NaiveDateTime { fn sub(&self, rhs: &NaiveDateTime) -> Duration { diff --git a/src/naive/time.rs b/src/naive/time.rs index 1365cc6..cdfeb5b 100644 --- a/src/naive/time.rs +++ b/src/naive/time.rs @@ -8,9 +8,9 @@ use std::fmt; use std::num::Int; -use num::Integer; use Timelike; +use div::div_mod_floor; use offset::Offset; use duration::Duration; use format::DelayedFormat; @@ -126,8 +126,8 @@ impl NaiveTime { /// Returns a triple of the hour, minute and second numbers. fn hms(&self) -> (u32, u32, u32) { - let (mins, sec) = self.secs.div_mod_floor(&60); - let (hour, min) = mins.div_mod_floor(&60); + let (mins, sec) = div_mod_floor(self.secs, 60); + let (hour, min) = div_mod_floor(mins, 60); (hour, min, sec) } } @@ -190,13 +190,10 @@ impl Add for NaiveTime { } } -/* -// Rust issue #7590, the current coherence checker can't handle multiple Add impls impl Add for Duration { #[inline] fn add(&self, rhs: &NaiveTime) -> NaiveTime { rhs.add(self) } } -*/ impl Sub for NaiveTime { fn sub(&self, rhs: &NaiveTime) -> Duration { @@ -303,7 +300,7 @@ mod tests { fn test_time_add() { fn check(lhs: NaiveTime, rhs: Duration, sum: NaiveTime) { assert_eq!(lhs + rhs, sum); - //assert_eq!(rhs + lhs, sum); + assert_eq!(rhs + lhs, sum); } let hmsm = |h,m,s,mi| NaiveTime::from_hms_milli(h, m, s, mi); diff --git a/src/offset.rs b/src/offset.rs index 64c44ed..5591808 100644 --- a/src/offset.rs +++ b/src/offset.rs @@ -9,9 +9,9 @@ use std::fmt; use std::str::MaybeOwned; use stdtime; -use num::Integer; use {Weekday, Datelike, Timelike}; +use div::div_mod_floor; use duration::Duration; use naive::date::NaiveDate; use naive::time::NaiveTime; @@ -365,8 +365,8 @@ impl fmt::Show for FixedOffset { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let offset = self.local_minus_utc; let (sign, offset) = if offset < 0 {('-', -offset)} else {('+', offset)}; - let (mins, sec) = offset.div_mod_floor(&60); - let (hour, min) = mins.div_mod_floor(&60); + let (mins, sec) = div_mod_floor(offset, 60); + let (hour, min) = div_mod_floor(mins, 60); if sec == 0 { write!(f, "{}{:02}:{:02}", sign, hour, min) } else { diff --git a/src/time.rs b/src/time.rs index 8f5796b..a344d00 100644 --- a/src/time.rs +++ b/src/time.rs @@ -113,13 +113,10 @@ impl Add> for Time { } } -/* -// Rust issue #7590, the current coherence checker can't handle multiple Add impls impl Add,Time> for Duration { #[inline] fn add(&self, rhs: &Time) -> Time { rhs.add(self) } } -*/ impl Sub,Duration> for Time { fn sub(&self, rhs: &Time) -> Duration {