diff --git a/Makefile b/Makefile index a40e71c30d..448a22e123 100644 --- a/Makefile +++ b/Makefile @@ -136,6 +136,9 @@ all:: # Define THREADED_DELTA_SEARCH if you have pthreads and wish to exploit # parallel delta searching when packing objects. # +# Define NEEDS_QUICK_QSORT if your qsort() implementation has O(n^2) +# worst case complexity. +# GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @"$(SHELL_PATH)" ./GIT-VERSION-GEN @@ -523,6 +526,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease NO_R_TO_GCC_LINKER = YesPlease + NEEDS_QUICK_QSORT = YesPlease NO_EXTRA_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -741,6 +745,10 @@ ifdef NO_MEMMEM COMPAT_CFLAGS += -DNO_MEMMEM COMPAT_OBJS += compat/memmem.o endif +ifdef NEEDS_QUICK_QSORT + COMPAT_CFLAGS += -DNEEDS_QUICK_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 index 0000000000..734866e5bc --- /dev/null +++ b/compat/qsort.c @@ -0,0 +1,60 @@ +#include "../git-compat-util.h" + +/* This merge sort implementation is simplified from glibc's. */ +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; + + if (size < 1024) { + char buf[size]; /* gcc-ism */ + + /* The temporary array is small, so put it on + the stack. */ + 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); + } +} diff --git a/git-compat-util.h b/git-compat-util.h index 5a81bc9e76..0f92d1d570 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -645,4 +645,10 @@ extern __attribute__((noreturn)) int git_exit(int code); #endif /* __MINGW32__ */ +#ifdef NEEDS_QUICK_QSORT +void git_qsort(void *base, size_t nmemb, size_t size, + int(*compar)(const void *, const void *)); +#define qsort git_qsort +#endif + #endif