From c6ce7a5358ab77a81942890af52b70f83f352d30 Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 6 Nov 2022 17:34:35 +0100 Subject: [PATCH] libc: Add bsearch (with a test!!) --- libs/libc/include/stdlib.h | 5 ++++- libs/libc/src/stdlib.cpp | 24 ++++++++++++++++++++++-- tests/libc/Test.c | 2 ++ tests/libc/stdlib.c | 25 +++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/libs/libc/include/stdlib.h b/libs/libc/include/stdlib.h index 17088d2c..2ab42cec 100644 --- a/libs/libc/include/stdlib.h +++ b/libs/libc/include/stdlib.h @@ -116,7 +116,10 @@ extern "C" /* Sorts the array pointed to by base of nmemb items of the specified size using the comparison function compar. */ void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)); - void* bsearch(const void*, const void*, size_t, size_t, int (*)(const void*, const void*)); // Not implemented. + /* Searches the sorted array base of nmemb items of the specified size for the given key using the comparison + * function compar. */ + void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, + int (*compar)(const void*, const void*)); size_t mbstowcs(wchar_t* dest, const char* src, size_t n); // Not implemented. diff --git a/libs/libc/src/stdlib.cpp b/libs/libc/src/stdlib.cpp index ffcf60c3..b123116c 100644 --- a/libs/libc/src/stdlib.cpp +++ b/libs/libc/src/stdlib.cpp @@ -122,6 +122,26 @@ static void quicksort(void* base, size_t start, size_t end, size_t size, int (*c } } +void* binary_search(const void* key, const void* base, size_t start, size_t end, size_t size, + int (*compar)(const void*, const void*)) +{ + auto atindex = [&base, &size](size_t index) { return (const void*)((const char*)base + (index * size)); }; + + if (end >= start) + { + size_t middle = start + (end - start) / 2; + int rc = compar(atindex(middle), key); + + if (rc == 0) return const_cast(atindex(middle)); // we found it!! + + if (rc < 0) return binary_search(key, base, middle + 1, end, size, compar); + + return binary_search(key, base, start, middle - 1, size, compar); + } + + return NULL; +} + extern "C" { __lc_noreturn void abort() @@ -225,9 +245,9 @@ extern "C" quicksort(base, 0, nmemb - 1, size, compar); } - void* bsearch(const void*, const void*, size_t, size_t, int (*)(const void*, const void*)) + void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)) { - NOT_IMPLEMENTED("bsearch"); + return binary_search(key, base, 0, nmemb - 1, size, compar); } size_t mbstowcs(wchar_t*, const char*, size_t) diff --git a/tests/libc/Test.c b/tests/libc/Test.c index be0b132d..ba08faf9 100644 --- a/tests/libc/Test.c +++ b/tests/libc/Test.c @@ -26,6 +26,7 @@ DEFINE_TEST(malloc); DEFINE_TEST(calloc); DEFINE_TEST(mktemp); DEFINE_TEST(qsort); +DEFINE_TEST(bsearch); int main() { @@ -55,4 +56,5 @@ int main() RUN_TEST(calloc); RUN_TEST(mktemp); RUN_TEST(qsort); + RUN_TEST(bsearch); } \ No newline at end of file diff --git a/tests/libc/stdlib.c b/tests/libc/stdlib.c index ed9a5e26..d869808c 100644 --- a/tests/libc/stdlib.c +++ b/tests/libc/stdlib.c @@ -205,5 +205,30 @@ DEFINE_TEST(qsort) EXPECT_EQ(rc, 0); + TEST_SUCCESS(); +} + +DEFINE_TEST(bsearch) +{ + START_TEST(bsearch); + + const char sorted[] = "abcdefjkl"; + char key = 'j'; + + char* ptr = bsearch(&key, sorted, 9, sizeof(char), compare_char); // try with sorted array first + + EXPECT_EQ(*ptr, 'j'); + EXPECT_EQ(ptr, &sorted[6]); + + int unsorted[] = {1500, 45, 3, 11, 41, 90, 6, 32, 5, 76}; + qsort(unsorted, 10, sizeof(int), compare_int); + + int key2 = 90; + + int* ptr2 = bsearch(&key2, unsorted, 10, sizeof(int), compare_int); + + EXPECT_EQ(*ptr2, 90); + EXPECT_EQ(ptr2, &unsorted[8]); + TEST_SUCCESS(); } \ No newline at end of file