summaryrefslogtreecommitdiff
path: root/xdiff/xutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'xdiff/xutils.c')
-rw-r--r--xdiff/xutils.c82
1 files changed, 65 insertions, 17 deletions
diff --git a/xdiff/xutils.c b/xdiff/xutils.c
index 444a108f87..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;
}
@@ -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);