summaryrefslogtreecommitdiff
path: root/src/iterator.c
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2015-06-24 18:10:30 -0400
committerEdward Thomson <ethomson@edwardthomson.com>2015-06-25 18:34:37 -0400
commit8960dc1ec69dd87d33e99e5e26b9982132b05113 (patch)
tree80fc9229ff7eed6b6354bedc1d241e6a17ada3b5 /src/iterator.c
parent82b1c93d088319c4e385c11ce738b68103eab96c (diff)
downloadlibgit2-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.c88
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;
+}