]> git.proxmox.com Git - libgit2.git/blobdiff - src/tsort.c
New upstream version 1.4.3+dfsg.1
[libgit2.git] / src / tsort.c
index 5dd99cc6e7a4737a5eddf10fbb3ee3479974685a..045efad23f6d09b65988192c8ae677fa9812b1b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009-2011 the libgit2 contributors
+ * Copyright (C) the libgit2 contributors. All rights reserved.
  *
  * This file is part of libgit2, distributed under the GNU GPL v2 with
  * a Linking Exception. For full terms see the included COPYING file.
 #      define MIN(x,y) (((x) < (y) ? (x) : (y)))
 #endif
 
-typedef int (*cmp_ptr_t)(const void *, const void *);
-
-static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
+static int binsearch(
+       void **dst, const void *x, size_t size, git__sort_r_cmp cmp, void *payload)
 {
        int l, c, r;
        void *lx, *cx;
 
        l = 0;
-       r = size - 1;
+       r = (int)size - 1;
        c = r >> 1;
        lx = dst[l];
 
        /* check for beginning conditions */
-       if (cmp(x, lx) < 0)
+       if (cmp(x, lx, payload) < 0)
                return 0;
 
-       else if (cmp(x, lx) == 0) {
+       else if (cmp(x, lx, payload) == 0) {
                int i = 1;
-               while (cmp(x, dst[i]) == 0)
+               while (cmp(x, dst[i], payload) == 0)
                        i++;
                return i;
        }
@@ -49,7 +48,7 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
        /* guaranteed not to be >= rx */
        cx = dst[c];
        while (1) {
-               const int val = cmp(x, cx);
+               const int val = cmp(x, cx, payload);
                if (val < 0) {
                        if (c - l <= 1) return c;
                        r = c;
@@ -60,7 +59,7 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
                } else {
                        do {
                                cx = dst[++c];
-                       } while (cmp(x, cx) == 0);
+                       } while (cmp(x, cx, payload) == 0);
                        return c;
                }
                c = l + ((r - l) >> 1);
@@ -69,7 +68,8 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
 }
 
 /* Binary insertion sort, but knowing that the first "start" entries are sorted. Used in timsort. */
-static void bisort(void **dst, size_t start, size_t size, cmp_ptr_t cmp)
+static void bisort(
+       void **dst, size_t start, size_t size, git__sort_r_cmp cmp, void *payload)
 {
        size_t i;
        void *x;
@@ -78,13 +78,13 @@ static void bisort(void **dst, size_t start, size_t size, cmp_ptr_t cmp)
        for (i = start; i < size; i++) {
                int j;
                /* If this entry is already correct, just move along */
-               if (cmp(dst[i - 1], dst[i]) <= 0)
+               if (cmp(dst[i - 1], dst[i], payload) <= 0)
                        continue;
 
                /* Else we need to find the right place, shift everything over, and squeeze in */
                x = dst[i];
-               location = binsearch(dst, x, i, cmp);
-               for (j = i - 1; j >= location; j--) {
+               location = binsearch(dst, x, i, cmp, payload);
+               for (j = (int)i - 1; j >= location; j--) {
                        dst[j + 1] = dst[j];
                }
                dst[location] = x;
@@ -100,11 +100,12 @@ struct tsort_run {
 
 struct tsort_store {
        size_t alloc;
-       cmp_ptr_t cmp;
+       git__sort_r_cmp cmp;
+       void *payload;
        void **storage;
 };
 
-static void reverse_elements(void **dst, int start, int end)
+static void reverse_elements(void **dst, ssize_t start, ssize_t end)
 {
        while (start < end) {
                void *tmp = dst[start];
@@ -116,7 +117,8 @@ static void reverse_elements(void **dst, int start, int end)
        }
 }
 
-static int count_run(void **dst, ssize_t start, ssize_t size, struct tsort_store *store)
+static ssize_t count_run(
+       void **dst, ssize_t start, ssize_t size, struct tsort_store *store)
 {
        ssize_t curr = start + 2;
 
@@ -124,7 +126,7 @@ static int count_run(void **dst, ssize_t start, ssize_t size, struct tsort_store
                return 1;
 
        if (start >= size - 2) {
-               if (store->cmp(dst[size - 2], dst[size - 1]) > 0) {
+               if (store->cmp(dst[size - 2], dst[size - 1], store->payload) > 0) {
                        void *tmp = dst[size - 1];
                        dst[size - 1] = dst[size - 2];
                        dst[size - 2] = tmp;
@@ -133,13 +135,15 @@ static int count_run(void **dst, ssize_t start, ssize_t size, struct tsort_store
                return 2;
        }
 
-       if (store->cmp(dst[start], dst[start + 1]) <= 0) {
-               while (curr < size - 1 && store->cmp(dst[curr - 1], dst[curr]) <= 0)
+       if (store->cmp(dst[start], dst[start + 1], store->payload) <= 0) {
+               while (curr < size - 1 &&
+                               store->cmp(dst[curr - 1], dst[curr], store->payload) <= 0)
                        curr++;
 
                return curr - start;
        } else {
-               while (curr < size - 1 && store->cmp(dst[curr - 1], dst[curr]) > 0)
+               while (curr < size - 1 &&
+                               store->cmp(dst[curr - 1], dst[curr], store->payload) > 0)
                        curr++;
 
                /* reverse in-place */
@@ -148,7 +152,7 @@ static int count_run(void **dst, ssize_t start, ssize_t size, struct tsort_store
        }
 }
 
-static int compute_minrun(size_t n)
+static size_t compute_minrun(size_t n)
 {
        int r = 0;
        while (n >= 64) {
@@ -158,19 +162,19 @@ static int compute_minrun(size_t n)
        return n + r;
 }
 
-static int check_invariant(struct tsort_run *stack, int stack_curr)
+static int check_invariant(struct tsort_run *stack, ssize_t stack_curr)
 {
        if (stack_curr < 2)
                return 1;
 
        else if (stack_curr == 2) {
-               const int A = stack[stack_curr - 2].length;
-               const int B = stack[stack_curr - 1].length;
+               const ssize_t A = stack[stack_curr - 2].length;
+               const ssize_t B = stack[stack_curr - 1].length;
                return (A > B);
        } else {
-               const int A = stack[stack_curr - 3].length;
-               const int B = stack[stack_curr - 2].length;
-               const int C = stack[stack_curr - 1].length;
+               const ssize_t A = stack[stack_curr - 3].length;
+               const ssize_t B = stack[stack_curr - 2].length;
+               const ssize_t C = stack[stack_curr - 1].length;
                return !((A <= B + C) || (B <= C));
        }
 }
@@ -178,7 +182,9 @@ static int check_invariant(struct tsort_run *stack, int stack_curr)
 static int resize(struct tsort_store *store, size_t new_size)
 {
        if (store->alloc < new_size) {
-               void **tempstore = realloc(store->storage, new_size * sizeof(void *));
+               void **tempstore;
+
+               tempstore = git__reallocarray(store->storage, new_size, sizeof(void *));
 
                /**
                 * Do not propagate on OOM; this will abort the sort and
@@ -195,7 +201,7 @@ static int resize(struct tsort_store *store, size_t new_size)
        return 0;
 }
 
-static void merge(void **dst, const struct tsort_run *stack, int stack_curr, struct tsort_store *store)
+static void merge(void **dst, const struct tsort_run *stack, ssize_t stack_curr, struct tsort_store *store)
 {
        const ssize_t A = stack[stack_curr - 2].length;
        const ssize_t B = stack[stack_curr - 1].length;
@@ -217,7 +223,7 @@ static void merge(void **dst, const struct tsort_run *stack, int stack_curr, str
 
                for (k = curr; k < curr + A + B; k++) {
                        if ((i < A) && (j < curr + A + B)) {
-                               if (store->cmp(storage[i], dst[j]) <= 0)
+                               if (store->cmp(storage[i], dst[j], store->payload) <= 0)
                                        dst[k] = storage[i++];
                                else
                                        dst[k] = dst[j++];
@@ -233,7 +239,7 @@ static void merge(void **dst, const struct tsort_run *stack, int stack_curr, str
 
                for (k = curr + A + B - 1; k >= curr; k--) {
                        if ((i >= 0) && (j >= curr)) {
-                               if (store->cmp(dst[j], storage[i]) > 0)
+                               if (store->cmp(dst[j], storage[i], store->payload) > 0)
                                        dst[k] = dst[j--];
                                else
                                        dst[k] = storage[i--];
@@ -302,10 +308,9 @@ static ssize_t collapse(void **dst, struct tsort_run *stack, ssize_t stack_curr,
 #define PUSH_NEXT() do {\
        len = count_run(dst, curr, size, store);\
        run = minrun;\
-       if (run < minrun) run = minrun;\
        if (run > (ssize_t)size - curr) run = size - curr;\
        if (run > len) {\
-               bisort(&dst[curr], len, run, cmp);\
+               bisort(&dst[curr], len, run, cmp, payload);\
                len = run;\
        }\
        run_stack[stack_curr].start = curr;\
@@ -319,7 +324,7 @@ static ssize_t collapse(void **dst, struct tsort_run *stack, ssize_t stack_curr,
                        stack_curr--; \
                } \
                if (store->storage != NULL) {\
-                       free(store->storage);\
+                       git__free(store->storage);\
                        store->storage = NULL;\
                }\
                return;\
@@ -327,7 +332,8 @@ static ssize_t collapse(void **dst, struct tsort_run *stack, ssize_t stack_curr,
 }\
 while (0)
 
-void git__tsort(void **dst, size_t size, cmp_ptr_t cmp)
+void git__tsort_r(
+       void **dst, size_t size, git__sort_r_cmp cmp, void *payload)
 {
        struct tsort_store _store, *store = &_store;
        struct tsort_run run_stack[128];
@@ -338,17 +344,18 @@ void git__tsort(void **dst, size_t size, cmp_ptr_t cmp)
        ssize_t minrun;
 
        if (size < 64) {
-               bisort(dst, 1, size, cmp);
+               bisort(dst, 1, size, cmp, payload);
                return;
        }
 
        /* compute the minimum run length */
-       minrun = compute_minrun(size);
+       minrun = (ssize_t)compute_minrun(size);
 
        /* temporary storage for merges */
        store->alloc = 0;
        store->storage = NULL;
        store->cmp = cmp;
+       store->payload = payload;
 
        PUSH_NEXT();
        PUSH_NEXT();
@@ -363,3 +370,13 @@ void git__tsort(void **dst, size_t size, cmp_ptr_t cmp)
                PUSH_NEXT();
        }
 }
+
+static int tsort_r_cmp(const void *a, const void *b, void *payload)
+{
+       return ((git__tsort_cmp)payload)(a, b);
+}
+
+void git__tsort(void **dst, size_t size, git__tsort_cmp cmp)
+{
+       git__tsort_r(dst, size, tsort_r_cmp, cmp);
+}