Browse Source

Add optimized version of memchr

Matija Skala 7 years ago
parent
commit
9bbb070104
1 changed files with 35 additions and 8 deletions
  1. 35 8
      src/string/src/lib.rs

+ 35 - 8
src/string/src/lib.rs

@@ -11,6 +11,7 @@ use errno::*;
 use core::cmp;
 use core::usize;
 use core::ptr;
+use core::mem;
 
 #[no_mangle]
 pub unsafe extern "C" fn memccpy(
@@ -32,12 +33,42 @@ pub unsafe extern "C" fn memccpy(
 
 #[no_mangle]
 pub unsafe extern "C" fn memchr(s: *const c_void, c: c_int, n: usize) -> *mut c_void {
-    let s = s as *mut u8;
+    let mut s = s as *const u8;
     let c = c as u8;
-    for i in 0..n {
-        if *s.offset(i as isize) == c {
-            return s.offset(i as isize) as *mut c_void;
+    let mut n = n;
+    // read one byte at a time until s is aligned
+    while s as usize % mem::size_of::<usize>() != 0 {
+        if n == 0 {
+            return ptr::null_mut();
+        }
+        if *s == c {
+            return s as *mut c_void;
+        }
+        n -= 1;
+        s = s.offset(1);
+    }
+    let mut s = s as *const usize;
+    let lowbits = !0 as usize / 255;
+    let highbits = lowbits * 0x80;
+    let repeated_c = lowbits * c as usize;
+    while n >= mem::size_of::<usize>() {
+        // read multiple bytes at a time
+        // turn the requested byte into 8 zero bits
+        let m = *s ^ repeated_c;
+        // subtracting one from zero flips high bit from 0 to 1
+        if (m.wrapping_sub(lowbits) & !m & highbits) != 0 {
+            break;
         }
+        n -= mem::size_of::<usize>();
+        s = s.offset(1);
+    }
+    let mut s = s as *const u8;
+    while n > 0 {
+        if *s == c {
+            return s as *mut c_void;
+        }
+        n -= 1;
+        s = s.offset(1);
     }
     ptr::null_mut()
 }
@@ -131,8 +162,6 @@ pub unsafe extern "C" fn strcpy(s1: *mut c_char, s2: *const c_char) -> *mut c_ch
 
 #[no_mangle]
 pub unsafe extern "C" fn strcspn(s1: *const c_char, s2: *const c_char) -> size_t {
-    use core::mem;
-
     let s1 = s1 as *const u8;
     let s2 = s2 as *const u8;
 
@@ -288,8 +317,6 @@ pub unsafe extern "C" fn strrchr(s: *const c_char, c: c_int) -> *mut c_char {
 
 #[no_mangle]
 pub unsafe extern "C" fn strspn(s1: *const c_char, s2: *const c_char) -> size_t {
-    use core::mem;
-
     let s1 = s1 as *const u8;
     let s2 = s2 as *const u8;