]> xenbits.xensource.com Git - people/royger/xen-test-framework.git/commitdiff
Provide a heapsort() implementation
authorAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 17 Dec 2015 11:20:36 +0000 (11:20 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 22 Dec 2015 20:46:44 +0000 (20:46 +0000)
Modelled after qsort() in the C standard library.  Sorts in place.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
build/files.mk
common/heapsort.c [new file with mode: 0644]
include/xtf/lib.h
selftests/Makefile
selftests/heapsort.c [new file with mode: 0644]

index bf9a3ce48aec9a8af445127f51f5165be32a0429..6d93772ed383170106f6be2098bc3c874cde58fd 100644 (file)
@@ -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 (file)
index 0000000..89dadcc
--- /dev/null
@@ -0,0 +1,49 @@
+#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:
+ */
index 86f9f0a0d715a359abba543fc80e01f6c5384d86..c40f8f2690e676c0482b34cd56e7cef2de9a9311 100644 (file)
 
 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 */
 
 /*
index 590dd9310391b6c23b43a7f50a962c91223d323c..7fae9d62ba8efcc0920a0d9b9cd62f473894d3fb 100644 (file)
@@ -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 (file)
index 0000000..0fb0d29
--- /dev/null
@@ -0,0 +1,102 @@
+#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;
+}