diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2015-06-24 18:10:30 -0400 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2015-06-25 18:34:37 -0400 |
commit | 8960dc1ec69dd87d33e99e5e26b9982132b05113 (patch) | |
tree | 80fc9229ff7eed6b6354bedc1d241e6a17ada3b5 /src/iterator.c | |
parent | 82b1c93d088319c4e385c11ce738b68103eab96c (diff) | |
download | libgit2-8960dc1ec69dd87d33e99e5e26b9982132b05113.tar.gz |
iterator: provide git_iterator_walk
Provide `git_iterator_walk` to walk each iterator in lockstep,
returning each iterator's idea of the contents of the next path.
Diffstat (limited to 'src/iterator.c')
-rw-r--r-- | src/iterator.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/src/iterator.c b/src/iterator.c index d5f7eec34..45eba3955 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -1843,3 +1843,91 @@ int git_iterator_advance_over_with_status( return error; } +int git_iterator_walk( + git_iterator **iterators, + size_t cnt, + git_iterator_walk_cb cb, + void *data) +{ + const git_index_entry **iterator_item; /* next in each iterator */ + const git_index_entry **cur_items; /* current path in each iter */ + const git_index_entry *first_match; + int cur_item_modified; + size_t i, j; + int error = 0; + + iterator_item = git__calloc(cnt, sizeof(git_index_entry *)); + cur_items = git__calloc(cnt, sizeof(git_index_entry *)); + + GITERR_CHECK_ALLOC(iterator_item); + GITERR_CHECK_ALLOC(cur_items); + + /* Set up the iterators */ + for (i = 0; i < cnt; i++) { + error = git_iterator_current(&iterator_item[i], iterators[i]); + + if (error < 0 && error != GIT_ITEROVER) + goto done; + } + + while (true) { + for (i = 0; i < cnt; i++) + cur_items[i] = NULL; + + first_match = NULL; + cur_item_modified = 0; + + /* Find the next path(s) to consume from each iterator */ + for (i = 0; i < cnt; i++) { + if (iterator_item[i] == NULL) + continue; + + if (first_match == NULL) { + first_match = iterator_item[i]; + cur_items[i] = iterator_item[i]; + } else { + int path_diff = git_index_entry_cmp(iterator_item[i], first_match); + + if (path_diff < 0) { + /* Found an index entry that sorts before the one we're + * looking at. Forget that we've seen the other and + * look at the other iterators for this path. + */ + for (j = 0; j < i; j++) + cur_items[j] = NULL; + + first_match = iterator_item[i]; + cur_items[i] = iterator_item[i]; + } else if (path_diff > 0) { + /* No entry for the current item, this is modified */ + cur_item_modified = 1; + } else if (path_diff == 0) { + cur_items[i] = iterator_item[i]; + } + } + } + + if (first_match == NULL) + break; + + if ((error = cb(cur_items, data)) != 0) + goto done; + + /* Advance each iterator that participated */ + for (i = 0; i < cnt; i++) { + if (cur_items[i] == NULL) + continue; + + error = git_iterator_advance(&iterator_item[i], iterators[i]); + + if (error < 0 && error != GIT_ITEROVER) + goto done; + } + } + +done: + if (error == GIT_ITEROVER) + error = 0; + + return error; +} |