summaryrefslogtreecommitdiff
path: root/src/util.c
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2011-07-07 01:46:20 +0200
committerVicent Marti <tanoku@gmail.com>2011-07-07 02:54:07 +0200
commitde18f276683a5cf3d85d001f6521e52c8c802e60 (patch)
tree01db449c1fa2d11568aca66bf4a5ef9d1a5c60f3 /src/util.c
parentc63aa494595a6d6e6d97cfa1bbc1741a0b2e0cc6 (diff)
downloadlibgit2-de18f276683a5cf3d85d001f6521e52c8c802e60.tar.gz
vector: Timsort all of the things
Drop the GLibc implementation of Merge Sort and replace it with Timsort. The algorithm has been tuned to work on arrays of pointers (void **), so there's no longer a need to abstract the byte-width of each element in the array. All the comparison callbacks now take pointers-to-elements, not pointers-to-pointers, so there's now one less level of dereferencing. E.g. int index_cmp(const void *a, const void *b) { - const git_index_entry *entry_a = *(const git_index_entry **)(a); + const git_index_entry *entry_a = (const git_index_entry *)(a); The result is up to a 40% speed-up when sorting vectors. Memory usage remains lineal. A new `bsearch` implementation has been added, whose callback also supplies pointer-to-elements, to uniform the Vector API again.
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c79
1 files changed, 20 insertions, 59 deletions
diff --git a/src/util.c b/src/util.c
index 03e911241..4a44f9988 100644
--- a/src/util.c
+++ b/src/util.c
@@ -331,66 +331,27 @@ uint32_t git__hash(const void *key, int len, uint32_t seed)
}
#endif
-/*
- * A merge sort implementation, simplified from the qsort implementation
- * by Mike Haertel, which is a part of the GNU C Library.
+/**
+ * A modified `bsearch` from the BSD glibc.
+ *
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
*/
-static void msort_with_tmp(void *b, size_t n, size_t s,
- int (*cmp)(const void *, const void *),
- char *t)
+void **git__bsearch(const void *key, void **base, size_t nmemb, int (*compar)(const void *, const void *))
{
- char *tmp;
- char *b1, *b2;
- size_t n1, n2;
-
- if (n <= 1)
- return;
-
- n1 = n / 2;
- n2 = n - n1;
- b1 = b;
- b2 = (char *)b + (n1 * s);
-
- msort_with_tmp(b1, n1, s, cmp, t);
- msort_with_tmp(b2, n2, s, cmp, t);
-
- tmp = t;
-
- while (n1 > 0 && n2 > 0) {
- if (cmp(b1, b2) <= 0) {
- memcpy(tmp, b1, s);
- tmp += s;
- b1 += s;
- --n1;
- } else {
- memcpy(tmp, b2, s);
- tmp += s;
- b2 += s;
- --n2;
- }
- }
- if (n1 > 0)
- memcpy(tmp, b1, n1 * s);
- memcpy(b, t, (n - n2) * s);
+ int lim, cmp;
+ void **p;
+
+ for (lim = nmemb; lim != 0; lim >>= 1) {
+ p = base + (lim >> 1);
+ cmp = (*compar)(key, *p);
+ if (cmp > 0) { /* key > p: move right */
+ base = p + 1;
+ lim--;
+ } else if (cmp == 0) {
+ return (void **)p;
+ } /* else move left */
+ }
+ return NULL;
}
-int git__msort(void *b, size_t n, size_t s,
- int (*cmp)(const void *, const void *))
-{
- const size_t size = n * s;
- char buf[1024];
-
- if (size < sizeof(buf)) {
- /* The temporary array fits on the small on-stack buffer. */
- msort_with_tmp(b, n, s, cmp, buf);
- } else {
- /* It's somewhat large, so malloc it. */
- char *tmp = git__malloc(size);
- if (tmp == NULL)
- return GIT_ENOMEM;
- msort_with_tmp(b, n, s, cmp, tmp);
- free(tmp);
- }
-
- return GIT_SUCCESS;
-}