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

Skip to content

Commit 8a23597

Browse files
committed
diff_generate: refactor DIFF_FROM_ITERATORS macro of doom
While the `DIFF_FROM_ITERATORS` does make it shorter to implement the various `git_diff_foo_to_bar` functions, it is a complex and unreadable beast that implicitly assumes certain local variable names. This is not something desirable to have at all and obstructs understanding and more importantly debugging the code by quite a bit. The `DIFF_FROM_ITERATORS` macro basically removed the burden of having to derive the options for both iterators from a pair of iterator flags and the diff options. This patch introduces a new function that does the that exact and refactors all callers to manage the iterators by themselves. As we potentially need to allocate a shared prefix for the iterator, we need to tell the caller to allocate that prefix as soon as the options aren't required anymore. Thus, the function has a `char **prefix` out pointer that will get set to the allocated string and subsequently be free'd by the caller. While this patch increases the line count, I personally deem this to an acceptable tradeoff for increased readbiblity.
1 parent 0f40e68 commit 8a23597

File tree

1 file changed

+121
-72
lines changed

1 file changed

+121
-72
lines changed

src/diff_generate.c

Lines changed: 121 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,29 +1262,30 @@ int git_diff__from_iterators(
12621262
return error;
12631263
}
12641264

1265-
#define DIFF_FROM_ITERATORS(MAKE_FIRST, FLAGS_FIRST, MAKE_SECOND, FLAGS_SECOND) do { \
1266-
git_iterator *a = NULL, *b = NULL; \
1267-
char *pfx = (opts && !(opts->flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH)) ? \
1268-
git_pathspec_prefix(&opts->pathspec) : NULL; \
1269-
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT, \
1270-
b_opts = GIT_ITERATOR_OPTIONS_INIT; \
1271-
a_opts.flags = FLAGS_FIRST; \
1272-
a_opts.start = pfx; \
1273-
a_opts.end = pfx; \
1274-
b_opts.flags = FLAGS_SECOND; \
1275-
b_opts.start = pfx; \
1276-
b_opts.end = pfx; \
1277-
GIT_ERROR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); \
1278-
if (opts && (opts->flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH)) { \
1279-
a_opts.pathlist.strings = opts->pathspec.strings; \
1280-
a_opts.pathlist.count = opts->pathspec.count; \
1281-
b_opts.pathlist.strings = opts->pathspec.strings; \
1282-
b_opts.pathlist.count = opts->pathspec.count; \
1283-
} \
1284-
if (!error && !(error = MAKE_FIRST) && !(error = MAKE_SECOND)) \
1285-
error = git_diff__from_iterators(&diff, repo, a, b, opts); \
1286-
git__free(pfx); git_iterator_free(a); git_iterator_free(b); \
1287-
} while (0)
1265+
static int diff_prepare_iterator_opts(char **prefix, git_iterator_options *a, int aflags,
1266+
git_iterator_options *b, int bflags,
1267+
const git_diff_options *opts)
1268+
{
1269+
GIT_ERROR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
1270+
1271+
*prefix = NULL;
1272+
1273+
if (opts && (opts->flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH)) {
1274+
a->pathlist.strings = opts->pathspec.strings;
1275+
a->pathlist.count = opts->pathspec.count;
1276+
b->pathlist.strings = opts->pathspec.strings;
1277+
b->pathlist.count = opts->pathspec.count;
1278+
} else if (opts) {
1279+
*prefix = git_pathspec_prefix(&opts->pathspec);
1280+
}
1281+
1282+
a->flags = aflags;
1283+
b->flags = bflags;
1284+
a->start = b->start = *prefix;
1285+
a->end = b->end = *prefix;
1286+
1287+
return 0;
1288+
}
12881289

12891290
int git_diff_tree_to_tree(
12901291
git_diff **out,
@@ -1293,8 +1294,12 @@ int git_diff_tree_to_tree(
12931294
git_tree *new_tree,
12941295
const git_diff_options *opts)
12951296
{
1296-
git_diff *diff = NULL;
12971297
git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE;
1298+
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
1299+
b_opts = GIT_ITERATOR_OPTIONS_INIT;
1300+
git_iterator *a = NULL, *b = NULL;
1301+
git_diff *diff = NULL;
1302+
char *prefix = NULL;
12981303
int error = 0;
12991304

13001305
assert(out && repo);
@@ -1308,13 +1313,19 @@ int git_diff_tree_to_tree(
13081313
if (opts && (opts->flags & GIT_DIFF_IGNORE_CASE) != 0)
13091314
iflag = GIT_ITERATOR_IGNORE_CASE;
13101315

1311-
DIFF_FROM_ITERATORS(
1312-
git_iterator_for_tree(&a, old_tree, &a_opts), iflag,
1313-
git_iterator_for_tree(&b, new_tree, &b_opts), iflag
1314-
);
1316+
if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, iflag, &b_opts, iflag, opts)) < 0 ||
1317+
(error = git_iterator_for_tree(&a, old_tree, &a_opts)) < 0 ||
1318+
(error = git_iterator_for_tree(&b, new_tree, &b_opts)) < 0 ||
1319+
(error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
1320+
goto out;
13151321

1316-
if (!error)
1317-
*out = diff;
1322+
*out = diff;
1323+
diff = NULL;
1324+
out:
1325+
git_iterator_free(a);
1326+
git_iterator_free(b);
1327+
git_diff_free(diff);
1328+
git__free(prefix);
13181329

13191330
return error;
13201331
}
@@ -1337,9 +1348,13 @@ int git_diff_tree_to_index(
13371348
git_index *index,
13381349
const git_diff_options *opts)
13391350
{
1340-
git_diff *diff = NULL;
13411351
git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE |
13421352
GIT_ITERATOR_INCLUDE_CONFLICTS;
1353+
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
1354+
b_opts = GIT_ITERATOR_OPTIONS_INIT;
1355+
git_iterator *a = NULL, *b = NULL;
1356+
git_diff *diff = NULL;
1357+
char *prefix = NULL;
13431358
bool index_ignore_case = false;
13441359
int error = 0;
13451360

@@ -1352,17 +1367,23 @@ int git_diff_tree_to_index(
13521367

13531368
index_ignore_case = index->ignore_case;
13541369

1355-
DIFF_FROM_ITERATORS(
1356-
git_iterator_for_tree(&a, old_tree, &a_opts), iflag,
1357-
git_iterator_for_index(&b, repo, index, &b_opts), iflag
1358-
);
1370+
if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, iflag, &b_opts, iflag, opts)) < 0 ||
1371+
(error = git_iterator_for_tree(&a, old_tree, &a_opts)) < 0 ||
1372+
(error = git_iterator_for_index(&b, repo, index, &b_opts)) < 0 ||
1373+
(error = git_diff__from_iterators(&diff, repo, a, b, opts) < 0))
1374+
goto out;
13591375

13601376
/* if index is in case-insensitive order, re-sort deltas to match */
1361-
if (!error && index_ignore_case)
1377+
if (index_ignore_case)
13621378
git_diff__set_ignore_case(diff, true);
13631379

1364-
if (!error)
1365-
*out = diff;
1380+
*out = diff;
1381+
diff = NULL;
1382+
out:
1383+
git_iterator_free(a);
1384+
git_iterator_free(b);
1385+
git_diff_free(diff);
1386+
git__free(prefix);
13661387

13671388
return error;
13681389
}
@@ -1373,7 +1394,11 @@ int git_diff_index_to_workdir(
13731394
git_index *index,
13741395
const git_diff_options *opts)
13751396
{
1397+
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
1398+
b_opts = GIT_ITERATOR_OPTIONS_INIT;
1399+
git_iterator *a = NULL, *b = NULL;
13761400
git_diff *diff = NULL;
1401+
char *prefix = NULL;
13771402
int error = 0;
13781403

13791404
assert(out && repo);
@@ -1383,20 +1408,24 @@ int git_diff_index_to_workdir(
13831408
if (!index && (error = diff_load_index(&index, repo)) < 0)
13841409
return error;
13851410

1386-
DIFF_FROM_ITERATORS(
1387-
git_iterator_for_index(&a, repo, index, &a_opts),
1388-
GIT_ITERATOR_INCLUDE_CONFLICTS,
1389-
1390-
git_iterator_for_workdir(&b, repo, index, NULL, &b_opts),
1391-
GIT_ITERATOR_DONT_AUTOEXPAND
1392-
);
1393-
1394-
if (!error && (diff->opts.flags & GIT_DIFF_UPDATE_INDEX) != 0 &&
1395-
((git_diff_generated *)diff)->index_updated)
1396-
error = git_index_write(index);
1397-
1398-
if (!error)
1399-
*out = diff;
1411+
if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, GIT_ITERATOR_INCLUDE_CONFLICTS,
1412+
&b_opts, GIT_ITERATOR_DONT_AUTOEXPAND, opts)) < 0 ||
1413+
(error = git_iterator_for_index(&a, repo, index, &a_opts)) < 0 ||
1414+
(error = git_iterator_for_workdir(&b, repo, index, NULL, &b_opts)) < 0 ||
1415+
(error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
1416+
goto out;
1417+
1418+
if ((diff->opts.flags & GIT_DIFF_UPDATE_INDEX) && ((git_diff_generated *)diff)->index_updated)
1419+
if ((error = git_index_write(index)) < 0)
1420+
goto out;
1421+
1422+
*out = diff;
1423+
diff = NULL;
1424+
out:
1425+
git_iterator_free(a);
1426+
git_iterator_free(b);
1427+
git_diff_free(diff);
1428+
git__free(prefix);
14001429

14011430
return error;
14021431
}
@@ -1407,24 +1436,33 @@ int git_diff_tree_to_workdir(
14071436
git_tree *old_tree,
14081437
const git_diff_options *opts)
14091438
{
1439+
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
1440+
b_opts = GIT_ITERATOR_OPTIONS_INIT;
1441+
git_iterator *a = NULL, *b = NULL;
14101442
git_diff *diff = NULL;
1443+
char *prefix = NULL;
14111444
git_index *index;
1412-
int error = 0;
1445+
int error;
14131446

14141447
assert(out && repo);
14151448

14161449
*out = NULL;
14171450

1418-
if ((error = git_repository_index__weakptr(&index, repo)))
1419-
return error;
1420-
1421-
DIFF_FROM_ITERATORS(
1422-
git_iterator_for_tree(&a, old_tree, &a_opts), 0,
1423-
git_iterator_for_workdir(&b, repo, index, old_tree, &b_opts), GIT_ITERATOR_DONT_AUTOEXPAND
1424-
);
1425-
1426-
if (!error)
1427-
*out = diff;
1451+
if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, 0,
1452+
&b_opts, GIT_ITERATOR_DONT_AUTOEXPAND, opts) < 0) ||
1453+
(error = git_repository_index__weakptr(&index, repo)) < 0 ||
1454+
(error = git_iterator_for_tree(&a, old_tree, &a_opts)) < 0 ||
1455+
(error = git_iterator_for_workdir(&b, repo, index, old_tree, &b_opts)) < 0 ||
1456+
(error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
1457+
goto out;
1458+
1459+
*out = diff;
1460+
diff = NULL;
1461+
out:
1462+
git_iterator_free(a);
1463+
git_iterator_free(b);
1464+
git_diff_free(diff);
1465+
git__free(prefix);
14281466

14291467
return error;
14301468
}
@@ -1468,24 +1506,35 @@ int git_diff_index_to_index(
14681506
git_index *new_index,
14691507
const git_diff_options *opts)
14701508
{
1471-
git_diff *diff;
1472-
int error = 0;
1509+
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
1510+
b_opts = GIT_ITERATOR_OPTIONS_INIT;
1511+
git_iterator *a = NULL, *b = NULL;
1512+
git_diff *diff = NULL;
1513+
char *prefix = NULL;
1514+
int error;
14731515

14741516
assert(out && old_index && new_index);
14751517

14761518
*out = NULL;
14771519

1478-
DIFF_FROM_ITERATORS(
1479-
git_iterator_for_index(&a, repo, old_index, &a_opts), GIT_ITERATOR_DONT_IGNORE_CASE,
1480-
git_iterator_for_index(&b, repo, new_index, &b_opts), GIT_ITERATOR_DONT_IGNORE_CASE
1481-
);
1520+
if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, GIT_ITERATOR_DONT_IGNORE_CASE,
1521+
&b_opts, GIT_ITERATOR_DONT_IGNORE_CASE, opts) < 0) ||
1522+
(error = git_iterator_for_index(&a, repo, old_index, &a_opts)) < 0 ||
1523+
(error = git_iterator_for_index(&b, repo, new_index, &b_opts)) < 0 ||
1524+
(error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
1525+
goto out;
14821526

14831527
/* if index is in case-insensitive order, re-sort deltas to match */
1484-
if (!error && (old_index->ignore_case || new_index->ignore_case))
1528+
if (old_index->ignore_case || new_index->ignore_case)
14851529
git_diff__set_ignore_case(diff, true);
14861530

1487-
if (!error)
1488-
*out = diff;
1531+
*out = diff;
1532+
diff = NULL;
1533+
out:
1534+
git_iterator_free(a);
1535+
git_iterator_free(b);
1536+
git_diff_free(diff);
1537+
git__free(prefix);
14891538

14901539
return error;
14911540
}

0 commit comments

Comments
 (0)