Skip to content

Commit 0cfc405

Browse files
committed
Optimize number formatting
1 parent 74ba83b commit 0cfc405

File tree

1 file changed

+82
-42
lines changed

1 file changed

+82
-42
lines changed

src/format/formatting.rs

Lines changed: 82 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -115,48 +115,88 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
115115
fn format_numeric(&self, w: &mut impl Write, spec: &Numeric, pad: Pad) -> fmt::Result {
116116
use self::Numeric::*;
117117

118-
let (width, v) = match (spec, self.date, self.time) {
119-
(Year, Some(d), _) => (4, i64::from(d.year())),
120-
(YearDiv100, Some(d), _) => (2, i64::from(d.year()).div_euclid(100)),
121-
(YearMod100, Some(d), _) => (2, i64::from(d.year()).rem_euclid(100)),
122-
(IsoYear, Some(d), _) => (4, i64::from(d.iso_week().year())),
123-
(IsoYearDiv100, Some(d), _) => (2, i64::from(d.iso_week().year()).div_euclid(100)),
124-
(IsoYearMod100, Some(d), _) => (2, i64::from(d.iso_week().year()).rem_euclid(100)),
125-
(Month, Some(d), _) => (2, i64::from(d.month())),
126-
(Day, Some(d), _) => (2, i64::from(d.day())),
127-
(WeekFromSun, Some(d), _) => (2, i64::from(d.weeks_from(Weekday::Sun))),
128-
(WeekFromMon, Some(d), _) => (2, i64::from(d.weeks_from(Weekday::Mon))),
129-
(IsoWeek, Some(d), _) => (2, i64::from(d.iso_week().week())),
130-
(NumDaysFromSun, Some(d), _) => (1, i64::from(d.weekday().num_days_from_sunday())),
131-
(WeekdayFromMon, Some(d), _) => (1, i64::from(d.weekday().number_from_monday())),
132-
(Ordinal, Some(d), _) => (3, i64::from(d.ordinal())),
133-
(Hour, _, Some(t)) => (2, i64::from(t.hour())),
134-
(Hour12, _, Some(t)) => (2, i64::from(t.hour12().1)),
135-
(Minute, _, Some(t)) => (2, i64::from(t.minute())),
136-
(Second, _, Some(t)) => (2, i64::from(t.second() + t.nanosecond() / 1_000_000_000)),
137-
(Nanosecond, _, Some(t)) => (9, i64::from(t.nanosecond() % 1_000_000_000)),
138-
(Timestamp, Some(d), Some(t)) => {
139-
let offset = self.off.as_ref().map(|(_, o)| i64::from(o.local_minus_utc()));
140-
let timestamp = d.and_time(t).and_utc().timestamp() - offset.unwrap_or(0);
141-
(1, timestamp)
118+
fn write_one(w: &mut impl Write, v: u8) -> fmt::Result {
119+
w.write_char((b'0' + v) as char)
120+
}
121+
122+
fn write_two(w: &mut impl Write, v: u8, pad: Pad) -> fmt::Result {
123+
let ones = b'0' + v % 10;
124+
match (v / 10, pad) {
125+
(0, Pad::None) => {}
126+
(0, Pad::Space) => w.write_char(' ')?,
127+
(tens, _) => w.write_char((b'0' + tens) as char)?,
142128
}
143-
(Internal(_), _, _) => return Ok(()), // for future expansion
144-
_ => return Err(fmt::Error), // insufficient arguments for given format
145-
};
129+
w.write_char(ones as char)
130+
}
146131

147-
if (spec == &Year || spec == &IsoYear) && !(0..10_000).contains(&v) {
148-
// non-four-digit years require an explicit sign as per ISO 8601
149-
match pad {
150-
Pad::None => write!(w, "{:+}", v),
151-
Pad::Zero => write!(w, "{:+01$}", v, width + 1),
152-
Pad::Space => write!(w, "{:+1$}", v, width + 1),
132+
#[inline]
133+
fn write_year(w: &mut impl Write, year: i32, pad: Pad) -> fmt::Result {
134+
if (1000..=9999).contains(&year) {
135+
// fast path
136+
write_hundreds(w, (year / 100) as u8)?;
137+
write_hundreds(w, (year % 100) as u8)
138+
} else {
139+
write_n(w, 4, year as i64, pad, !(0..10_000).contains(&year))
153140
}
154-
} else {
155-
match pad {
156-
Pad::None => write!(w, "{}", v),
157-
Pad::Zero => write!(w, "{:01$}", v, width),
158-
Pad::Space => write!(w, "{:1$}", v, width),
141+
}
142+
143+
fn write_n(
144+
w: &mut impl Write,
145+
n: usize,
146+
v: i64,
147+
pad: Pad,
148+
always_sign: bool,
149+
) -> fmt::Result {
150+
if always_sign {
151+
match pad {
152+
Pad::None => write!(w, "{:+}", v),
153+
Pad::Zero => write!(w, "{:+01$}", v, n + 1),
154+
Pad::Space => write!(w, "{:+1$}", v, n + 1),
155+
}
156+
} else {
157+
match pad {
158+
Pad::None => write!(w, "{}", v),
159+
Pad::Zero => write!(w, "{:01$}", v, n),
160+
Pad::Space => write!(w, "{:1$}", v, n),
161+
}
162+
}
163+
}
164+
165+
match (spec, self.date, self.time) {
166+
(Year, Some(d), _) => write_year(w, d.year(), pad),
167+
(YearDiv100, Some(d), _) => write_two(w, d.year().div_euclid(100) as u8, pad),
168+
(YearMod100, Some(d), _) => write_two(w, d.year().rem_euclid(100) as u8, pad),
169+
(IsoYear, Some(d), _) => write_year(w, d.iso_week().year(), pad),
170+
(IsoYearDiv100, Some(d), _) => {
171+
write_two(w, d.iso_week().year().div_euclid(100) as u8, pad)
172+
}
173+
(IsoYearMod100, Some(d), _) => {
174+
write_two(w, d.iso_week().year().rem_euclid(100) as u8, pad)
175+
}
176+
(Month, Some(d), _) => write_two(w, d.month() as u8, pad),
177+
(Day, Some(d), _) => write_two(w, d.day() as u8, pad),
178+
(WeekFromSun, Some(d), _) => write_two(w, d.weeks_from(Weekday::Sun) as u8, pad),
179+
(WeekFromMon, Some(d), _) => write_two(w, d.weeks_from(Weekday::Mon) as u8, pad),
180+
(IsoWeek, Some(d), _) => write_two(w, d.iso_week().week() as u8, pad),
181+
(NumDaysFromSun, Some(d), _) => write_one(w, d.weekday().num_days_from_sunday() as u8),
182+
(WeekdayFromMon, Some(d), _) => write_one(w, d.weekday().number_from_monday() as u8),
183+
(Ordinal, Some(d), _) => write_n(w, 3, d.ordinal() as i64, pad, false),
184+
(Hour, _, Some(t)) => write_two(w, t.hour() as u8, pad),
185+
(Hour12, _, Some(t)) => write_two(w, t.hour12().1 as u8, pad),
186+
(Minute, _, Some(t)) => write_two(w, t.minute() as u8, pad),
187+
(Second, _, Some(t)) => {
188+
write_two(w, (t.second() + t.nanosecond() / 1_000_000_000) as u8, pad)
189+
}
190+
(Nanosecond, _, Some(t)) => {
191+
write_n(w, 9, (t.nanosecond() % 1_000_000_000) as i64, pad, false)
192+
}
193+
(Timestamp, Some(d), Some(t)) => {
194+
let offset = self.off.as_ref().map(|(_, o)| i64::from(o.local_minus_utc()));
195+
let timestamp = d.and_time(t).and_utc().timestamp() - offset.unwrap_or(0);
196+
write_n(w, 9, timestamp, pad, false)
159197
}
198+
(Internal(_), _, _) => Ok(()), // for future expansion
199+
_ => Err(fmt::Error), // insufficient arguments for given format
160200
}
161201
}
162202

@@ -206,21 +246,21 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
206246
}
207247
(Nanosecond3, _, Some(t), _) => {
208248
w.write_str(decimal_point(self.locale))?;
209-
write!(w, "{:03}", t.nanosecond() % 1_000_000_000 / 1_000_000)
249+
write!(w, "{:03}", t.nanosecond() / 1_000_000 % 1000)
210250
}
211251
(Nanosecond6, _, Some(t), _) => {
212252
w.write_str(decimal_point(self.locale))?;
213-
write!(w, "{:06}", t.nanosecond() % 1_000_000_000 / 1_000)
253+
write!(w, "{:06}", t.nanosecond() / 1_000 % 1_000_000)
214254
}
215255
(Nanosecond9, _, Some(t), _) => {
216256
w.write_str(decimal_point(self.locale))?;
217257
write!(w, "{:09}", t.nanosecond() % 1_000_000_000)
218258
}
219259
(Internal(InternalFixed { val: Nanosecond3NoDot }), _, Some(t), _) => {
220-
write!(w, "{:03}", t.nanosecond() % 1_000_000_000 / 1_000_000)
260+
write!(w, "{:03}", t.nanosecond() / 1_000_000 % 1_000)
221261
}
222262
(Internal(InternalFixed { val: Nanosecond6NoDot }), _, Some(t), _) => {
223-
write!(w, "{:06}", t.nanosecond() % 1_000_000_000 / 1_000)
263+
write!(w, "{:06}", t.nanosecond() / 1_000 % 1_000_000)
224264
}
225265
(Internal(InternalFixed { val: Nanosecond9NoDot }), _, Some(t), _) => {
226266
write!(w, "{:09}", t.nanosecond() % 1_000_000_000)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy