Skip to content

Commit 8e961af

Browse files
committed
Optimize month length, is_leap_year, weeks_in_year
1 parent 0a50218 commit 8e961af

File tree

4 files changed

+61
-43
lines changed

4 files changed

+61
-43
lines changed

benchmarks/month.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,34 @@ setup_benchmark! {
3333
ben.iter(|| November.next());
3434
ben.iter(|| December.next());
3535
}
36+
37+
fn length(ben: &mut Bencher<'_>) {
38+
// Common year
39+
ben.iter(|| January.length(2019));
40+
ben.iter(|| February.length(2019));
41+
ben.iter(|| March.length(2019));
42+
ben.iter(|| April.length(2019));
43+
ben.iter(|| May.length(2019));
44+
ben.iter(|| June.length(2019));
45+
ben.iter(|| July.length(2019));
46+
ben.iter(|| August.length(2019));
47+
ben.iter(|| September.length(2019));
48+
ben.iter(|| October.length(2019));
49+
ben.iter(|| November.length(2019));
50+
ben.iter(|| December.length(2019));
51+
52+
// Leap year
53+
ben.iter(|| January.length(2020));
54+
ben.iter(|| February.length(2020));
55+
ben.iter(|| March.length(2020));
56+
ben.iter(|| April.length(2020));
57+
ben.iter(|| May.length(2020));
58+
ben.iter(|| June.length(2020));
59+
ben.iter(|| July.length(2020));
60+
ben.iter(|| August.length(2020));
61+
ben.iter(|| September.length(2020));
62+
ben.iter(|| October.length(2020));
63+
ben.iter(|| November.length(2020));
64+
ben.iter(|| December.length(2020));
65+
}
3666
}

benchmarks/util.rs

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,9 @@
11
use criterion::{black_box, Bencher};
2-
use time::{util, Month};
2+
use time::util;
33

44
setup_benchmark! {
55
"Utils",
66

7-
fn days_in_year_month(ben: &mut Bencher<'_>) {
8-
// Common year
9-
ben.iter(|| util::days_in_year_month(2019, Month::January));
10-
ben.iter(|| util::days_in_year_month(2019, Month::February));
11-
ben.iter(|| util::days_in_year_month(2019, Month::March));
12-
ben.iter(|| util::days_in_year_month(2019, Month::April));
13-
ben.iter(|| util::days_in_year_month(2019, Month::May));
14-
ben.iter(|| util::days_in_year_month(2019, Month::June));
15-
ben.iter(|| util::days_in_year_month(2019, Month::July));
16-
ben.iter(|| util::days_in_year_month(2019, Month::August));
17-
ben.iter(|| util::days_in_year_month(2019, Month::September));
18-
ben.iter(|| util::days_in_year_month(2019, Month::October));
19-
ben.iter(|| util::days_in_year_month(2019, Month::November));
20-
ben.iter(|| util::days_in_year_month(2019, Month::December));
21-
22-
// Leap year
23-
ben.iter(|| util::days_in_year_month(2020, Month::January));
24-
ben.iter(|| util::days_in_year_month(2020, Month::February));
25-
ben.iter(|| util::days_in_year_month(2020, Month::March));
26-
ben.iter(|| util::days_in_year_month(2020, Month::April));
27-
ben.iter(|| util::days_in_year_month(2020, Month::May));
28-
ben.iter(|| util::days_in_year_month(2020, Month::June));
29-
ben.iter(|| util::days_in_year_month(2020, Month::July));
30-
ben.iter(|| util::days_in_year_month(2020, Month::August));
31-
ben.iter(|| util::days_in_year_month(2020, Month::September));
32-
ben.iter(|| util::days_in_year_month(2020, Month::October));
33-
ben.iter(|| util::days_in_year_month(2020, Month::November));
34-
ben.iter(|| util::days_in_year_month(2020, Month::December));
35-
}
36-
377
fn is_leap_year(ben: &mut Bencher<'_>) {
388
ben.iter(|| {
399
for year in 0..400 {

time-core/src/util.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
/// assert!(!is_leap_year(2100));
1313
/// ```
1414
pub const fn is_leap_year(year: i32) -> bool {
15-
year % 4 == 0 && (year % 25 != 0 || year % 16 == 0)
15+
let d = if year % 100 == 0 { 15 } else { 3 };
16+
year & d == 0
1617
}
1718

1819
/// Get the number of calendar days in a given year.
@@ -45,12 +46,18 @@ pub const fn days_in_year(year: i32) -> u16 {
4546
/// assert_eq!(weeks_in_year(2020), 53);
4647
/// ```
4748
pub const fn weeks_in_year(year: i32) -> u8 {
48-
match year.rem_euclid(400) {
49-
4 | 9 | 15 | 20 | 26 | 32 | 37 | 43 | 48 | 54 | 60 | 65 | 71 | 76 | 82 | 88 | 93 | 99
50-
| 105 | 111 | 116 | 122 | 128 | 133 | 139 | 144 | 150 | 156 | 161 | 167 | 172 | 178
51-
| 184 | 189 | 195 | 201 | 207 | 212 | 218 | 224 | 229 | 235 | 240 | 246 | 252 | 257
52-
| 263 | 268 | 274 | 280 | 285 | 291 | 296 | 303 | 308 | 314 | 320 | 325 | 331 | 336
53-
| 342 | 348 | 353 | 359 | 364 | 370 | 376 | 381 | 387 | 392 | 398 => 53,
49+
match year % 400 {
50+
-396 | -391 | -385 | -380 | -374 | -368 | -363 | -357 | -352 | -346 | -340 | -335
51+
| -329 | -324 | -318 | -312 | -307 | -301 | -295 | -289 | -284 | -278 | -272 | -267
52+
| -261 | -256 | -250 | -244 | -239 | -233 | -228 | -222 | -216 | -211 | -205 | -199
53+
| -193 | -188 | -182 | -176 | -171 | -165 | -160 | -154 | -148 | -143 | -137 | -132
54+
| -126 | -120 | -115 | -109 | -104 | -97 | -92 | -86 | -80 | -75 | -69 | -64 | -58
55+
| -52 | -47 | -41 | -36 | -30 | -24 | -19 | -13 | -8 | -2 | 4 | 9 | 15 | 20 | 26 | 32
56+
| 37 | 43 | 48 | 54 | 60 | 65 | 71 | 76 | 82 | 88 | 93 | 99 | 105 | 111 | 116 | 122
57+
| 128 | 133 | 139 | 144 | 150 | 156 | 161 | 167 | 172 | 178 | 184 | 189 | 195 | 201
58+
| 207 | 212 | 218 | 224 | 229 | 235 | 240 | 246 | 252 | 257 | 263 | 268 | 274 | 280
59+
| 285 | 291 | 296 | 303 | 308 | 314 | 320 | 325 | 331 | 336 | 342 | 348 | 353 | 359
60+
| 364 | 370 | 376 | 381 | 387 | 392 | 398 => 53,
5461
_ => 52,
5562
}
5663
}

time/src/month.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,22 @@ impl Month {
7272
/// assert_eq!(Month::February.length(2020), 29);
7373
/// ```
7474
pub const fn length(self, year: i32) -> u8 {
75-
match self {
76-
January | March | May | July | August | October | December => 31,
77-
April | June | September | November => 30,
78-
February if util::is_leap_year(year) => 29,
79-
February => 28,
75+
let val = self as u8;
76+
if val != 2 {
77+
30 | val ^ val >> 3
78+
} else {
79+
// Until there's `likely`/`unlikely`/`cold_path` on stable, this is the only way to tell
80+
// the compiler to put February after all other months. This results in a performance
81+
// gain.
82+
#[cold]
83+
const fn february_length(year: i32) -> u8 {
84+
if util::is_leap_year(year) {
85+
29
86+
} else {
87+
28
88+
}
89+
}
90+
february_length(year)
8091
}
8192
}
8293

0 commit comments

Comments
 (0)