mercurial/bdiff.c
changeset 2577 fa76c5d609c9
parent 2543 860e9c83fc59
child 2600 c4325f0a9b91
--- a/mercurial/bdiff.c
+++ b/mercurial/bdiff.c
@@ -65,7 +65,7 @@ static inline uint32_t rol32(uint32_t wo
 
 int splitlines(const char *a, int len, struct line **lr)
 {
-	int h, i;
+	int g, h, i;
 	const char *p, *b = a;
 	struct line *l;
 
@@ -82,7 +82,16 @@ int splitlines(const char *a, int len, s
 	/* build the line array and calculate hashes */
 	h = 0;
 	for (p = a; p < a + len; p++) {
-		h = *p + rol32(h, 7); /* a simple hash from GNU diff */
+		/*
+		 * a simple hash from GNU diff, with better collision
+		 * resistance from hashpjw. this slows down common
+		 * case by 10%, but speeds up worst case by 100x.
+		 */
+		h = *p + rol32(h, 7);
+		if ((g = h & 0xf0000000)) {
+			h ^= g >> 24;
+			h ^= g;
+		}
 		if (*p == '\n' || p == a + len - 1) {
 			l->len = p - b + 1;
 			l->h = h * l->len;