summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-09-06 14:20:51 -0700
committerRussell Belfer <rb@github.com>2013-09-06 14:20:51 -0700
commit32e49929725a76d9871038f30e2ea67fe0e4a4f8 (patch)
tree2cbcbb0d469c67c84d2ca26dc1b2b4c696bbe65a
parent97affdf2134d91c88fca6adbb6eeb0d990d01a31 (diff)
parentfb23d05f0bc3084cdb5a9737b1c678817c5bc9e8 (diff)
downloadlibgit2-32e49929725a76d9871038f30e2ea67fe0e4a4f8.tar.gz
Merge pull request #1791 from libgit2/cmn/revwalk-recursive
revwalk: make mark_unintersting use a loop
-rw-r--r--src/array.h2
-rw-r--r--src/revwalk.c42
2 files changed, 34 insertions, 10 deletions
diff --git a/src/array.h b/src/array.h
index c25a1b29e..b82079bd8 100644
--- a/src/array.h
+++ b/src/array.h
@@ -63,6 +63,8 @@ GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
#define git_array_last(a) ((a).size ? &(a).ptr[(a).size - 1] : NULL)
+#define git_array_pop(a) ((a).size ? &(a).ptr[--(a).size] : NULL)
+
#define git_array_get(a, i) (((i) < (a).size) ? &(a).ptr[(i)] : NULL)
#define git_array_size(a) (a).size
diff --git a/src/revwalk.c b/src/revwalk.c
index 528d02b20..1ff41bfb1 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -41,28 +41,50 @@ git_commit_list_node *git_revwalk__commit_lookup(
return commit;
}
-static void mark_uninteresting(git_commit_list_node *commit)
+static int mark_uninteresting(git_commit_list_node *commit)
{
unsigned short i;
+ git_array_t(git_commit_list_node *) pending = GIT_ARRAY_INIT;
+ git_commit_list_node **tmp;
+
assert(commit);
- commit->uninteresting = 1;
+ git_array_alloc(pending);
+ GITERR_CHECK_ARRAY(pending);
- /* This means we've reached a merge base, so there's no need to walk any more */
- if ((commit->flags & (RESULT | STALE)) == RESULT)
- return;
+ do {
+ commit->uninteresting = 1;
+
+ /* This means we've reached a merge base, so there's no need to walk any more */
+ if ((commit->flags & (RESULT | STALE)) == RESULT) {
+ tmp = git_array_pop(pending);
+ commit = tmp ? *tmp : NULL;
+ continue;
+ }
+
+ for (i = 0; i < commit->out_degree; ++i)
+ if (!commit->parents[i]->uninteresting) {
+ git_commit_list_node **node = git_array_alloc(pending);
+ GITERR_CHECK_ALLOC(node);
+ *node = commit->parents[i];
+ }
+
+ tmp = git_array_pop(pending);
+ commit = tmp ? *tmp : NULL;
+
+ } while (git_array_size(pending) > 0);
- for (i = 0; i < commit->out_degree; ++i)
- if (!commit->parents[i]->uninteresting)
- mark_uninteresting(commit->parents[i]);
+ git_array_clear(pending);
+
+ return 0;
}
static int process_commit(git_revwalk *walk, git_commit_list_node *commit, int hide)
{
int error;
- if (hide)
- mark_uninteresting(commit);
+ if (hide && mark_uninteresting(commit) < 0)
+ return -1;
if (commit->seen)
return 0;