tree-diff: remove special-case diff-emitting code for empty-tree cases

While walking trees, we iterate their entries from lowest to highest in
sort order, so empty tree means all entries were already went over.

If we artificially assign +infinity value to such tree "entry", it will
go after all usual entries, and through the usual driver loop we will be
taking the same actions, which were hand-coded for special cases, i.e.

    t1 empty, t2 non-empty
        pathcmp(+∞, t2) -> +1
        show_path(/*t1=*/NULL, t2);     /* = t1 > t2 case in main loop */

    t1 non-empty, t2-empty
        pathcmp(t1, +∞) -> -1
        show_path(t1, /*t2=*/NULL);     /* = t1 < t2 case in main loop */

In other words when we have t1 and t2, we return a sign that tells the
caller to indicate the "earlier" one to be emitted, and by returning the
sign that causes the non-empty side to be emitted, we will automatically
cause the entries from the remaining side to be emitted, without
attempting to touch the empty side at all.  We can teach
tree_entry_pathcmp() to pretend that an empty tree has an element that
sorts after anything else to achieve this.

Right now we never go to when compared tree descriptors are both
infinity, as this condition is checked in the loop beginning as
finishing criteria, but will do so in the future, when there will be
several parents iterated simultaneously, and some pair of them would run
to the end.

Signed-off-by: Kirill Smelkov <kirr@mns.spb.ru>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Kirill Smelkov 2014-02-24 20:21:44 +04:00 committed by Junio C Hamano
parent 1a27a15452
commit 6ca844e9f5

View File

@ -12,12 +12,24 @@
* *
* NOTE files and directories *always* compare differently, even when having * NOTE files and directories *always* compare differently, even when having
* the same name - thanks to base_name_compare(). * the same name - thanks to base_name_compare().
*
* NOTE empty (=invalid) descriptor(s) take part in comparison as +infty,
* so that they sort *after* valid tree entries.
*
* Due to this convention, if trees are scanned in sorted order, all
* non-empty descriptors will be processed first.
*/ */
static int tree_entry_pathcmp(struct tree_desc *t1, struct tree_desc *t2) static int tree_entry_pathcmp(struct tree_desc *t1, struct tree_desc *t2)
{ {
struct name_entry *e1, *e2; struct name_entry *e1, *e2;
int cmp; int cmp;
/* empty descriptors sort after valid tree entries */
if (!t1->size)
return t2->size ? 1 : 0;
else if (!t2->size)
return -1;
e1 = &t1->entry; e1 = &t1->entry;
e2 = &t2->entry; e2 = &t2->entry;
cmp = base_name_compare(e1->path, tree_entry_len(e1), e1->mode, cmp = base_name_compare(e1->path, tree_entry_len(e1), e1->mode,
@ -150,18 +162,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
skip_uninteresting(t1, &base, opt); skip_uninteresting(t1, &base, opt);
skip_uninteresting(t2, &base, opt); skip_uninteresting(t2, &base, opt);
} }
if (!t1->size) { if (!t1->size && !t2->size)
if (!t2->size) break;
break;
show_path(&base, opt, /*t1=*/NULL, t2);
update_tree_entry(t2);
continue;
}
if (!t2->size) {
show_path(&base, opt, t1, /*t2=*/NULL);
update_tree_entry(t1);
continue;
}
cmp = tree_entry_pathcmp(t1, t2); cmp = tree_entry_pathcmp(t1, t2);