Merge branch 'bd/qsort'
authorJunio C Hamano <gitster@pobox.com>
Sun, 17 Feb 2008 02:11:10 +0000 (18:11 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 17 Feb 2008 02:11:47 +0000 (18:11 -0800)
* bd/qsort:
compat: Add simplified merge sort implementation from glibc

Makefile
compat/qsort.c [new file with mode: 0644]
git-compat-util.h
index d288378aa18677f575b83b07809b4f438ddfcdaa..83c359acde102c653b197001b3272781f9fd2697 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -137,6 +137,10 @@ all::
 # Define THREADED_DELTA_SEARCH if you have pthreads and wish to exploit
 # parallel delta searching when packing objects.
 #
+# Define INTERNAL_QSORT to use Git's implementation of qsort(), which
+# is a simplified version of the merge sort used in glibc. This is
+# recommended if Git triggers O(n^2) behavior in your platform's qsort().
+#
 
 GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -722,6 +726,10 @@ ifdef NO_MEMMEM
        COMPAT_CFLAGS += -DNO_MEMMEM
        COMPAT_OBJS += compat/memmem.o
 endif
+ifdef INTERNAL_QSORT
+       COMPAT_CFLAGS += -DINTERNAL_QSORT
+       COMPAT_OBJS += compat/qsort.o
+endif
 
 ifdef THREADED_DELTA_SEARCH
        BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH
diff --git a/compat/qsort.c b/compat/qsort.c
new file mode 100644 (file)
index 0000000..d93dce2
--- /dev/null
@@ -0,0 +1,62 @@
+#include "../git-compat-util.h"
+
+/*
+ * A merge sort implementation, simplified from the qsort implementation
+ * by Mike Haertel, which is a part of the GNU C Library.
+ */
+
+static void msort_with_tmp(void *b, size_t n, size_t s,
+                          int (*cmp)(const void *, const void *),
+                          char *t)
+{
+       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);
+}
+
+void git_qsort(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 = malloc(size);
+               msort_with_tmp(b, n, s, cmp, tmp);
+               free(tmp);
+       }
+}
index 4df90cb34e61deb56ecb49797e48e67bdc98ff3b..05146047e0f33476df963e0e5aef30dd02a249fc 100644 (file)
@@ -426,4 +426,10 @@ static inline int strtol_i(char const *s, int base, int *result)
        return 0;
 }
 
+#ifdef INTERNAL_QSORT
+void git_qsort(void *base, size_t nmemb, size_t size,
+              int(*compar)(const void *, const void *));
+#define qsort git_qsort
+#endif
+
 #endif