.. by not using quite so much indirection.

This currently grows the "struct commit" a bit, which could be avoided by
using a union for "util" and "indegree" (the topo-sort used to use "util"
anyway, so you cannot use them together), but for now the goal of this was
to simplify, not optimize.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Linus Torvalds 2007-11-02 13:32:58 -07:00 коммит произвёл Junio C Hamano
Родитель 140dd77a5c
Коммит 23c17d4a4a
4 изменённых файлов: 54 добавлений и 125 удалений

148
commit.c
Просмотреть файл

@ -9,22 +9,6 @@
int save_commit_buffer = 1; int save_commit_buffer = 1;
struct sort_node
{
/*
* the number of children of the associated commit
* that also occur in the list being sorted.
*/
unsigned int indegree;
/*
* reference to original list item that we will re-use
* on output.
*/
struct commit_list * list_item;
};
const char *commit_type = "commit"; const char *commit_type = "commit";
static struct cmt_fmt_map { static struct cmt_fmt_map {
@ -1149,69 +1133,38 @@ struct commit *pop_commit(struct commit_list **stack)
return item; return item;
} }
void topo_sort_default_setter(struct commit *c, void *data)
{
c->util = data;
}
void *topo_sort_default_getter(struct commit *c)
{
return c->util;
}
/* /*
* Performs an in-place topological sort on the list supplied. * Performs an in-place topological sort on the list supplied.
*/ */
void sort_in_topological_order(struct commit_list ** list, int lifo) void sort_in_topological_order(struct commit_list ** list, int lifo)
{ {
sort_in_topological_order_fn(list, lifo, topo_sort_default_setter, struct commit_list *next, *orig = *list;
topo_sort_default_getter); struct commit_list *work, **insert;
} struct commit_list **pptr;
void sort_in_topological_order_fn(struct commit_list ** list, int lifo, if (!orig)
topo_sort_set_fn_t setter,
topo_sort_get_fn_t getter)
{
struct commit_list * next = *list;
struct commit_list * work = NULL, **insert;
struct commit_list ** pptr = list;
struct sort_node * nodes;
struct sort_node * next_nodes;
int count = 0;
/* determine the size of the list */
while (next) {
next = next->next;
count++;
}
if (!count)
return; return;
/* allocate an array to help sort the list */ *list = NULL;
nodes = xcalloc(count, sizeof(*nodes));
/* link the list to the array */ /* Mark them and clear the indegree */
next_nodes = nodes; for (next = orig; next; next = next->next) {
next=*list; struct commit *commit = next->item;
while (next) { commit->object.flags |= TOPOSORT;
next_nodes->list_item = next; commit->indegree = 0;
setter(next->item, next_nodes);
next_nodes++;
next = next->next;
} }
/* update the indegree */ /* update the indegree */
next=*list; for (next = orig; next; next = next->next) {
while (next) {
struct commit_list * parents = next->item->parents; struct commit_list * parents = next->item->parents;
while (parents) { while (parents) {
struct commit * parent=parents->item; struct commit *parent = parents->item;
struct sort_node * pn = (struct sort_node *) getter(parent);
if (pn) if (parent->object.flags & TOPOSORT)
pn->indegree++; parent->indegree++;
parents=parents->next; parents = parents->next;
} }
next=next->next;
} }
/* /*
* find the tips * find the tips
* *
@ -1219,55 +1172,56 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
* *
* the tips serve as a starting set for the work queue. * the tips serve as a starting set for the work queue.
*/ */
next=*list; work = NULL;
insert = &work; insert = &work;
while (next) { for (next = orig; next; next = next->next) {
struct sort_node * node = (struct sort_node *) getter(next->item); struct commit *commit = next->item;
if (node->indegree == 0) { if (!commit->indegree)
insert = &commit_list_insert(next->item, insert)->next; insert = &commit_list_insert(commit, insert)->next;
}
next=next->next;
} }
/* process the list in topological order */ /* process the list in topological order */
if (!lifo) if (!lifo)
sort_by_date(&work); sort_by_date(&work);
pptr = list;
*list = NULL;
while (work) { while (work) {
struct commit * work_item = pop_commit(&work); struct commit *commit;
struct sort_node * work_node = (struct sort_node *) getter(work_item); struct commit_list *parents, *work_item;
struct commit_list * parents = work_item->parents;
while (parents) { work_item = work;
struct commit * parent=parents->item; work = work_item->next;
struct sort_node * pn = (struct sort_node *) getter(parent); work_item->next = NULL;
if (pn) { commit = work_item->item;
/* for (parents = commit->parents; parents ; parents = parents->next) {
* parents are only enqueued for emission struct commit *parent=parents->item;
* when all their children have been emitted thereby
* guaranteeing topological order. if (!(parent->object.flags & TOPOSORT))
*/ continue;
pn->indegree--;
if (!pn->indegree) { /*
if (!lifo) * parents are only enqueued for emission
insert_by_date(parent, &work); * when all their children have been emitted thereby
else * guaranteeing topological order.
commit_list_insert(parent, &work); */
} if (!--parent->indegree) {
if (!lifo)
insert_by_date(parent, &work);
else
commit_list_insert(parent, &work);
} }
parents=parents->next;
} }
/* /*
* work_item is a commit all of whose children * work_item is a commit all of whose children
* have already been emitted. we can emit it now. * have already been emitted. we can emit it now.
*/ */
*pptr = work_node->list_item; commit->object.flags &= ~TOPOSORT;
pptr = &(*pptr)->next; *pptr = work_item;
*pptr = NULL; pptr = &work_item->next;
setter(work_item, NULL);
} }
free(nodes);
} }
/* merge-base stuff */ /* merge-base stuff */

Просмотреть файл

@ -14,6 +14,7 @@ struct commit_list {
struct commit { struct commit {
struct object object; struct object object;
void *util; void *util;
unsigned int indegree;
unsigned long date; unsigned long date;
struct commit_list *parents; struct commit_list *parents;
struct tree *tree; struct tree *tree;
@ -84,31 +85,12 @@ void clear_commit_marks(struct commit *commit, unsigned int mark);
/* /*
* Performs an in-place topological sort of list supplied. * Performs an in-place topological sort of list supplied.
* *
* Pre-conditions for sort_in_topological_order:
* all commits in input list and all parents of those
* commits must have object.util == NULL
*
* Pre-conditions for sort_in_topological_order_fn:
* all commits in input list and all parents of those
* commits must have getter(commit) == NULL
*
* Post-conditions:
* invariant of resulting list is: * invariant of resulting list is:
* a reachable from b => ord(b) < ord(a) * a reachable from b => ord(b) < ord(a)
* in addition, when lifo == 0, commits on parallel tracks are * in addition, when lifo == 0, commits on parallel tracks are
* sorted in the dates order. * sorted in the dates order.
*/ */
typedef void (*topo_sort_set_fn_t)(struct commit*, void *data);
typedef void* (*topo_sort_get_fn_t)(struct commit*);
void topo_sort_default_setter(struct commit *c, void *data);
void *topo_sort_default_getter(struct commit *c);
void sort_in_topological_order(struct commit_list ** list, int lifo); void sort_in_topological_order(struct commit_list ** list, int lifo);
void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
topo_sort_set_fn_t setter,
topo_sort_get_fn_t getter);
struct commit_graft { struct commit_graft {
unsigned char sha1[20]; unsigned char sha1[20];

Просмотреть файл

@ -677,9 +677,6 @@ void init_revisions(struct rev_info *revs, const char *prefix)
revs->prune_fn = NULL; revs->prune_fn = NULL;
revs->prune_data = NULL; revs->prune_data = NULL;
revs->topo_setter = topo_sort_default_setter;
revs->topo_getter = topo_sort_default_getter;
revs->commit_format = CMIT_FMT_DEFAULT; revs->commit_format = CMIT_FMT_DEFAULT;
diff_setup(&revs->diffopt); diff_setup(&revs->diffopt);
@ -1303,9 +1300,7 @@ int prepare_revision_walk(struct rev_info *revs)
if (limit_list(revs) < 0) if (limit_list(revs) < 0)
return -1; return -1;
if (revs->topo_order) if (revs->topo_order)
sort_in_topological_order_fn(&revs->commits, revs->lifo, sort_in_topological_order(&revs->commits, revs->lifo);
revs->topo_setter,
revs->topo_getter);
return 0; return 0;
} }

Просмотреть файл

@ -10,6 +10,7 @@
#define CHILD_SHOWN (1u<<6) #define CHILD_SHOWN (1u<<6)
#define ADDED (1u<<7) /* Parents already parsed and added? */ #define ADDED (1u<<7) /* Parents already parsed and added? */
#define SYMMETRIC_LEFT (1u<<8) #define SYMMETRIC_LEFT (1u<<8)
#define TOPOSORT (1u<<9) /* In the active toposort list.. */
struct rev_info; struct rev_info;
struct log_info; struct log_info;
@ -96,9 +97,6 @@ struct rev_info {
struct diff_options diffopt; struct diff_options diffopt;
struct diff_options pruning; struct diff_options pruning;
topo_sort_set_fn_t topo_setter;
topo_sort_get_fn_t topo_getter;
struct reflog_walk_info *reflog_info; struct reflog_walk_info *reflog_info;
}; };