Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8960dc1

Browse files
committed
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.
1 parent 82b1c93 commit 8960dc1

File tree

3 files changed

+133
-86
lines changed

3 files changed

+133
-86
lines changed

src/iterator.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,3 +1843,91 @@ int git_iterator_advance_over_with_status(
18431843
return error;
18441844
}
18451845

1846+
int git_iterator_walk(
1847+
git_iterator **iterators,
1848+
size_t cnt,
1849+
git_iterator_walk_cb cb,
1850+
void *data)
1851+
{
1852+
const git_index_entry **iterator_item; /* next in each iterator */
1853+
const git_index_entry **cur_items; /* current path in each iter */
1854+
const git_index_entry *first_match;
1855+
int cur_item_modified;
1856+
size_t i, j;
1857+
int error = 0;
1858+
1859+
iterator_item = git__calloc(cnt, sizeof(git_index_entry *));
1860+
cur_items = git__calloc(cnt, sizeof(git_index_entry *));
1861+
1862+
GITERR_CHECK_ALLOC(iterator_item);
1863+
GITERR_CHECK_ALLOC(cur_items);
1864+
1865+
/* Set up the iterators */
1866+
for (i = 0; i < cnt; i++) {
1867+
error = git_iterator_current(&iterator_item[i], iterators[i]);
1868+
1869+
if (error < 0 && error != GIT_ITEROVER)
1870+
goto done;
1871+
}
1872+
1873+
while (true) {
1874+
for (i = 0; i < cnt; i++)
1875+
cur_items[i] = NULL;
1876+
1877+
first_match = NULL;
1878+
cur_item_modified = 0;
1879+
1880+
/* Find the next path(s) to consume from each iterator */
1881+
for (i = 0; i < cnt; i++) {
1882+
if (iterator_item[i] == NULL)
1883+
continue;
1884+
1885+
if (first_match == NULL) {
1886+
first_match = iterator_item[i];
1887+
cur_items[i] = iterator_item[i];
1888+
} else {
1889+
int path_diff = git_index_entry_cmp(iterator_item[i], first_match);
1890+
1891+
if (path_diff < 0) {
1892+
/* Found an index entry that sorts before the one we're
1893+
* looking at. Forget that we've seen the other and
1894+
* look at the other iterators for this path.
1895+
*/
1896+
for (j = 0; j < i; j++)
1897+
cur_items[j] = NULL;
1898+
1899+
first_match = iterator_item[i];
1900+
cur_items[i] = iterator_item[i];
1901+
} else if (path_diff > 0) {
1902+
/* No entry for the current item, this is modified */
1903+
cur_item_modified = 1;
1904+
} else if (path_diff == 0) {
1905+
cur_items[i] = iterator_item[i];
1906+
}
1907+
}
1908+
}
1909+
1910+
if (first_match == NULL)
1911+
break;
1912+
1913+
if ((error = cb(cur_items, data)) != 0)
1914+
goto done;
1915+
1916+
/* Advance each iterator that participated */
1917+
for (i = 0; i < cnt; i++) {
1918+
if (cur_items[i] == NULL)
1919+
continue;
1920+
1921+
error = git_iterator_advance(&iterator_item[i], iterators[i]);
1922+
1923+
if (error < 0 && error != GIT_ITEROVER)
1924+
goto done;
1925+
}
1926+
}
1927+
1928+
done:
1929+
if (error == GIT_ITEROVER)
1930+
error = 0;
1931+
1932+
return error;
1933+
}

src/iterator.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,19 @@ extern int git_iterator_advance_over_with_status(
294294
*/
295295
extern int git_iterator_index(git_index **out, git_iterator *iter);
296296

297+
typedef int (*git_iterator_walk_cb)(
298+
const git_index_entry **entries,
299+
void *data);
300+
301+
/**
302+
* Walk the given iterators in lock-step. The given callback will be
303+
* called for each unique path, with the index entry in each iterator
304+
* (or NULL if the given iterator does not contain that path).
305+
*/
306+
extern int git_iterator_walk(
307+
git_iterator **iterators,
308+
size_t cnt,
309+
git_iterator_walk_cb cb,
310+
void *data);
311+
297312
#endif

src/merge.c

Lines changed: 30 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,100 +1449,44 @@ static int merge_diff_list_insert_unmodified(
14491449
return error;
14501450
}
14511451

1452+
struct merge_diff_find_data {
1453+
git_merge_diff_list *diff_list;
1454+
struct merge_diff_df_data df_data;
1455+
};
1456+
1457+
static int queue_difference(const git_index_entry **entries, void *data)
1458+
{
1459+
struct merge_diff_find_data *find_data = data;
1460+
bool item_modified = false;
1461+
size_t i;
1462+
1463+
if (!entries[0] || !entries[1] || !entries[2]) {
1464+
item_modified = true;
1465+
} else {
1466+
for (i = 1; i < 3; i++) {
1467+
if (index_entry_cmp(entries[0], entries[i]) != 0) {
1468+
item_modified = true;
1469+
break;
1470+
}
1471+
}
1472+
}
1473+
1474+
return item_modified ?
1475+
merge_diff_list_insert_conflict(
1476+
find_data->diff_list, &find_data->df_data, entries) :
1477+
merge_diff_list_insert_unmodified(find_data->diff_list, entries);
1478+
}
1479+
14521480
int git_merge_diff_list__find_differences(
14531481
git_merge_diff_list *diff_list,
14541482
git_iterator *ancestor_iter,
14551483
git_iterator *our_iter,
14561484
git_iterator *their_iter)
14571485
{
14581486
git_iterator *iterators[3] = { ancestor_iter, our_iter, their_iter };
1459-
const git_index_entry *items[3] = {0}, *best_cur_item, *cur_items[3];
1460-
git_vector_cmp entry_compare = git_index_entry_cmp;
1461-
struct merge_diff_df_data df_data = {0};
1462-
int cur_item_modified;
1463-
size_t i, j;
1464-
int error = 0;
1465-
1466-
assert(diff_list && (our_iter || their_iter));
1467-
1468-
/* Set up the iterators */
1469-
for (i = 0; i < 3; i++) {
1470-
error = git_iterator_current(&items[i], iterators[i]);
1471-
1472-
if (error < 0 && error != GIT_ITEROVER)
1473-
goto done;
1474-
}
1475-
1476-
while (true) {
1477-
for (i = 0; i < 3; i++)
1478-
cur_items[i] = NULL;
1479-
1480-
best_cur_item = NULL;
1481-
cur_item_modified = 0;
1482-
1483-
/* Find the next path(s) to consume from each iterator */
1484-
for (i = 0; i < 3; i++) {
1485-
if (items[i] == NULL) {
1486-
cur_item_modified = 1;
1487-
continue;
1488-
}
1489-
1490-
if (best_cur_item == NULL) {
1491-
best_cur_item = items[i];
1492-
cur_items[i] = items[i];
1493-
} else {
1494-
int path_diff = entry_compare(items[i], best_cur_item);
1495-
1496-
if (path_diff < 0) {
1497-
/*
1498-
* Found an item that sorts before our current item, make
1499-
* our current item this one.
1500-
*/
1501-
for (j = 0; j < i; j++)
1502-
cur_items[j] = NULL;
1503-
1504-
cur_item_modified = 1;
1505-
best_cur_item = items[i];
1506-
cur_items[i] = items[i];
1507-
} else if (path_diff > 0) {
1508-
/* No entry for the current item, this is modified */
1509-
cur_item_modified = 1;
1510-
} else if (path_diff == 0) {
1511-
cur_items[i] = items[i];
1512-
1513-
if (!cur_item_modified)
1514-
cur_item_modified = index_entry_cmp(best_cur_item, items[i]);
1515-
}
1516-
}
1517-
}
1518-
1519-
if (best_cur_item == NULL)
1520-
break;
1521-
1522-
if (cur_item_modified)
1523-
error = merge_diff_list_insert_conflict(diff_list, &df_data, cur_items);
1524-
else
1525-
error = merge_diff_list_insert_unmodified(diff_list, cur_items);
1526-
if (error < 0)
1527-
goto done;
1487+
struct merge_diff_find_data find_data = { diff_list };
15281488

1529-
/* Advance each iterator that participated */
1530-
for (i = 0; i < 3; i++) {
1531-
if (cur_items[i] == NULL)
1532-
continue;
1533-
1534-
error = git_iterator_advance(&items[i], iterators[i]);
1535-
1536-
if (error < 0 && error != GIT_ITEROVER)
1537-
goto done;
1538-
}
1539-
}
1540-
1541-
done:
1542-
if (error == GIT_ITEROVER)
1543-
error = 0;
1544-
1545-
return error;
1489+
return git_iterator_walk(iterators, 3, queue_difference, &find_data);
15461490
}
15471491

15481492
git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo)

0 commit comments

Comments
 (0)