From 041e1704fcd9cc932a4fa587c43d32ed9dcb9712 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 29 Dec 2019 15:47:13 +0000 Subject: [PATCH 1/2] use of wmemchr for faster searching in [u16] --- src/libstd/sys/windows/mod.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 74dd41fd50147..cb75e8122fdd5 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -81,10 +81,20 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { } } +pub fn wmemchr(needle: u16, haystack: &[u16]) -> Option { + extern "C" { + fn wmemchr(s: *const u16, c: u16, n: usize) -> *mut u16; + } + let len = haystack.len(); + 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) } +} + pub fn to_u16s>(s: S) -> crate::io::Result> { fn inner(s: &OsStr) -> crate::io::Result> { let mut maybe_result: Vec = s.encode_wide().collect(); - if maybe_result.iter().any(|&u| u == 0) { + if wmemchr(0, &maybe_result).is_some() { return Err(crate::io::Error::new( ErrorKind::InvalidInput, "strings passed to WinAPI cannot contain NULs", @@ -214,7 +224,7 @@ fn wide_char_to_multi_byte( } pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] { - match v.iter().position(|c| *c == 0) { + match wmemchr(0, v) { // don't include the 0 Some(i) => &v[..i], None => v, From 89bc23643bc4ba979f28d6df8c091813c89c36a9 Mon Sep 17 00:00:00 2001 From: lzutao Date: Thu, 2 Apr 2020 02:43:23 +0000 Subject: [PATCH 2/2] Use unrolled loop --- src/libstd/sys/windows/mod.rs | 52 +++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index cb75e8122fdd5..d745e87a07258 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 { - 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 { 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: S) -> crate::io::Result> { fn inner(s: &OsStr) -> crate::io::Result> { let mut maybe_result: Vec = 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,