Justin Raymond 7 years ago
parent
commit
a0c76f7ce5
4 changed files with 77 additions and 3 deletions
  1. 21 3
      src/stdlib/src/lib.rs
  2. 1 0
      tests/.gitignore
  3. 1 0
      tests/Makefile
  4. 54 0
      tests/stdlib/bsearch.c

+ 21 - 3
src/stdlib/src/lib.rs

@@ -130,15 +130,33 @@ pub extern "C" fn atol(s: *const c_char) -> c_long {
     dec_num_from_ascii!(s, c_long)
 }
 
+unsafe extern "C" fn void_cmp(a: *const c_void, b: *const c_void) -> c_int {
+    return *(a as *const i32) - *(b as *const i32) as c_int;
+}
+
 #[no_mangle]
-pub extern "C" fn bsearch(
+pub unsafe extern "C" fn bsearch(
     key: *const c_void,
     base: *const c_void,
     nel: size_t,
     width: size_t,
-    compar: Option<extern "C" fn(*const c_void, *const c_void) -> c_int>,
+    compar: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
 ) -> *mut c_void {
-    unimplemented!();
+    let mut start = base;
+    let mut len = nel;
+    let cmp_fn = compar.unwrap_or(void_cmp);
+    while len > 0 {
+        let med = (start as size_t + (len >> 1) * width) as *const c_void;
+        let diff = cmp_fn(key, med);
+        if diff == 0 {
+            return med as *mut c_void;
+        } else if diff > 0 {
+            start = (med as usize + width) as *const c_void;
+            len -= 1;
+        }
+        len >>= 1;
+    }
+    ptr::null_mut()
 }
 
 #[no_mangle]

+ 1 - 0
tests/.gitignore

@@ -25,6 +25,7 @@
 /rmdir
 /setid
 /sprintf
+/stdlib/bsearch
 /stdlib/strtol
 /stdlib/a64l
 /string/strncmp

+ 1 - 0
tests/Makefile

@@ -20,6 +20,7 @@ EXPECT_BINS=\
 	rmdir \
 	sleep \
 	sprintf \
+	stdlib/bsearch \
 	stdlib/strtol \
 	stdlib/a64l \
 	string/strncmp \

+ 54 - 0
tests/stdlib/bsearch.c

@@ -0,0 +1,54 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+int int_cmp(const void* a, const void* b) {
+  return *(const int*) a - *(const int*) b;
+}
+
+#define BSEARCH_TEST_INT(key, arr, len, expect) \
+  do { \
+    void* res = bsearch((const void*) &key, (void*) arr, len, sizeof(int), int_cmp); \
+    if (res != expect) { \
+      printf("FAIL bsearch for %d in [", key); \
+      for (size_t i = 0; i < len; ++i) printf("%d,", arr[i]); \
+      printf("] expected %p but got %p\n", (void*) expect, res); \
+      return 1; \
+    } \
+  } while (0);
+
+
+
+int main(int argc, char* argv[]) {
+  int x = 0;
+  int y = 1024;
+  int empty[] = {};
+  BSEARCH_TEST_INT(x, empty, 0, NULL);
+
+  int singleton[] = {42};
+  printf("%p\n%p\n", singleton, &singleton[1]);
+  BSEARCH_TEST_INT(x, singleton, 1, NULL);
+  BSEARCH_TEST_INT(singleton[0], singleton, 1, &singleton[0]);
+  BSEARCH_TEST_INT(y, singleton, 1, NULL);
+
+  int two[] = {14, 42};
+  BSEARCH_TEST_INT(x, two, 2, NULL);
+  BSEARCH_TEST_INT(y, two, 2, NULL);
+  BSEARCH_TEST_INT(two[0], two, 2, &two[0]);
+  BSEARCH_TEST_INT(two[0], two, 1, &two[0]);
+  BSEARCH_TEST_INT(two[1], two, 2, &two[1]);
+  BSEARCH_TEST_INT(two[1], two, 1, NULL);
+
+  int three[] = {-5, -1, 4};
+  BSEARCH_TEST_INT(three[0], three, 3, &three[0]);
+  BSEARCH_TEST_INT(three[1], three, 3, &three[1]);
+  BSEARCH_TEST_INT(three[2], three, 3, &three[2]);
+
+  int big[] = {-19, -13, -7, -3, 2, 5, 11};
+  BSEARCH_TEST_INT(big[0], big, 7, big);
+  BSEARCH_TEST_INT(big[6], big, 7, &big[6]);
+  BSEARCH_TEST_INT(big[3], big, 7, &big[3]);
+  BSEARCH_TEST_INT(x, big, 7, NULL);
+
+  printf("PASS bsearch\n");
+  return 0;
+}