mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-21 10:17:20 +00:00
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.
This commit is contained in:
parent
82b1c93d08
commit
8960dc1ec6
@ -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;
|
||||
}
|
||||
|
@ -294,4 +294,19 @@ extern int git_iterator_advance_over_with_status(
|
||||
*/
|
||||
extern int git_iterator_index(git_index **out, git_iterator *iter);
|
||||
|
||||
typedef int (*git_iterator_walk_cb)(
|
||||
const git_index_entry **entries,
|
||||
void *data);
|
||||
|
||||
/**
|
||||
* Walk the given iterators in lock-step. The given callback will be
|
||||
* called for each unique path, with the index entry in each iterator
|
||||
* (or NULL if the given iterator does not contain that path).
|
||||
*/
|
||||
extern int git_iterator_walk(
|
||||
git_iterator **iterators,
|
||||
size_t cnt,
|
||||
git_iterator_walk_cb cb,
|
||||
void *data);
|
||||
|
||||
#endif
|
||||
|
116
src/merge.c
116
src/merge.c
@ -1449,6 +1449,34 @@ static int merge_diff_list_insert_unmodified(
|
||||
return error;
|
||||
}
|
||||
|
||||
struct merge_diff_find_data {
|
||||
git_merge_diff_list *diff_list;
|
||||
struct merge_diff_df_data df_data;
|
||||
};
|
||||
|
||||
static int queue_difference(const git_index_entry **entries, void *data)
|
||||
{
|
||||
struct merge_diff_find_data *find_data = data;
|
||||
bool item_modified = false;
|
||||
size_t i;
|
||||
|
||||
if (!entries[0] || !entries[1] || !entries[2]) {
|
||||
item_modified = true;
|
||||
} else {
|
||||
for (i = 1; i < 3; i++) {
|
||||
if (index_entry_cmp(entries[0], entries[i]) != 0) {
|
||||
item_modified = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return item_modified ?
|
||||
merge_diff_list_insert_conflict(
|
||||
find_data->diff_list, &find_data->df_data, entries) :
|
||||
merge_diff_list_insert_unmodified(find_data->diff_list, entries);
|
||||
}
|
||||
|
||||
int git_merge_diff_list__find_differences(
|
||||
git_merge_diff_list *diff_list,
|
||||
git_iterator *ancestor_iter,
|
||||
@ -1456,93 +1484,9 @@ int git_merge_diff_list__find_differences(
|
||||
git_iterator *their_iter)
|
||||
{
|
||||
git_iterator *iterators[3] = { ancestor_iter, our_iter, their_iter };
|
||||
const git_index_entry *items[3] = {0}, *best_cur_item, *cur_items[3];
|
||||
git_vector_cmp entry_compare = git_index_entry_cmp;
|
||||
struct merge_diff_df_data df_data = {0};
|
||||
int cur_item_modified;
|
||||
size_t i, j;
|
||||
int error = 0;
|
||||
struct merge_diff_find_data find_data = { diff_list };
|
||||
|
||||
assert(diff_list && (our_iter || their_iter));
|
||||
|
||||
/* Set up the iterators */
|
||||
for (i = 0; i < 3; i++) {
|
||||
error = git_iterator_current(&items[i], iterators[i]);
|
||||
|
||||
if (error < 0 && error != GIT_ITEROVER)
|
||||
goto done;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
for (i = 0; i < 3; i++)
|
||||
cur_items[i] = NULL;
|
||||
|
||||
best_cur_item = NULL;
|
||||
cur_item_modified = 0;
|
||||
|
||||
/* Find the next path(s) to consume from each iterator */
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (items[i] == NULL) {
|
||||
cur_item_modified = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (best_cur_item == NULL) {
|
||||
best_cur_item = items[i];
|
||||
cur_items[i] = items[i];
|
||||
} else {
|
||||
int path_diff = entry_compare(items[i], best_cur_item);
|
||||
|
||||
if (path_diff < 0) {
|
||||
/*
|
||||
* Found an item that sorts before our current item, make
|
||||
* our current item this one.
|
||||
*/
|
||||
for (j = 0; j < i; j++)
|
||||
cur_items[j] = NULL;
|
||||
|
||||
cur_item_modified = 1;
|
||||
best_cur_item = items[i];
|
||||
cur_items[i] = items[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] = items[i];
|
||||
|
||||
if (!cur_item_modified)
|
||||
cur_item_modified = index_entry_cmp(best_cur_item, items[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best_cur_item == NULL)
|
||||
break;
|
||||
|
||||
if (cur_item_modified)
|
||||
error = merge_diff_list_insert_conflict(diff_list, &df_data, cur_items);
|
||||
else
|
||||
error = merge_diff_list_insert_unmodified(diff_list, cur_items);
|
||||
if (error < 0)
|
||||
goto done;
|
||||
|
||||
/* Advance each iterator that participated */
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (cur_items[i] == NULL)
|
||||
continue;
|
||||
|
||||
error = git_iterator_advance(&items[i], iterators[i]);
|
||||
|
||||
if (error < 0 && error != GIT_ITEROVER)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (error == GIT_ITEROVER)
|
||||
error = 0;
|
||||
|
||||
return error;
|
||||
return git_iterator_walk(iterators, 3, queue_difference, &find_data);
|
||||
}
|
||||
|
||||
git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo)
|
||||
|
Loading…
Reference in New Issue
Block a user