Merge branch 'js/diff-rename-force-stable-sort'

The rename detection logic sorts a list of rename source candidates
by similarity to pick the best candidate, which means that a tie
between sources with the same similarity is broken by the original
location in the original candidate list (which is sorted by path).
Force the sorting by similarity done with a stable sort, which is
not promised by system supplied qsort(3), to ensure consistent
results across platforms.

* js/diff-rename-force-stable-sort:
  diffcore_rename(): use a stable sort
  Move git_sort(), a stable sort, into into libgit.a
This commit is contained in:
Junio C Hamano
2019-10-09 14:00:59 +09:00
5 changed files with 14 additions and 16 deletions

View File

@ -1236,11 +1236,6 @@ static int wenvcmp(const void *a, const void *b)
return _wcsnicmp(p, q, p_len);
}
/* We need a stable sort to convert the environment between UTF-16 <-> UTF-8 */
#ifndef INTERNAL_QSORT
#include "qsort.c"
#endif
/*
* Build an environment block combining the inherited environment
* merged with the given list of settings.
@ -1279,8 +1274,8 @@ static wchar_t *make_environment_block(char **deltaenv)
/*
* If there is a deltaenv, let's accumulate all keys into `array`,
* sort them using the stable git_qsort() and then copy, skipping
* duplicate keys
* sort them using the stable git_stable_qsort() and then copy,
* skipping duplicate keys
*/
for (p = wenv; p && *p; ) {
ALLOC_GROW(array, nr + 1, alloc);
@ -1303,7 +1298,7 @@ static wchar_t *make_environment_block(char **deltaenv)
p += wlen + 1;
}
git_qsort(array, nr, sizeof(*array), wenvcmp);
git_stable_qsort(array, nr, sizeof(*array), wenvcmp);
ALLOC_ARRAY(result, size + delta_size);
for (p = result, i = 0; i < nr; i++) {

View File

@ -1,62 +0,0 @@
#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 = st_mult(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 = xmalloc(size);
msort_with_tmp(b, n, s, cmp, tmp);
free(tmp);
}
}