Modelled after qsort() in the C standard library. Sorts in place.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
# 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
--- /dev/null
+#include <xtf/types.h>
+
+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:
+ */
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 */
/*
TESTS := test-vsnprintf32
TESTS += test-vsnprintf64
+TESTS += test-heapsort
.PHONY: test
test: $(TESTS)
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
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#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;
+}