xdiff: remove "line_hash" field from xrecord_t

Prior to commit 6a26019c81 (xdiff: split xrecord_t.ha into line_hash and minimal_perfect_hash, 2025-11-18) the "ha" field of xrecord_t initially held the "line_hash" value and once the line had been interned that field was updated to hold the "minimal_perfect_hash". The "line_hash" is only used to intern the line so there is no point in storing it after all the input lines have been interned. Removing the "line_hash" field from xrecord_t and storing it in xdlclass_t where it is actually used makes it clearer that it is a temporary value and it should not be used once we're calculated the "minimal_perfect_hash". This also reduces the size of xrecord_t by 25% on 64-bit platforms and 40% on 32-bit platforms. While the struct is small we create one instance per input line so any saving is welcome. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Phillip Wood committed Jan 26, 2026 at 10:48 UTC c27afcbfd0f440f410758432e2fe11a16fb2b360
2 files changed +7 -6
xdiff/xprepare.c
+7 -5
@@ -34,6 +34,7 @@
34 #define INVESTIGATE 2
35
36 typedef struct s_xdlclass {
37 + uint64_t line_hash;
38 struct s_xdlclass *next;
39 xrecord_t rec;
40 long idx;
@@ -92,13 +93,14 @@ static void xdl_free_classifier(xdlclassifier_t *cf) {
93 }
94
95
95 -static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t *rec) {
96 +static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t *rec,
97 + uint64_t line_hash) {
98 size_t hi;
99 xdlclass_t *rcrec;
100
99 - hi = XDL_HASHLONG(rec->line_hash, cf->hbits);
101 + hi = XDL_HASHLONG(line_hash, cf->hbits);
102 for (rcrec = cf->rchash[hi]; rcrec; rcrec = rcrec->next)
101 - if (rcrec->rec.line_hash == rec->line_hash &&
103 + if (rcrec->line_hash == line_hash &&
104 xdl_recmatch((const char *)rcrec->rec.ptr, (long)rcrec->rec.size,
105 (const char *)rec->ptr, (long)rec->size, cf->flags))
106 break;
@@ -112,6 +114,7 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t
114 if (XDL_ALLOC_GROW(cf->rcrecs, cf->count, cf->alloc))
115 return -1;
116 cf->rcrecs[rcrec->idx] = rcrec;
117 + rcrec->line_hash = line_hash;
118 rcrec->rec = *rec;
119 rcrec->len1 = rcrec->len2 = 0;
120 rcrec->next = cf->rchash[hi];
@@ -158,8 +161,7 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
161 crec = &xdf->recs[xdf->nrec++];
162 crec->ptr = prev;
163 crec->size = cur - prev;
161 - crec->line_hash = hav;
162 - if (xdl_classify_record(pass, cf, crec) < 0)
164 + if (xdl_classify_record(pass, cf, crec, hav) < 0)
165 goto abort;
166 }
167 }
xdiff/xtypes.h
-1
@@ -41,7 +41,6 @@ typedef struct s_chastore {
41 typedef struct s_xrecord {
42 uint8_t const *ptr;
43 size_t size;
44 - uint64_t line_hash;
44 size_t minimal_perfect_hash;
45 } xrecord_t;
46