diff options
Diffstat (limited to 'line-log.c')
-rw-r--r-- | line-log.c | 55 |
1 files changed, 46 insertions, 9 deletions
diff --git a/line-log.c b/line-log.c index 40e1738dbb..51d93310a4 100644 --- a/line-log.c +++ b/line-log.c @@ -14,7 +14,8 @@ #include "graph.h" #include "userdiff.h" #include "line-log.h" -#include "argv-array.h" +#include "strvec.h" +#include "bloom.h" static void range_set_grow(struct range_set *rs, size_t extra) { @@ -295,7 +296,7 @@ static void line_log_data_insert(struct line_log_data **list, return; } - p = xcalloc(1, sizeof(struct line_log_data)); + CALLOC_ARRAY(p, 1); p->path = path; range_set_append(&p->ranges, begin, end); if (ip) { @@ -480,7 +481,7 @@ static struct commit *check_single_commit(struct rev_info *revs) if (obj->flags & UNINTERESTING) continue; obj = deref_tag(revs->repo, obj, NULL, 0); - if (obj->type != OBJ_COMMIT) + if (!obj || obj->type != OBJ_COMMIT) die("Non commit %s?", revs->pending.objects[i].name); if (commit) die("More than one commit to dig from: %s and %s?", @@ -757,12 +758,12 @@ static void parse_pathspec_from_ranges(struct pathspec *pathspec, struct line_log_data *range) { struct line_log_data *r; - struct argv_array array = ARGV_ARRAY_INIT; + struct strvec array = STRVEC_INIT; const char **paths; for (r = range; r; r = r->next) - argv_array_push(&array, r->path); - paths = argv_array_detach(&array); + strvec_push(&array, r->path); + paths = strvec_detach(&array); parse_pathspec(pathspec, 0, PATHSPEC_PREFER_FULL, "", paths); /* strings are now owned by pathspec */ @@ -1146,6 +1147,37 @@ int line_log_print(struct rev_info *rev, struct commit *commit) return 1; } +static int bloom_filter_check(struct rev_info *rev, + struct commit *commit, + struct line_log_data *range) +{ + struct bloom_filter *filter; + struct bloom_key key; + int result = 0; + + if (!commit->parents) + return 1; + + if (!rev->bloom_filter_settings || + !(filter = get_bloom_filter(rev->repo, commit))) + return 1; + + if (!range) + return 0; + + while (!result && range) { + fill_bloom_key(range->path, strlen(range->path), &key, rev->bloom_filter_settings); + + if (bloom_filter_contains(filter, &key, rev->bloom_filter_settings)) + result = 1; + + clear_bloom_key(&key); + range = range->next; + } + + return result; +} + static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *commit, struct line_log_data *range) { @@ -1159,6 +1191,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c queue_diffs(range, &rev->diffopt, &queue, commit, parent); changed = process_all_files(&parent_range, rev, &queue, range); + if (parent) add_line_range(rev, parent, parent_range); free_line_log_data(parent_range); @@ -1227,13 +1260,17 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm /* NEEDSWORK leaking like a sieve */ } -static int process_ranges_arbitrary_commit(struct rev_info *rev, struct commit *commit) +int line_log_process_ranges_arbitrary_commit(struct rev_info *rev, struct commit *commit) { struct line_log_data *range = lookup_line_range(rev, commit); int changed = 0; if (range) { - if (!commit->parents || !commit->parents->next) + if (commit->parents && !bloom_filter_check(rev, commit, range)) { + struct line_log_data *prange = line_log_data_copy(range); + add_line_range(rev, commit->parents->item, prange); + clear_commit_line_range(rev, commit); + } else if (!commit->parents || !commit->parents->next) changed = process_ranges_ordinary_commit(rev, commit, range); else changed = process_ranges_merge_commit(rev, commit, range); @@ -1270,7 +1307,7 @@ int line_log_filter(struct rev_info *rev) while (list) { struct commit_list *to_free = NULL; commit = list->item; - if (process_ranges_arbitrary_commit(rev, commit)) { + if (line_log_process_ranges_arbitrary_commit(rev, commit)) { *pp = list; pp = &list->next; } else |