blame: optionally track line fingerprints during fill_blame_origin()

fill_blame_origin() is a convenient place to store data that we will use throughout the lifetime of a blame_origin. Some heuristics for ignoring commits during a blame session can make use of this storage. In particular, we will calculate a fingerprint for each line of a file for blame_origins involved in an ignored commit. In this commit, we only calculate the line_starts, reusing the existing code from the scoreboard's line_starts. In an upcoming commit, we will actually compute the fingerprints. This feature will be used when we attempt to pass blame entries to parents when we "ignore" a commit. Most uses of fill_blame_origin() will not require this feature, hence the flag parameter. Multiple calls to fill_blame_origin() are idempotent, and any of them can request the creation of the fingerprints structure. Suggested-by: Michael Platings <michael@platin.gs> Signed-off-by: Barret Rhoden <brho@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Barret Rhoden committed May 15, 2019 at 17:45 UTC 1fc73384bac289b4907f0adba2a25d0644affa73
2 files changed +62 -30
blame.c
+60 -30
@@ -310,12 +310,58 @@ static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b,
310 return xdi_diff(file_a, file_b, &xpp, &xecfg, &ecb);
311 }
312
313 +static const char *get_next_line(const char *start, const char *end)
314 +{
315 + const char *nl = memchr(start, '\n', end - start);
316 +
317 + return nl ? nl + 1 : end;
318 +}
319 +
320 +static int find_line_starts(int **line_starts, const char *buf,
321 + unsigned long len)
322 +{
323 + const char *end = buf + len;
324 + const char *p;
325 + int *lineno;
326 + int num = 0;
327 +
328 + for (p = buf; p < end; p = get_next_line(p, end))
329 + num++;
330 +
331 + ALLOC_ARRAY(*line_starts, num + 1);
332 + lineno = *line_starts;
333 +
334 + for (p = buf; p < end; p = get_next_line(p, end))
335 + *lineno++ = p - buf;
336 +
337 + *lineno = len;
338 +
339 + return num;
340 +}
341 +
342 +static void fill_origin_fingerprints(struct blame_origin *o, mmfile_t *file)
343 +{
344 + int *line_starts;
345 +
346 + if (o->fingerprints)
347 + return;
348 + o->num_lines = find_line_starts(&line_starts, o->file.ptr,
349 + o->file.size);
350 + /* TODO: Will fill in fingerprints in a future commit */
351 + free(line_starts);
352 +}
353 +
354 +static void drop_origin_fingerprints(struct blame_origin *o)
355 +{
356 +}
357 +
358 /*
359 * Given an origin, prepare mmfile_t structure to be used by the
360 * diff machinery
361 */
362 static void fill_origin_blob(struct diff_options *opt,
318 - struct blame_origin *o, mmfile_t *file, int *num_read_blob)
363 + struct blame_origin *o, mmfile_t *file,
364 + int *num_read_blob, int fill_fingerprints)
365 {
366 if (!o->file.ptr) {
367 enum object_type type;
@@ -339,11 +385,14 @@ static void fill_origin_blob(struct diff_options *opt,
385 }
386 else
387 *file = o->file;
388 + if (fill_fingerprints)
389 + fill_origin_fingerprints(o, file);
390 }
391
392 static void drop_origin_blob(struct blame_origin *o)
393 {
394 FREE_AND_NULL(o->file.ptr);
395 + drop_origin_fingerprints(o);
396 }
397
398 /*
@@ -1140,8 +1189,10 @@ static void pass_blame_to_parent(struct blame_scoreboard *sb,
1189 d.ignore_diffs = ignore_diffs;
1190 d.dstq = &newdest; d.srcq = &target->suspects;
1191
1143 - fill_origin_blob(&sb->revs->diffopt, parent, &file_p, &sb->num_read_blob);
1144 - fill_origin_blob(&sb->revs->diffopt, target, &file_o, &sb->num_read_blob);
1192 + fill_origin_blob(&sb->revs->diffopt, parent, &file_p,
1193 + &sb->num_read_blob, ignore_diffs);
1194 + fill_origin_blob(&sb->revs->diffopt, target, &file_o,
1195 + &sb->num_read_blob, ignore_diffs);
1196 sb->num_get_patch++;
1197
1198 if (diff_hunks(&file_p, &file_o, blame_chunk_cb, &d, sb->xdl_opts))
@@ -1352,7 +1403,8 @@ static void find_move_in_parent(struct blame_scoreboard *sb,
1403 if (!unblamed)
1404 return; /* nothing remains for this target */
1405
1355 - fill_origin_blob(&sb->revs->diffopt, parent, &file_p, &sb->num_read_blob);
1406 + fill_origin_blob(&sb->revs->diffopt, parent, &file_p,
1407 + &sb->num_read_blob, 0);
1408 if (!file_p.ptr)
1409 return;
1410
@@ -1481,7 +1533,8 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
1533 norigin = get_origin(parent, p->one->path);
1534 oidcpy(&norigin->blob_oid, &p->one->oid);
1535 norigin->mode = p->one->mode;
1484 - fill_origin_blob(&sb->revs->diffopt, norigin, &file_p, &sb->num_read_blob);
1536 + fill_origin_blob(&sb->revs->diffopt, norigin, &file_p,
1537 + &sb->num_read_blob, 0);
1538 if (!file_p.ptr)
1539 continue;
1540
@@ -1820,37 +1873,14 @@ void assign_blame(struct blame_scoreboard *sb, int opt)
1873 }
1874 }
1875
1823 -static const char *get_next_line(const char *start, const char *end)
1824 -{
1825 - const char *nl = memchr(start, '\n', end - start);
1826 - return nl ? nl + 1 : end;
1827 -}
1828 -
1876 /*
1877 * To allow quick access to the contents of nth line in the
1878 * final image, prepare an index in the scoreboard.
1879 */
1880 static int prepare_lines(struct blame_scoreboard *sb)
1881 {
1835 - const char *buf = sb->final_buf;
1836 - unsigned long len = sb->final_buf_size;
1837 - const char *end = buf + len;
1838 - const char *p;
1839 - int *lineno;
1840 - int num = 0;
1841 -
1842 - for (p = buf; p < end; p = get_next_line(p, end))
1843 - num++;
1844 -
1845 - ALLOC_ARRAY(sb->lineno, num + 1);
1846 - lineno = sb->lineno;
1847 -
1848 - for (p = buf; p < end; p = get_next_line(p, end))
1849 - *lineno++ = p - buf;
1850 -
1851 - *lineno = len;
1852 -
1853 - sb->num_lines = num;
1882 + sb->num_lines = find_line_starts(&sb->lineno, sb->final_buf,
1883 + sb->final_buf_size);
1884 return sb->num_lines;
1885 }
1886
blame.h
+2
@@ -51,6 +51,8 @@ struct blame_origin {
51 */
52 struct blame_entry *suspects;
53 mmfile_t file;
54 + int num_lines;
55 + void *fingerprints;
56 struct object_id blob_oid;
57 unsigned mode;
58 /* guilty gets set when shipping any suspects to the final