iterator: advance the tree iterator smartly

While advancing the tree iterator, if we advance over things that
we aren't interested in, then call `current`.  Which may *itself*
call advance.

While advancing the tree iterator, if we advance over things that
we aren't interested in, then call `current`.  Which may *itself*
call advance.

While advancing the tree iterator, if we advance over things that
we aren't interested in, then call `current`.  Which may *itself*
call advance.

While advancing the tree iterator, if we advance over things that
we aren't interested in, then call `current`.  Which may *itself*
call advance.

While advancing the tree iterator, if we advance over things that
we aren't interested in, then call `current`.  Which may *itself*
call advance.

Error: stack overflow.
This commit is contained in:
Edward Thomson 2015-09-11 17:38:28 -04:00
parent 6c21211c38
commit a1859e21f3

View File

@ -640,74 +640,32 @@ static int tree_iterator__current_internal(
return 0;
}
static int tree_iterator__advance(
const git_index_entry **out, git_iterator *self);
static int tree_iterator__current(
const git_index_entry **out, git_iterator *self)
{
const git_index_entry *entry = NULL;
iterator_pathlist__match_t m;
int error;
do {
if ((error = tree_iterator__current_internal(&entry, self)) < 0)
return error;
if (self->pathlist.length) {
m = iterator_pathlist__match(
self, entry->path, strlen(entry->path));
if (m != ITERATOR_PATHLIST_MATCH) {
if ((error = tree_iterator__advance(&entry, self)) < 0)
return error;
entry = NULL;
}
}
} while (!entry);
if (out)
*out = entry;
return error;
}
static int tree_iterator__advance_into(
const git_index_entry **entry, git_iterator *self)
static int tree_iterator__advance_into_internal(git_iterator *self)
{
int error = 0;
tree_iterator *ti = (tree_iterator *)self;
iterator__clear_entry(entry);
if (tree_iterator__at_tree(ti))
error = tree_iterator__push_frame(ti);
if (!error && entry)
error = tree_iterator__current(entry, self);
return error;
}
static int tree_iterator__advance(
const git_index_entry **entry, git_iterator *self)
static int tree_iterator__advance_internal(git_iterator *self)
{
int error;
tree_iterator *ti = (tree_iterator *)self;
tree_iterator_frame *tf = ti->head;
iterator__clear_entry(entry);
if (tf->current >= tf->n_entries)
return GIT_ITEROVER;
if (!iterator__has_been_accessed(ti))
return tree_iterator__current(entry, self);
return 0;
if (iterator__do_autoexpand(ti) && iterator__include_trees(ti) &&
tree_iterator__at_tree(ti))
return tree_iterator__advance_into(entry, self);
return tree_iterator__advance_into_internal(self);
if (ti->path_has_filename) {
git_buf_rtruncate_at_char(&ti->path, '/');
@ -725,7 +683,63 @@ static int tree_iterator__advance(
/* deal with include_trees / auto_expand as needed */
if (!iterator__include_trees(ti) && tree_iterator__at_tree(ti))
return tree_iterator__advance_into(entry, self);
return tree_iterator__advance_into_internal(self);
return 0;
}
static int tree_iterator__current(
const git_index_entry **out, git_iterator *self)
{
const git_index_entry *entry = NULL;
iterator_pathlist__match_t m;
int error;
do {
if ((error = tree_iterator__current_internal(&entry, self)) < 0)
return error;
if (self->pathlist.length) {
m = iterator_pathlist__match(
self, entry->path, strlen(entry->path));
if (m != ITERATOR_PATHLIST_MATCH) {
if ((error = tree_iterator__advance_internal(self)) < 0)
return error;
entry = NULL;
}
}
} while (!entry);
if (out)
*out = entry;
return error;
}
static int tree_iterator__advance(
const git_index_entry **entry, git_iterator *self)
{
int error = tree_iterator__advance_internal(self);
iterator__clear_entry(entry);
if (error < 0)
return error;
return tree_iterator__current(entry, self);
}
static int tree_iterator__advance_into(
const git_index_entry **entry, git_iterator *self)
{
int error = tree_iterator__advance_into_internal(self);
iterator__clear_entry(entry);
if (error < 0)
return error;
return tree_iterator__current(entry, self);
}