|
8 | 8 | #include "revision.h"
|
9 | 9 | #include "tag.h"
|
10 | 10 | #include "commit-reach.h"
|
| 11 | +#include "ewah/ewok.h" |
11 | 12 |
|
12 | 13 | /* Remember to update object flag allocation in object.h */
|
13 | 14 | #define PARENT1 (1u<<16)
|
@@ -941,3 +942,105 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
|
941 | 942 |
|
942 | 943 | return found_commits;
|
943 | 944 | }
|
| 945 | + |
| 946 | +define_commit_slab(bit_arrays, struct bitmap *); |
| 947 | +static struct bit_arrays bit_arrays; |
| 948 | + |
| 949 | +static void insert_no_dup(struct prio_queue *queue, struct commit *c) |
| 950 | +{ |
| 951 | + if (c->object.flags & PARENT2) |
| 952 | + return; |
| 953 | + prio_queue_put(queue, c); |
| 954 | + c->object.flags |= PARENT2; |
| 955 | +} |
| 956 | + |
| 957 | +static struct bitmap *get_bit_array(struct commit *c, int width) |
| 958 | +{ |
| 959 | + struct bitmap **bitmap = bit_arrays_at(&bit_arrays, c); |
| 960 | + if (!*bitmap) |
| 961 | + *bitmap = bitmap_word_alloc(width); |
| 962 | + return *bitmap; |
| 963 | +} |
| 964 | + |
| 965 | +static void free_bit_array(struct commit *c) |
| 966 | +{ |
| 967 | + struct bitmap **bitmap = bit_arrays_at(&bit_arrays, c); |
| 968 | + if (!*bitmap) |
| 969 | + return; |
| 970 | + bitmap_free(*bitmap); |
| 971 | + *bitmap = NULL; |
| 972 | +} |
| 973 | + |
| 974 | +void ahead_behind(struct repository *r, |
| 975 | + struct commit **commits, size_t commits_nr, |
| 976 | + struct ahead_behind_count *counts, size_t counts_nr) |
| 977 | +{ |
| 978 | + struct prio_queue queue = { .compare = compare_commits_by_gen_then_commit_date }; |
| 979 | + size_t width = DIV_ROUND_UP(commits_nr, BITS_IN_EWORD); |
| 980 | + |
| 981 | + if (!commits_nr || !counts_nr) |
| 982 | + return; |
| 983 | + |
| 984 | + for (size_t i = 0; i < counts_nr; i++) { |
| 985 | + counts[i].ahead = 0; |
| 986 | + counts[i].behind = 0; |
| 987 | + } |
| 988 | + |
| 989 | + ensure_generations_valid(r, commits, commits_nr); |
| 990 | + |
| 991 | + init_bit_arrays(&bit_arrays); |
| 992 | + |
| 993 | + for (size_t i = 0; i < commits_nr; i++) { |
| 994 | + struct commit *c = commits[i]; |
| 995 | + struct bitmap *bitmap = get_bit_array(c, width); |
| 996 | + |
| 997 | + bitmap_set(bitmap, i); |
| 998 | + insert_no_dup(&queue, c); |
| 999 | + } |
| 1000 | + |
| 1001 | + while (queue_has_nonstale(&queue)) { |
| 1002 | + struct commit *c = prio_queue_get(&queue); |
| 1003 | + struct commit_list *p; |
| 1004 | + struct bitmap *bitmap_c = get_bit_array(c, width); |
| 1005 | + |
| 1006 | + for (size_t i = 0; i < counts_nr; i++) { |
| 1007 | + int reach_from_tip = !!bitmap_get(bitmap_c, counts[i].tip_index); |
| 1008 | + int reach_from_base = !!bitmap_get(bitmap_c, counts[i].base_index); |
| 1009 | + |
| 1010 | + if (reach_from_tip ^ reach_from_base) { |
| 1011 | + if (reach_from_base) |
| 1012 | + counts[i].behind++; |
| 1013 | + else |
| 1014 | + counts[i].ahead++; |
| 1015 | + } |
| 1016 | + } |
| 1017 | + |
| 1018 | + for (p = c->parents; p; p = p->next) { |
| 1019 | + struct bitmap *bitmap_p; |
| 1020 | + |
| 1021 | + repo_parse_commit(r, p->item); |
| 1022 | + |
| 1023 | + bitmap_p = get_bit_array(p->item, width); |
| 1024 | + bitmap_or(bitmap_p, bitmap_c); |
| 1025 | + |
| 1026 | + /* |
| 1027 | + * If this parent is reachable from every starting |
| 1028 | + * commit, then none of its ancestors can contribute |
| 1029 | + * to the ahead/behind count. Mark it as STALE, so |
| 1030 | + * we can stop the walk when every commit in the |
| 1031 | + * queue is STALE. |
| 1032 | + */ |
| 1033 | + if (bitmap_popcount(bitmap_p) == commits_nr) |
| 1034 | + p->item->object.flags |= STALE; |
| 1035 | + |
| 1036 | + insert_no_dup(&queue, p->item); |
| 1037 | + } |
| 1038 | + |
| 1039 | + free_bit_array(c); |
| 1040 | + } |
| 1041 | + |
| 1042 | + /* STALE is used here, PARENT2 is used by insert_no_dup(). */ |
| 1043 | + repo_clear_commit_marks(r, PARENT2 | STALE); |
| 1044 | + clear_bit_arrays(&bit_arrays); |
| 1045 | + clear_prio_queue(&queue); |
| 1046 | +} |
0 commit comments