aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2025-02-03 10:23:33 -0800
committerJunio C Hamano <gitster@pobox.com>2025-02-03 10:23:33 -0800
commitc43136d67b7c6a9ecfa988004eb4a87bfbe957a0 (patch)
treecc4c17eed6328f3baa142c811aec4eec7005e690
parentMerge branch 'tb/unsafe-hash-cleanup' (diff)
parenttree-diff: make list tail-passing more explicit (diff)
downloadgit-c43136d67b7c6a9ecfa988004eb4a87bfbe957a0.tar.gz
git-c43136d67b7c6a9ecfa988004eb4a87bfbe957a0.zip
Merge branch 'jk/combine-diff-cleanup'
Code clean-up for code paths around combined diff. * jk/combine-diff-cleanup: tree-diff: make list tail-passing more explicit tree-diff: simplify emit_path() list management tree-diff: use the name "tail" to refer to list tail tree-diff: drop list-tail argument to diff_tree_paths() combine-diff: drop public declaration of combine_diff_path_size() tree-diff: inline path_appendnew() tree-diff: pass whole path string to path_appendnew() tree-diff: drop path_appendnew() alloc optimization run_diff_files(): de-mystify the size of combine_diff_path struct diff: add a comment about combine_diff_path.parent.path combine-diff: use pointer for parent paths tree-diff: clear parent array in path_appendnew() combine-diff: add combine_diff_path_new() run_diff_files(): delay allocation of combine_diff_path
-rw-r--r--combine-diff.c80
-rw-r--r--diff-lib.c36
-rw-r--r--diff.h18
-rw-r--r--tree-diff.c152
4 files changed, 102 insertions, 184 deletions
diff --git a/combine-diff.c b/combine-diff.c
index 641bc92dbd..9527f3160d 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -47,31 +47,20 @@ static struct combine_diff_path *intersect_paths(
if (!n) {
for (i = 0; i < q->nr; i++) {
- int len;
- const char *path;
if (diff_unmodified_pair(q->queue[i]))
continue;
- path = q->queue[i]->two->path;
- len = strlen(path);
- p = xmalloc(combine_diff_path_size(num_parent, len));
- p->path = (char *) &(p->parent[num_parent]);
- memcpy(p->path, path, len);
- p->path[len] = 0;
- p->next = NULL;
- memset(p->parent, 0,
- sizeof(p->parent[0]) * num_parent);
-
- oidcpy(&p->oid, &q->queue[i]->two->oid);
- p->mode = q->queue[i]->two->mode;
+ p = combine_diff_path_new(q->queue[i]->two->path,
+ strlen(q->queue[i]->two->path),
+ q->queue[i]->two->mode,
+ &q->queue[i]->two->oid,
+ num_parent);
oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid);
p->parent[n].mode = q->queue[i]->one->mode;
p->parent[n].status = q->queue[i]->status;
if (combined_all_paths &&
filename_changed(p->parent[n].status)) {
- strbuf_init(&p->parent[n].path, 0);
- strbuf_addstr(&p->parent[n].path,
- q->queue[i]->one->path);
+ p->parent[n].path = xstrdup(q->queue[i]->one->path);
}
*tail = p;
tail = &p->next;
@@ -92,9 +81,7 @@ static struct combine_diff_path *intersect_paths(
/* p->path not in q->queue[]; drop it */
*tail = p->next;
for (j = 0; j < num_parent; j++)
- if (combined_all_paths &&
- filename_changed(p->parent[j].status))
- strbuf_release(&p->parent[j].path);
+ free(p->parent[j].path);
free(p);
continue;
}
@@ -110,8 +97,7 @@ static struct combine_diff_path *intersect_paths(
p->parent[n].status = q->queue[i]->status;
if (combined_all_paths &&
filename_changed(p->parent[n].status))
- strbuf_addstr(&p->parent[n].path,
- q->queue[i]->one->path);
+ p->parent[n].path = xstrdup(q->queue[i]->one->path);
tail = &p->next;
i++;
@@ -996,8 +982,9 @@ static void show_combined_header(struct combine_diff_path *elem,
if (rev->combined_all_paths) {
for (i = 0; i < num_parent; i++) {
- char *path = filename_changed(elem->parent[i].status)
- ? elem->parent[i].path.buf : elem->path;
+ const char *path = elem->parent[i].path ?
+ elem->parent[i].path :
+ elem->path;
if (elem->parent[i].status == DIFF_STATUS_ADDED)
dump_quoted_path("--- ", "", "/dev/null",
line_prefix, c_meta, c_reset);
@@ -1278,12 +1265,10 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
for (i = 0; i < num_parent; i++)
if (rev->combined_all_paths) {
- if (filename_changed(p->parent[i].status))
- write_name_quoted(p->parent[i].path.buf, stdout,
- inter_name_termination);
- else
- write_name_quoted(p->path, stdout,
- inter_name_termination);
+ const char *path = p->parent[i].path ?
+ p->parent[i].path :
+ p->path;
+ write_name_quoted(path, stdout, inter_name_termination);
}
write_name_quoted(p->path, stdout, line_termination);
}
@@ -1443,22 +1428,19 @@ static struct combine_diff_path *find_paths_multitree(
{
int i, nparent = parents->nr;
const struct object_id **parents_oid;
- struct combine_diff_path paths_head;
+ struct combine_diff_path *paths;
struct strbuf base;
ALLOC_ARRAY(parents_oid, nparent);
for (i = 0; i < nparent; i++)
parents_oid[i] = &parents->oid[i];
- /* fake list head, so worker can assume it is non-NULL */
- paths_head.next = NULL;
-
strbuf_init(&base, PATH_MAX);
- diff_tree_paths(&paths_head, oid, parents_oid, nparent, &base, opt);
+ paths = diff_tree_paths(oid, parents_oid, nparent, &base, opt);
strbuf_release(&base);
free(parents_oid);
- return paths_head.next;
+ return paths;
}
static int match_objfind(struct combine_diff_path *path,
@@ -1645,9 +1627,7 @@ void diff_tree_combined(const struct object_id *oid,
struct combine_diff_path *tmp = paths;
paths = paths->next;
for (i = 0; i < num_parent; i++)
- if (rev->combined_all_paths &&
- filename_changed(tmp->parent[i].status))
- strbuf_release(&tmp->parent[i].path);
+ free(tmp->parent[i].path);
free(tmp);
}
@@ -1667,3 +1647,25 @@ void diff_tree_combined_merge(const struct commit *commit,
diff_tree_combined(&commit->object.oid, &parents, rev);
oid_array_clear(&parents);
}
+
+struct combine_diff_path *combine_diff_path_new(const char *path,
+ size_t path_len,
+ unsigned int mode,
+ const struct object_id *oid,
+ size_t num_parents)
+{
+ struct combine_diff_path *p;
+ size_t parent_len = st_mult(sizeof(p->parent[0]), num_parents);
+
+ p = xmalloc(st_add4(sizeof(*p), path_len, 1, parent_len));
+ p->path = (char *)&(p->parent[num_parents]);
+ memcpy(p->path, path, path_len);
+ p->path[path_len] = 0;
+ p->next = NULL;
+ p->mode = mode;
+ oidcpy(&p->oid, oid);
+
+ memset(p->parent, 0, parent_len);
+
+ return p;
+}
diff --git a/diff-lib.c b/diff-lib.c
index c6d3bc4d37..353b473ed5 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -153,21 +153,8 @@ void run_diff_files(struct rev_info *revs, unsigned int option)
struct diff_filepair *pair;
unsigned int wt_mode = 0;
int num_compare_stages = 0;
- size_t path_len;
struct stat st;
- path_len = ce_namelen(ce);
-
- dpath = xmalloc(combine_diff_path_size(5, path_len));
- dpath->path = (char *) &(dpath->parent[5]);
-
- dpath->next = NULL;
- memcpy(dpath->path, ce->name, path_len);
- dpath->path[path_len] = '\0';
- oidclr(&dpath->oid, the_repository->hash_algo);
- memset(&(dpath->parent[0]), 0,
- sizeof(struct combine_diff_parent)*5);
-
changed = check_removed(ce, &st);
if (!changed)
wt_mode = ce_mode_from_stat(ce, st.st_mode);
@@ -178,7 +165,14 @@ void run_diff_files(struct rev_info *revs, unsigned int option)
}
wt_mode = 0;
}
- dpath->mode = wt_mode;
+
+ /*
+ * Allocate space for two parents, which will come from
+ * index stages #2 and #3, if present. Below we'll fill
+ * these from (stage - 2).
+ */
+ dpath = combine_diff_path_new(ce->name, ce_namelen(ce),
+ wt_mode, null_oid(), 2);
while (i < entries) {
struct cache_entry *nce = istate->cache[i];
@@ -405,16 +399,10 @@ static int show_modified(struct rev_info *revs,
if (revs->combine_merges && !cached &&
(!oideq(oid, &old_entry->oid) || !oideq(&old_entry->oid, &new_entry->oid))) {
struct combine_diff_path *p;
- int pathlen = ce_namelen(new_entry);
-
- p = xmalloc(combine_diff_path_size(2, pathlen));
- p->path = (char *) &p->parent[2];
- p->next = NULL;
- memcpy(p->path, new_entry->name, pathlen);
- p->path[pathlen] = 0;
- p->mode = mode;
- oidclr(&p->oid, the_repository->hash_algo);
- memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent));
+
+ p = combine_diff_path_new(new_entry->name,
+ ce_namelen(new_entry),
+ mode, null_oid(), 2);
p->parent[0].status = DIFF_STATUS_MODIFIED;
p->parent[0].mode = new_entry->ce_mode;
oidcpy(&p->parent[0].oid, &new_entry->oid);
diff --git a/diff.h b/diff.h
index 6e6007c17b..7831ed1a2b 100644
--- a/diff.h
+++ b/diff.h
@@ -462,7 +462,7 @@ const char *diff_line_prefix(struct diff_options *);
extern const char mime_boundary_leader[];
struct combine_diff_path *diff_tree_paths(
- struct combine_diff_path *p, const struct object_id *oid,
+ const struct object_id *oid,
const struct object_id **parents_oid, int nparent,
struct strbuf *base, struct diff_options *opt);
void diff_tree_oid(const struct object_id *old_oid,
@@ -480,12 +480,20 @@ struct combine_diff_path {
char status;
unsigned int mode;
struct object_id oid;
- struct strbuf path;
+ /*
+ * This per-parent path is filled only when doing a combined
+ * diff with revs.combined_all_paths set, and only if the path
+ * differs from the post-image (e.g., a rename or copy).
+ * Otherwise it is left NULL.
+ */
+ char *path;
} parent[FLEX_ARRAY];
};
-#define combine_diff_path_size(n, l) \
- st_add4(sizeof(struct combine_diff_path), (l), 1, \
- st_mult(sizeof(struct combine_diff_parent), (n)))
+struct combine_diff_path *combine_diff_path_new(const char *path,
+ size_t path_len,
+ unsigned int mode,
+ const struct object_id *oid,
+ size_t num_parents);
void show_combined_diff(struct combine_diff_path *elem, int num_parent,
struct rev_info *);
diff --git a/tree-diff.c b/tree-diff.c
index d9237ffd9b..60c558c2b5 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -48,8 +48,8 @@
free((x)); \
} while(0)
-static struct combine_diff_path *ll_diff_tree_paths(
- struct combine_diff_path *p, const struct object_id *oid,
+static void ll_diff_tree_paths(
+ struct combine_diff_path ***tail, const struct object_id *oid,
const struct object_id **parents_oid, int nparent,
struct strbuf *base, struct diff_options *opt,
int depth);
@@ -125,72 +125,6 @@ static int emit_diff_first_parent_only(struct diff_options *opt, struct combine_
/*
- * Make a new combine_diff_path from path/mode/sha1
- * and append it to paths list tail.
- *
- * Memory for created elements could be reused:
- *
- * - if last->next == NULL, the memory is allocated;
- *
- * - if last->next != NULL, it is assumed that p=last->next was returned
- * earlier by this function, and p->next was *not* modified.
- * The memory is then reused from p.
- *
- * so for clients,
- *
- * - if you do need to keep the element
- *
- * p = path_appendnew(p, ...);
- * process(p);
- * p->next = NULL;
- *
- * - if you don't need to keep the element after processing
- *
- * pprev = p;
- * p = path_appendnew(p, ...);
- * process(p);
- * p = pprev;
- * ; don't forget to free tail->next in the end
- *
- * p->parent[] remains uninitialized.
- */
-static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,
- int nparent, const struct strbuf *base, const char *path, int pathlen,
- unsigned mode, const struct object_id *oid)
-{
- struct combine_diff_path *p;
- size_t len = st_add(base->len, pathlen);
- size_t alloclen = combine_diff_path_size(nparent, len);
-
- /* if last->next is !NULL - it is a pre-allocated memory, we can reuse */
- p = last->next;
- if (p && (alloclen > (intptr_t)p->next)) {
- FREE_AND_NULL(p);
- }
-
- if (!p) {
- p = xmalloc(alloclen);
-
- /*
- * until we go to it next round, .next holds how many bytes we
- * allocated (for faster realloc - we don't need copying old data).
- */
- p->next = (struct combine_diff_path *)(intptr_t)alloclen;
- }
-
- last->next = p;
-
- p->path = (char *)&(p->parent[nparent]);
- memcpy(p->path, base->buf, base->len);
- memcpy(p->path + base->len, path, pathlen);
- p->path[len] = 0;
- p->mode = mode;
- oidcpy(&p->oid, oid ? oid : null_oid());
-
- return p;
-}
-
-/*
* new path should be added to combine diff
*
* 3 cases on how/when it should be called and behaves:
@@ -200,10 +134,10 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,
* t, tp -> path modified/added
* (M for tp[i]=tp[imin], A otherwise)
*/
-static struct combine_diff_path *emit_path(struct combine_diff_path *p,
- struct strbuf *base, struct diff_options *opt, int nparent,
- struct tree_desc *t, struct tree_desc *tp,
- int imin, int depth)
+static void emit_path(struct combine_diff_path ***tail,
+ struct strbuf *base, struct diff_options *opt,
+ int nparent, struct tree_desc *t, struct tree_desc *tp,
+ int imin, int depth)
{
unsigned short mode;
const char *path;
@@ -243,8 +177,13 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
if (emitthis) {
int keep;
- struct combine_diff_path *pprev = p;
- p = path_appendnew(p, nparent, base, path, pathlen, mode, oid);
+ struct combine_diff_path *p;
+
+ strbuf_add(base, path, pathlen);
+ p = combine_diff_path_new(base->buf, base->len, mode,
+ oid ? oid : null_oid(),
+ nparent);
+ strbuf_setlen(base, old_baselen);
for (i = 0; i < nparent; ++i) {
/*
@@ -279,21 +218,12 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
if (opt->pathchange)
keep = opt->pathchange(opt, p);
- /*
- * If a path was filtered or consumed - we don't need to add it
- * to the list and can reuse its memory, leaving it as
- * pre-allocated element on the tail.
- *
- * On the other hand, if path needs to be kept, we need to
- * correct its .next to NULL, as it was pre-initialized to how
- * much memory was allocated.
- *
- * see path_appendnew() for details.
- */
- if (!keep)
- p = pprev;
- else
- p->next = NULL;
+ if (keep) {
+ **tail = p;
+ *tail = &p->next;
+ } else {
+ free(p);
+ }
}
if (recurse) {
@@ -309,13 +239,12 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
strbuf_add(base, path, pathlen);
strbuf_addch(base, '/');
- p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt,
- depth + 1);
+ ll_diff_tree_paths(tail, oid, parents_oid, nparent, base, opt,
+ depth + 1);
FAST_ARRAY_FREE(parents_oid, nparent);
}
strbuf_setlen(base, old_baselen);
- return p;
}
static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
@@ -428,8 +357,8 @@ static inline void update_tp_entries(struct tree_desc *tp, int nparent)
update_tree_entry(&tp[i]);
}
-static struct combine_diff_path *ll_diff_tree_paths(
- struct combine_diff_path *p, const struct object_id *oid,
+static void ll_diff_tree_paths(
+ struct combine_diff_path ***tail, const struct object_id *oid,
const struct object_id **parents_oid, int nparent,
struct strbuf *base, struct diff_options *opt,
int depth)
@@ -533,8 +462,8 @@ static struct combine_diff_path *ll_diff_tree_paths(
}
/* D += {δ(t,pi) if pi=p[imin]; "+a" if pi > p[imin]} */
- p = emit_path(p, base, opt, nparent,
- &t, tp, imin, depth);
+ emit_path(tail, base, opt, nparent,
+ &t, tp, imin, depth);
skip_emit_t_tp:
/* t↓, ∀ pi=p[imin] pi↓ */
@@ -545,8 +474,8 @@ static struct combine_diff_path *ll_diff_tree_paths(
/* t < p[imin] */
else if (cmp < 0) {
/* D += "+t" */
- p = emit_path(p, base, opt, nparent,
- &t, /*tp=*/NULL, -1, depth);
+ emit_path(tail, base, opt, nparent,
+ &t, /*tp=*/NULL, -1, depth);
/* t↓ */
update_tree_entry(&t);
@@ -561,8 +490,8 @@ static struct combine_diff_path *ll_diff_tree_paths(
goto skip_emit_tp;
}
- p = emit_path(p, base, opt, nparent,
- /*t=*/NULL, tp, imin, depth);
+ emit_path(tail, base, opt, nparent,
+ /*t=*/NULL, tp, imin, depth);
skip_emit_tp:
/* ∀ pi=p[imin] pi↓ */
@@ -575,24 +504,16 @@ static struct combine_diff_path *ll_diff_tree_paths(
free(tptree[i]);
FAST_ARRAY_FREE(tptree, nparent);
FAST_ARRAY_FREE(tp, nparent);
-
- return p;
}
struct combine_diff_path *diff_tree_paths(
- struct combine_diff_path *p, const struct object_id *oid,
+ const struct object_id *oid,
const struct object_id **parents_oid, int nparent,
struct strbuf *base, struct diff_options *opt)
{
- p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt, 0);
-
- /*
- * free pre-allocated last element, if any
- * (see path_appendnew() for details about why)
- */
- FREE_AND_NULL(p->next);
-
- return p;
+ struct combine_diff_path *head = NULL, **tail = &head;
+ ll_diff_tree_paths(&tail, oid, parents_oid, nparent, base, opt, 0);
+ return head;
}
/*
@@ -708,14 +629,13 @@ static void ll_diff_tree_oid(const struct object_id *old_oid,
const struct object_id *new_oid,
struct strbuf *base, struct diff_options *opt)
{
- struct combine_diff_path phead, *p;
+ struct combine_diff_path *paths, *p;
pathchange_fn_t pathchange_old = opt->pathchange;
- phead.next = NULL;
opt->pathchange = emit_diff_first_parent_only;
- diff_tree_paths(&phead, new_oid, &old_oid, 1, base, opt);
+ paths = diff_tree_paths(new_oid, &old_oid, 1, base, opt);
- for (p = phead.next; p;) {
+ for (p = paths; p;) {
struct combine_diff_path *pprev = p;
p = p->next;
free(pprev);