Skip to content

Commit 79ff014

Browse files
authored
perf: slightly improve parsing a port (servo#1022)
* Benchmark * add fast u16 to str * fix no-std
1 parent c7abab2 commit 79ff014

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

url/benches/parse_url.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ fn plain(bench: &mut Bencher) {
3333
bench.iter(|| black_box(url).parse::<Url>().unwrap());
3434
}
3535

36+
fn port(bench: &mut Bencher) {
37+
let url = "https://example.com:8080";
38+
39+
bench.bytes = url.len() as u64;
40+
bench.iter(|| black_box(url).parse::<Url>().unwrap());
41+
}
42+
3643
fn hyphen(bench: &mut Bencher) {
3744
let url = "https://hyphenated-example.com/";
3845

@@ -95,6 +102,7 @@ benchmark_group!(
95102
long,
96103
fragment,
97104
plain,
105+
port,
98106
hyphen,
99107
leading_digit,
100108
unicode_mixed,

url/src/parser.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -970,13 +970,17 @@ impl<'a> Parser<'a> {
970970

971971
let (port, remaining) = if let Some(remaining) = remaining.split_prefix(':') {
972972
let scheme = || default_port(&self.serialization[..scheme_end as usize]);
973-
Parser::parse_port(remaining, scheme, self.context)?
973+
let (port, remaining) = Parser::parse_port(remaining, scheme, self.context)?;
974+
if let Some(port) = port {
975+
self.serialization.push(':');
976+
let mut buffer = [0u8; 5];
977+
let port_str = fast_u16_to_str(&mut buffer, port);
978+
self.serialization.push_str(port_str);
979+
}
980+
(port, remaining)
974981
} else {
975982
(None, remaining)
976983
};
977-
if let Some(port) = port {
978-
write!(&mut self.serialization, ":{}", port).unwrap()
979-
}
980984
Ok((host_end, host.into(), port, remaining))
981985
}
982986

@@ -1744,3 +1748,25 @@ fn starts_with_windows_drive_letter_segment(input: &Input<'_>) -> bool {
17441748
_ => false,
17451749
}
17461750
}
1751+
1752+
#[inline]
1753+
fn fast_u16_to_str(
1754+
// max 5 digits for u16 (65535)
1755+
buffer: &mut [u8; 5],
1756+
mut value: u16,
1757+
) -> &str {
1758+
let mut index = buffer.len();
1759+
1760+
loop {
1761+
index -= 1;
1762+
buffer[index] = b'0' + (value % 10) as u8;
1763+
value /= 10;
1764+
if value == 0 {
1765+
break;
1766+
}
1767+
}
1768+
1769+
// SAFETY: we know the values in the buffer from the
1770+
// current index on will be a number
1771+
unsafe { core::str::from_utf8_unchecked(&buffer[index..]) }
1772+
}

0 commit comments

Comments
 (0)