summaryrefslogtreecommitdiffstats
path: root/xdiff/xutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'xdiff/xutils.c')
-rw-r--r--xdiff/xutils.c86
1 files changed, 67 insertions, 19 deletions
diff --git a/xdiff/xutils.c b/xdiff/xutils.c
index 9e36f24875..447e66c719 100644
--- a/xdiff/xutils.c
+++ b/xdiff/xutils.c
@@ -249,7 +249,7 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
return 1;
}
-static unsigned long xdl_hash_record_with_whitespace(char const **data,
+unsigned long xdl_hash_record_with_whitespace(char const **data,
char const *top, long flags) {
unsigned long ha = 5381;
char const *ptr = *data;
@@ -294,19 +294,67 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
return ha;
}
-unsigned long xdl_hash_record(char const **data, char const *top, long flags) {
- unsigned long ha = 5381;
+/*
+ * Compiler reassociation barrier: pretend to modify X and Y to disallow
+ * changing evaluation order with respect to following uses of X and Y.
+ */
+#ifdef __GNUC__
+#define REASSOC_FENCE(x, y) __asm__("" : "+r"(x), "+r"(y))
+#else
+#define REASSOC_FENCE(x, y)
+#endif
+
+unsigned long xdl_hash_record_verbatim(char const **data, char const *top) {
+ unsigned long ha = 5381, c0, c1;
char const *ptr = *data;
-
- if (flags & XDF_WHITESPACE_FLAGS)
- return xdl_hash_record_with_whitespace(data, top, flags);
-
+#if 0
+ /*
+ * The baseline form of the optimized loop below. This is the djb2
+ * hash (the above function uses a variant with XOR instead of ADD).
+ */
for (; ptr < top && *ptr != '\n'; ptr++) {
ha += (ha << 5);
- ha ^= (unsigned long) *ptr;
+ ha += (unsigned long) *ptr;
}
*data = ptr < top ? ptr + 1: ptr;
-
+#else
+ /* Process two characters per iteration. */
+ if (top - ptr >= 2) do {
+ if ((c0 = ptr[0]) == '\n') {
+ *data = ptr + 1;
+ return ha;
+ }
+ if ((c1 = ptr[1]) == '\n') {
+ *data = ptr + 2;
+ c0 += ha;
+ REASSOC_FENCE(c0, ha);
+ ha = ha * 32 + c0;
+ return ha;
+ }
+ /*
+ * Combine characters C0 and C1 into the hash HA. We have
+ * HA = (HA * 33 + C0) * 33 + C1, and we want to ensure
+ * that dependency chain over HA is just one multiplication
+ * and one addition, i.e. we want to evaluate this as
+ * HA = HA * 33 * 33 + (C0 * 33 + C1), and likewise prefer
+ * (C0 * 32 + (C0 + C1)) for the expression in parenthesis.
+ */
+ ha *= 33 * 33;
+ c1 += c0;
+ REASSOC_FENCE(c1, c0);
+ c1 += c0 * 32;
+ REASSOC_FENCE(c1, ha);
+ ha += c1;
+
+ ptr += 2;
+ } while (ptr < top - 1);
+ *data = top;
+ if (ptr < top && (c0 = ptr[0]) != '\n') {
+ c0 += ha;
+ REASSOC_FENCE(c0, ha);
+ ha = ha * 32 + c0;
+ }
+#endif
return ha;
}
@@ -375,7 +423,7 @@ static int xdl_format_hunk_hdr(long s1, long c1, long s2, long c2,
nb += 3;
if (func && funclen) {
buf[nb++] = ' ';
- if (funclen > sizeof(buf) - nb - 1)
+ if ((size_t)funclen > sizeof(buf) - nb - 1)
funclen = sizeof(buf) - nb - 1;
memcpy(buf + nb, func, funclen);
nb += funclen;
@@ -416,17 +464,17 @@ int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
mmfile_t subfile1, subfile2;
xdfenv_t env;
- subfile1.ptr = (char *)diff_env->xdf1.recs[line1 - 1]->ptr;
- subfile1.size = diff_env->xdf1.recs[line1 + count1 - 2]->ptr +
- diff_env->xdf1.recs[line1 + count1 - 2]->size - subfile1.ptr;
- subfile2.ptr = (char *)diff_env->xdf2.recs[line2 - 1]->ptr;
- subfile2.size = diff_env->xdf2.recs[line2 + count2 - 2]->ptr +
- diff_env->xdf2.recs[line2 + count2 - 2]->size - subfile2.ptr;
+ subfile1.ptr = (char *)diff_env->xdf1.recs[line1 - 1].ptr;
+ subfile1.size = diff_env->xdf1.recs[line1 + count1 - 2].ptr +
+ diff_env->xdf1.recs[line1 + count1 - 2].size - subfile1.ptr;
+ subfile2.ptr = (char *)diff_env->xdf2.recs[line2 - 1].ptr;
+ subfile2.size = diff_env->xdf2.recs[line2 + count2 - 2].ptr +
+ diff_env->xdf2.recs[line2 + count2 - 2].size - subfile2.ptr;
if (xdl_do_diff(&subfile1, &subfile2, xpp, &env) < 0)
return -1;
- memcpy(diff_env->xdf1.rchg + line1 - 1, env.xdf1.rchg, count1);
- memcpy(diff_env->xdf2.rchg + line2 - 1, env.xdf2.rchg, count2);
+ memcpy(diff_env->xdf1.changed + line1 - 1, env.xdf1.changed, count1);
+ memcpy(diff_env->xdf2.changed + line2 - 1, env.xdf2.changed, count2);
xdl_free_env(&env);
@@ -437,7 +485,7 @@ void* xdl_alloc_grow_helper(void *p, long nr, long *alloc, size_t size)
{
void *tmp = NULL;
size_t n = ((LONG_MAX - 16) / 2 >= *alloc) ? 2 * *alloc + 16 : LONG_MAX;
- if (nr > n)
+ if ((size_t)nr > n)
n = nr;
if (SIZE_MAX / size >= n)
tmp = xdl_realloc(p, n * size);