reduce_heads(): reimplement on top of remove_redundant()

This is used by "git merge" and "git merge-base --independent" but used to use a similar N*(N-1) traversals to reject commits that are ancestors of other commits. Reimplement it on top of remove_redundant(). Note that the callers of this function are allowed to pass the same commit more than once, but remove_redundant() is designed to be fed each commit only once. The function removes duplicates before calling remove_redundant(). Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Aug 30, 2012 at 23:20 UTC f37d3c755209234acfc2ca280027ebdab8e9ea8a
1 file changed +18 -38
commit.c
+18 -38
@@ -842,51 +842,31 @@ struct commit_list *reduce_heads(struct commit_list *heads)
842 {
843 struct commit_list *p;
844 struct commit_list *result = NULL, **tail = &result;
845 - struct commit **other;
846 - size_t num_head, num_other;
845 + struct commit **array;
846 + int num_head, i;
847
848 if (!heads)
849 return NULL;
850
851 - /* Avoid unnecessary reallocations */
852 - for (p = heads, num_head = 0; p; p = p->next)
853 - num_head++;
854 - other = xcalloc(sizeof(*other), num_head);
855 -
856 - /* For each commit, see if it can be reached by others */
857 - for (p = heads; p; p = p->next) {
858 - struct commit_list *q, *base;
859 -
860 - /* Do we already have this in the result? */
861 - for (q = result; q; q = q->next)
862 - if (p->item == q->item)
863 - break;
864 - if (q)
851 + /* Uniquify */
852 + for (p = heads; p; p = p->next)
853 + p->item->object.flags &= ~STALE;
854 + for (p = heads, num_head = 0; p; p = p->next) {
855 + if (p->item->object.flags & STALE)
856 continue;
866 -
867 - num_other = 0;
868 - for (q = heads; q; q = q->next) {
869 - if (p->item == q->item)
870 - continue;
871 - other[num_other++] = q->item;
857 + p->item->object.flags |= STALE;
858 + num_head++;
859 + }
860 + array = xcalloc(sizeof(*array), num_head);
861 + for (p = heads, i = 0; p; p = p->next) {
862 + if (p->item->object.flags & STALE) {
863 + array[i++] = p->item;
864 + p->item->object.flags &= ~STALE;
865 }
873 - if (num_other)
874 - base = get_merge_bases_many(p->item, num_other, other, 1);
875 - else
876 - base = NULL;
877 - /*
878 - * If p->item does not have anything common with other
879 - * commits, there won't be any merge base. If it is
880 - * reachable from some of the others, p->item will be
881 - * the merge base. If its history is connected with
882 - * others, but p->item is not reachable by others, we
883 - * will get something other than p->item back.
884 - */
885 - if (!base || (base->item != p->item))
886 - tail = &(commit_list_insert(p->item, tail)->next);
887 - free_commit_list(base);
866 }
889 - free(other);
867 + num_head = remove_redundant(array, num_head);
868 + for (i = 0; i < num_head; i++)
869 + tail = &commit_list_insert(array[i], tail)->next;
870 return result;
871 }
872