about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
authorlzutao <taolzu@gmail.com>2020-04-02 02:43:23 +0000
committerLzu Tao <taolzu@gmail.com>2020-04-02 02:43:23 +0000
commit89bc23643bc4ba979f28d6df8c091813c89c36a9 (patch)
tree8cb75b45c011a4dfd561acd029fc4b941d9a1890 /src/libstd/sys
parent041e1704fcd9cc932a4fa587c43d32ed9dcb9712 (diff)
downloadrust-89bc23643bc4ba979f28d6df8c091813c89c36a9.tar.gz
rust-89bc23643bc4ba979f28d6df8c091813c89c36a9.zip
Use unrolled loop
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/windows/mod.rs52
1 files changed, 43 insertions, 9 deletions
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index cb75e8122fd..d745e87a072 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -81,20 +81,54 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
     }
 }
 
-pub fn wmemchr(needle: u16, haystack: &[u16]) -> Option<usize> {
-    extern "C" {
-        fn wmemchr(s: *const u16, c: u16, n: usize) -> *mut u16;
-    }
-    let len = haystack.len();
+pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
     let ptr = haystack.as_ptr();
-    let p = unsafe { wmemchr(ptr, needle, len) };
-    if p.is_null() { None } else { Some((p as usize - ptr as usize) / 2) }
+    let mut len = haystack.len();
+    let mut start = &haystack[..];
+
+    // For performance reasons unfold the loop eight times.
+    while len >= 8 {
+        if start[0] == needle {
+            return Some((start.as_ptr() as usize - ptr as usize) / 2);
+        }
+        if start[1] == needle {
+            return Some((start[1..].as_ptr() as usize - ptr as usize) / 2);
+        }
+        if start[2] == needle {
+            return Some((start[2..].as_ptr() as usize - ptr as usize) / 2);
+        }
+        if start[3] == needle {
+            return Some((start[3..].as_ptr() as usize - ptr as usize) / 2);
+        }
+        if start[4] == needle {
+            return Some((start[4..].as_ptr() as usize - ptr as usize) / 2);
+        }
+        if start[5] == needle {
+            return Some((start[5..].as_ptr() as usize - ptr as usize) / 2);
+        }
+        if start[6] == needle {
+            return Some((start[6..].as_ptr() as usize - ptr as usize) / 2);
+        }
+        if start[7] == needle {
+            return Some((start[7..].as_ptr() as usize - ptr as usize) / 2);
+        }
+
+        start = &start[8..];
+        len -= 8;
+    }
+
+    for (i, c) in start.iter().enumerate() {
+        if *c == needle {
+            return Some((start.as_ptr() as usize - ptr as usize) / 2 + i);
+        }
+    }
+    None
 }
 
 pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
     fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
         let mut maybe_result: Vec<u16> = s.encode_wide().collect();
-        if wmemchr(0, &maybe_result).is_some() {
+        if unrolled_find_u16s(0, &maybe_result).is_some() {
             return Err(crate::io::Error::new(
                 ErrorKind::InvalidInput,
                 "strings passed to WinAPI cannot contain NULs",
@@ -224,7 +258,7 @@ fn wide_char_to_multi_byte(
 }
 
 pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
-    match wmemchr(0, v) {
+    match unrolled_find_u16s(0, v) {
         // don't include the 0
         Some(i) => &v[..i],
         None => v,