Skip to content

Commit 0491d39

Browse files
newrengitster
authored andcommitted
diffcore-rename: check if we have enough renames for directories early on
As noted in the past few commits, if we can determine that a directory already has enough renames to determine how directory rename detection will be decided for that directory, then we can mark that directory as no longer needing any more renames detected for files underneath it. For such directories, we change the value in the dirs_removed map from RELEVANT_TO_SELF to RELEVANT_FOR_ANCESTOR. A subsequent patch will use this information while iterating over the remaining potential rename sources to mark ones that were only location_relevant as unneeded if no containing directory is still marked as RELEVANT_TO_SELF. Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e54385b commit 0491d39

File tree

1 file changed

+63
-10
lines changed

1 file changed

+63
-10
lines changed

diffcore-rename.c

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,28 @@ static const char *get_highest_rename_path(struct strintmap *counts)
407407
return highest_destination_dir;
408408
}
409409

410+
static char *UNKNOWN_DIR = "/"; /* placeholder -- short, illegal directory */
411+
412+
static int dir_rename_already_determinable(struct strintmap *counts)
413+
{
414+
struct hashmap_iter iter;
415+
struct strmap_entry *entry;
416+
int first = 0, second = 0, unknown = 0;
417+
strintmap_for_each_entry(counts, &iter, entry) {
418+
const char *destination_dir = entry->key;
419+
intptr_t count = (intptr_t)entry->value;
420+
if (!strcmp(destination_dir, UNKNOWN_DIR)) {
421+
unknown = count;
422+
} else if (count >= first) {
423+
second = first;
424+
first = count;
425+
} else if (count >= second) {
426+
second = count;
427+
}
428+
}
429+
return first > second + unknown;
430+
}
431+
410432
static void increment_count(struct dir_rename_info *info,
411433
char *old_dir,
412434
char *new_dir)
@@ -1096,17 +1118,48 @@ static void handle_early_known_dir_renames(struct dir_rename_info *info,
10961118
struct strintmap *dirs_removed)
10971119
{
10981120
/*
1099-
* Not yet implemented; directory renames are determined via an
1100-
* aggregate of all renames under them and using a "majority wins"
1101-
* rule. The fact that "majority wins", though, means we don't need
1102-
* all the renames under the given directory, we only need enough to
1103-
* ensure we have a majority.
1104-
*
1105-
* For now, we don't have enough information to know if we have a
1106-
* majority after exact renames and basename-guided rename detection,
1107-
* so just return early without doing any extra filtering.
1121+
* Directory renames are determined via an aggregate of all renames
1122+
* under them and using a "majority wins" rule. The fact that
1123+
* "majority wins", though, means we don't need all the renames
1124+
* under the given directory, we only need enough to ensure we have
1125+
* a majority.
11081126
*/
1109-
return;
1127+
1128+
struct hashmap_iter iter;
1129+
struct strmap_entry *entry;
1130+
1131+
if (!dirs_removed || !relevant_sources)
1132+
return; /* nothing to cull */
1133+
if (break_idx)
1134+
return; /* culling incompatbile with break detection */
1135+
1136+
/*
1137+
* FIXME: Supplement dir_rename_count with number of potential
1138+
* renames, marking all potential rename sources as mapping to
1139+
* UNKNOWN_DIR.
1140+
*/
1141+
1142+
/*
1143+
* For any directory which we need a potential rename detected for
1144+
* (i.e. those marked as RELEVANT_FOR_SELF in dirs_removed), check
1145+
* whether we have enough renames to satisfy the "majority rules"
1146+
* requirement such that detecting any more renames of files under
1147+
* it won't change the result. For any such directory, mark that
1148+
* we no longer need to detect a rename for it. However, since we
1149+
* might need to still detect renames for an ancestor of that
1150+
* directory, use RELEVANT_FOR_ANCESTOR.
1151+
*/
1152+
strmap_for_each_entry(info->dir_rename_count, &iter, entry) {
1153+
/* entry->key is source_dir */
1154+
struct strintmap *counts = entry->value;
1155+
1156+
if (strintmap_get(dirs_removed, entry->key) ==
1157+
RELEVANT_FOR_SELF &&
1158+
dir_rename_already_determinable(counts)) {
1159+
strintmap_set(dirs_removed, entry->key,
1160+
RELEVANT_FOR_ANCESTOR);
1161+
}
1162+
}
11101163
}
11111164

11121165
void diffcore_rename_extended(struct diff_options *options,

0 commit comments

Comments
 (0)