Subject: Re: [PATCH] ref-filter: share bases and is_base_tips between formatting and sorting

From: René Scharfe <[email-masked]>
Date: Sun, 19 Jan 2025 10:11:07 +0100

Am 18.01.25 um 18:11 schrieb René Scharfe:
> I think moving to the right place in one step requires less churn.  Let's
> compare; v2 coming up.

... and this:

---
 ref-filter.c | 49 +++++++++++++++++++++++++++++--------------------
 1 file changed, 29 insertions(+), 20 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index caf28466ab..6da8d4c03b 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -236,6 +236,7 @@ static struct used_atom {
 			       S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option;
 		} signature;
 		struct {
+			char *name;
 			struct commit *commit;
 		} base;
 		struct strvec describe_args;
@@ -245,9 +246,6 @@ static struct used_atom {
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;

-/* List of bases for is-base indicators. */
-static struct string_list is_base_tips = STRING_LIST_INIT_DUP;
-
 /*
  * Expand string, append it to strbuf *sb, then return error code ret.
  * Allow to save few lines of code.
@@ -912,17 +910,15 @@ static int ahead_behind_atom_parser(struct ref_format *format UNUSED,
 }

 static int is_base_atom_parser(struct ref_format *format UNUSED,
-			       struct used_atom *atom UNUSED,
+			       struct used_atom *atom,
 			       const char *arg, struct strbuf *err)
 {
-	struct string_list_item *item;
-
 	if (!arg)
 		return strbuf_addf_ret(err, -1, _("expected format: %%(is-base:<committish>)"));

-	item = string_list_append(&is_base_tips, arg);
-	item->util = lookup_commit_reference_by_name(arg);
-	if (!item->util)
+	atom->u.base.name = xstrdup(arg);
+	atom->u.base.commit = lookup_commit_reference_by_name(arg);
+	if (!atom->u.base.commit)
 		die("failed to find '%s'", arg);

 	return 0;
@@ -3012,6 +3008,8 @@ void ref_array_clear(struct ref_array *array)
 			free(atom->u.head);
 		else if (atom->atom_type == ATOM_DESCRIBE)
 			strvec_clear(&atom->u.describe_args);
+		else if (atom->atom_type == ATOM_ISBASE)
+			free(atom->u.base.name);
 		else if (atom->atom_type == ATOM_TRAILERS ||
 			 (atom->atom_type == ATOM_CONTENTS &&
 			  atom->u.contents.option == C_TRAILERS)) {
@@ -3027,7 +3025,6 @@ void ref_array_clear(struct ref_array *array)
 	}
 	FREE_AND_NULL(used_atom);
 	used_atom_cnt = 0;
-	string_list_clear(&is_base_tips, 0);

 	if (ref_to_worktree_map.worktrees) {
 		hashmap_clear_and_free(&(ref_to_worktree_map.map),
@@ -3140,10 +3137,17 @@ void filter_is_base(struct repository *r,
 		    struct ref_array *array)
 {
 	struct commit **bases;
-	size_t bases_nr = 0;
+	size_t bases_nr = 0, is_base_nr;
 	struct ref_array_item **back_index;

-	if (!is_base_tips.nr || !array->nr)
+	if (!array->nr)
+		return;
+
+	for (size_t i = is_base_nr = 0; i < used_atom_cnt; i++) {
+		if (used_atom[i].atom_type == ATOM_ISBASE)
+			is_base_nr++;
+	}
+	if (!is_base_nr)
 		return;

 	CALLOC_ARRAY(back_index, array->nr);
@@ -3153,7 +3157,7 @@ void filter_is_base(struct repository *r,
 		const char *name = array->items[i]->refname;
 		struct commit *c = lookup_commit_reference_by_name_gently(name, 1);

-		CALLOC_ARRAY(array->items[i]->is_base, is_base_tips.nr);
+		CALLOC_ARRAY(array->items[i]->is_base, is_base_nr);

 		if (!c)
 			continue;
@@ -3163,15 +3167,20 @@ void filter_is_base(struct repository *r,
 		bases_nr++;
 	}

-	for (size_t i = 0; i < is_base_tips.nr; i++) {
-		struct commit *tip = is_base_tips.items[i].util;
-		int base_index = get_branch_base_for_tip(r, tip, bases, bases_nr);
+	for (size_t i = 0, j = 0; i < used_atom_cnt; i++) {
+		struct commit *tip;
+		int base_index;

+		if (used_atom[i].atom_type != ATOM_ISBASE)
+			continue;
+
+		tip = used_atom[i].u.base.commit;
+		base_index = get_branch_base_for_tip(r, tip, bases, bases_nr);
 		if (base_index < 0)
 			continue;

 		/* Store the string for use in output later. */
-		back_index[base_index]->is_base[i] = xstrdup(is_base_tips.items[i].string);
+		back_index[base_index]->is_base[j++] = xstrdup(used_atom[i].u.base.name);
 	}

 	free(back_index);
@@ -3290,10 +3299,10 @@ static inline int can_do_iterative_format(struct ref_filter *filter,
 	for (size_t i = 0; i < used_atom_cnt; i++) {
 		if (used_atom[i].atom_type == ATOM_AHEADBEHIND)
 			return 0;
+		if (used_atom[i].atom_type == ATOM_ISBASE)
+			return 0;
 	}
-	return !(filter->reachable_from ||
-		 filter->unreachable_from ||
-		 is_base_tips.nr);
+	return !(filter->reachable_from || filter->unreachable_from);
 }

 void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
--
2.48.1