فهرست منبع

perf: slightly improve parsing a port (#1022)

* Benchmark

* add fast u16 to str

* fix no-std
David Sherret 1 سال پیش
والد
کامیت
79ff014219
2فایلهای تغییر یافته به همراه38 افزوده شده و 4 حذف شده
  1. 8 0
      url/benches/parse_url.rs
  2. 30 4
      url/src/parser.rs

+ 8 - 0
url/benches/parse_url.rs

@@ -33,6 +33,13 @@ fn plain(bench: &mut Bencher) {
     bench.iter(|| black_box(url).parse::<Url>().unwrap());
 }
 
+fn port(bench: &mut Bencher) {
+    let url = "https://example.com:8080";
+
+    bench.bytes = url.len() as u64;
+    bench.iter(|| black_box(url).parse::<Url>().unwrap());
+}
+
 fn hyphen(bench: &mut Bencher) {
     let url = "https://hyphenated-example.com/";
 
@@ -95,6 +102,7 @@ benchmark_group!(
     long,
     fragment,
     plain,
+    port,
     hyphen,
     leading_digit,
     unicode_mixed,

+ 30 - 4
url/src/parser.rs

@@ -970,13 +970,17 @@ impl<'a> Parser<'a> {
 
         let (port, remaining) = if let Some(remaining) = remaining.split_prefix(':') {
             let scheme = || default_port(&self.serialization[..scheme_end as usize]);
-            Parser::parse_port(remaining, scheme, self.context)?
+            let (port, remaining) = Parser::parse_port(remaining, scheme, self.context)?;
+            if let Some(port) = port {
+                self.serialization.push(':');
+                let mut buffer = [0u8; 5];
+                let port_str = fast_u16_to_str(&mut buffer, port);
+                self.serialization.push_str(port_str);
+            }
+            (port, remaining)
         } else {
             (None, remaining)
         };
-        if let Some(port) = port {
-            write!(&mut self.serialization, ":{}", port).unwrap()
-        }
         Ok((host_end, host.into(), port, remaining))
     }
 
@@ -1744,3 +1748,25 @@ fn starts_with_windows_drive_letter_segment(input: &Input<'_>) -> bool {
         _ => false,
     }
 }
+
+#[inline]
+fn fast_u16_to_str(
+    // max 5 digits for u16 (65535)
+    buffer: &mut [u8; 5],
+    mut value: u16,
+) -> &str {
+    let mut index = buffer.len();
+
+    loop {
+        index -= 1;
+        buffer[index] = b'0' + (value % 10) as u8;
+        value /= 10;
+        if value == 0 {
+            break;
+        }
+    }
+
+    // SAFETY: we know the values in the buffer from the
+    // current index on will be a number
+    unsafe { core::str::from_utf8_unchecked(&buffer[index..]) }
+}