зеркало из https://github.com/microsoft/git.git
Simplify topo-sort logic
.. 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:
Родитель
140dd77a5c
Коммит
23c17d4a4a
148
commit.c
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 */
|
||||||
|
|
20
commit.h
20
commit.h
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче