From: Andrew Cooper Date: Thu, 17 Dec 2015 11:20:36 +0000 (+0000) Subject: Provide a heapsort() implementation X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=8d079026e99bdd997b0c5160db8c06696af153d1;p=people%2Froyger%2Fxen-test-framework.git Provide a heapsort() implementation Modelled after qsort() in the C standard library. Sorts in place. Signed-off-by: Andrew Cooper --- diff --git a/build/files.mk b/build/files.mk index bf9a3ce..6d93772 100644 --- a/build/files.mk +++ b/build/files.mk @@ -5,6 +5,7 @@ # obj-$(env) are objects unique to a specific environment obj-perarch += $(ROOT)/common/console.o +obj-perarch += $(ROOT)/common/heapsort.o obj-perarch += $(ROOT)/common/lib.o obj-perarch += $(ROOT)/common/libc/string.o obj-perarch += $(ROOT)/common/libc/vsnprintf.o diff --git a/common/heapsort.c b/common/heapsort.c new file mode 100644 index 0000000..89dadcc --- /dev/null +++ b/common/heapsort.c @@ -0,0 +1,49 @@ +#include + +static void siftdown(void *base, size_t _size, + int (*compar)(const void *, const void *), + void (*swap)(void *, void *), + long start, long stop) +{ + long size = _size, root, child; + + for ( root = start; root * 2 + size < stop; root = child ) + { + child = root * 2 + size; + + if ( (child + size < stop) && + (compar(base + child, base + child + size) < 0) ) + child += size; + + if ( compar(base + root, base + child) >= 0 ) + return; + + swap(base + root, base + child); + } +} + +void heapsort(void *base, size_t nmemb, size_t _size, + int (*compar)(const void *, const void *), + void (*swap)(void *, void *)) +{ + long size = _size, total = size * nmemb, idx; + + for ( idx = (nmemb/2 - 1) * size; idx >= 0; idx -= size ) + siftdown(base, _size, compar, swap, idx, total); + + for ( idx = total - size; idx > 0; idx -= size ) + { + swap(base, base + idx); + siftdown(base, _size, compar, swap, 0, idx); + } +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/include/xtf/lib.h b/include/xtf/lib.h index 86f9f0a..c40f8f2 100644 --- a/include/xtf/lib.h +++ b/include/xtf/lib.h @@ -13,6 +13,10 @@ void __noreturn panic(const char *fmt, ...) __printf(1, 2); +void heapsort(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *), + void (*swap)(void *, void *)); + #endif /* XTF_LIB_H */ /* diff --git a/selftests/Makefile b/selftests/Makefile index 590dd93..7fae9d6 100644 --- a/selftests/Makefile +++ b/selftests/Makefile @@ -5,6 +5,7 @@ COMMON_CFLAGS := -Wall -Werror -Wextra -MMD -MP TESTS := test-vsnprintf32 TESTS += test-vsnprintf64 +TESTS += test-heapsort .PHONY: test test: $(TESTS) @@ -20,6 +21,9 @@ test-vsnprintf32 : vsnprintf.c test-vsnprintf64 : vsnprintf.c $(CC) -m64 $(COMMON_CFLAGS) -I $(ROOT)/include -Wno-format -O3 $< -o $@ +test-heapsort : heapsort.c + $(CC) $(COMMON_CFLAGS) -I $(ROOT)/include -O3 $< -o $@ + -include $(TESTS:%=%.d) .PHONY: clean diff --git a/selftests/heapsort.c b/selftests/heapsort.c new file mode 100644 index 0000000..0fb0d29 --- /dev/null +++ b/selftests/heapsort.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include + +#include "../common/heapsort.c" + +void print_array(const char *pref, size_t n, int arr[n]) +{ + size_t i; + + printf("%s{", pref); + for ( i = 0; i < n; ++i ) + { + printf("%d", arr[i]); + if ( i != n - 1 ) + printf(", "); + } + printf("}\n"); +} + +int compar_int(const void *_l, const void *_r) +{ + const int *l = _l, *r = _r; + + return *l - *r; +} + +void swap_int(void *_l, void *_r) +{ + int *l = _l, *r = _r, tmp; + + tmp = *l; + *l = *r; + *r = tmp; +} + +bool test(size_t n, int arr[n]) +{ + size_t i; + int heap[n]; + + memcpy(heap, arr, n * sizeof(arr[0])); + + print_array("Input: ", n, arr); + + heapsort(heap, n, sizeof(arr[0]), compar_int, swap_int); + + if ( n > 1 ) + { + for ( i = 1; i < n; ++i ) + if ( heap[i - 1] > heap[i] ) + { + print_array(" Failed! ", n, heap); + return false; + } + } + + return true; +} + +#define TEST(...) \ + ({ int _a[] = { __VA_ARGS__ }; \ + size_t _s = sizeof _a / sizeof *_a; \ + if ( !test(_s, _a) ) \ + return 1; \ + }) + +int main(void) +{ + bool success = true; + TEST(1); + TEST(1, 2); + TEST(2, 1); + TEST(3, 2, 1); + TEST(4, 3, 2, 1); + TEST(3, 2, 4, 1); + TEST(3, 3, 4, 1); + TEST(3, 3, 4, 1, 10); + TEST(2, 3, 11, 1, 10); + TEST(2, 3, 11, 1, 10, 4); + + printf("Testing array of 10000 random elements\n"); + + int i, *arr = malloc(sizeof(*arr) * 10000); + for ( i = 0; i < 10000; ++i ) + arr[i] = rand(); + + heapsort(arr, 10000, sizeof(*arr), compar_int, swap_int); + + for ( i = 1; i < 10000; ++i ) + if ( arr[i - 1] > arr[i] ) + { + printf("Failed\n"); + success = false; + break; + } + free(arr); + + return !success; +}