diff --git a/src/stdlib/src/lib.rs b/src/stdlib/src/lib.rs index 7813b9bdc953c45e9a8a8a173f130f6022c95d4a..575f759a264f4eb6624c2577be08145114bbac14 100644 --- a/src/stdlib/src/lib.rs +++ b/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] diff --git a/tests/.gitignore b/tests/.gitignore index 0edf72a5dcc12d503821a0e0aad1524118ee4105..ff5cc28a8c266c21d6c227ce6743e1c49267f02f 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -25,6 +25,7 @@ /rmdir /setid /sprintf +/stdlib/bsearch /stdlib/strtol /stdlib/a64l /string/strncmp diff --git a/tests/Makefile b/tests/Makefile index c2aad5593a04ca46af2aadaca2d652fc99c79e84..8dffd5edd5a88d3e05a1954db86492691ce7c3eb 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -20,6 +20,7 @@ EXPECT_BINS=\ rmdir \ sleep \ sprintf \ + stdlib/bsearch \ stdlib/strtol \ stdlib/a64l \ string/strncmp \ diff --git a/tests/stdlib/bsearch.c b/tests/stdlib/bsearch.c new file mode 100644 index 0000000000000000000000000000000000000000..efe8d46521278021be48e6574e1e120e4d834cc7 --- /dev/null +++ b/tests/stdlib/bsearch.c @@ -0,0 +1,55 @@ +#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); \ + size_t i = 0; \ + for (; 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; +}