bisect: use the new generic "sha1_pos" function to lookup sha1
[git/kirr.git] / bisect.c
blob47120c1cd87c1df97d28c7d687bedbc69338806a
1 #include "cache.h"
2 #include "commit.h"
3 #include "diff.h"
4 #include "revision.h"
5 #include "sha1-lookup.h"
6 #include "bisect.h"
8 static unsigned char (*skipped_sha1)[20];
9 static int skipped_sha1_nr;
11 /* bits #0-15 in revision.h */
13 #define COUNTED (1u<<16)
16 * This is a truly stupid algorithm, but it's only
17 * used for bisection, and we just don't care enough.
19 * We care just barely enough to avoid recursing for
20 * non-merge entries.
22 static int count_distance(struct commit_list *entry)
24 int nr = 0;
26 while (entry) {
27 struct commit *commit = entry->item;
28 struct commit_list *p;
30 if (commit->object.flags & (UNINTERESTING | COUNTED))
31 break;
32 if (!(commit->object.flags & TREESAME))
33 nr++;
34 commit->object.flags |= COUNTED;
35 p = commit->parents;
36 entry = p;
37 if (p) {
38 p = p->next;
39 while (p) {
40 nr += count_distance(p);
41 p = p->next;
46 return nr;
49 static void clear_distance(struct commit_list *list)
51 while (list) {
52 struct commit *commit = list->item;
53 commit->object.flags &= ~COUNTED;
54 list = list->next;
58 #define DEBUG_BISECT 0
60 static inline int weight(struct commit_list *elem)
62 return *((int*)(elem->item->util));
65 static inline void weight_set(struct commit_list *elem, int weight)
67 *((int*)(elem->item->util)) = weight;
70 static int count_interesting_parents(struct commit *commit)
72 struct commit_list *p;
73 int count;
75 for (count = 0, p = commit->parents; p; p = p->next) {
76 if (p->item->object.flags & UNINTERESTING)
77 continue;
78 count++;
80 return count;
83 static inline int halfway(struct commit_list *p, int nr)
86 * Don't short-cut something we are not going to return!
88 if (p->item->object.flags & TREESAME)
89 return 0;
90 if (DEBUG_BISECT)
91 return 0;
93 * 2 and 3 are halfway of 5.
94 * 3 is halfway of 6 but 2 and 4 are not.
96 switch (2 * weight(p) - nr) {
97 case -1: case 0: case 1:
98 return 1;
99 default:
100 return 0;
104 #if !DEBUG_BISECT
105 #define show_list(a,b,c,d) do { ; } while (0)
106 #else
107 static void show_list(const char *debug, int counted, int nr,
108 struct commit_list *list)
110 struct commit_list *p;
112 fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr);
114 for (p = list; p; p = p->next) {
115 struct commit_list *pp;
116 struct commit *commit = p->item;
117 unsigned flags = commit->object.flags;
118 enum object_type type;
119 unsigned long size;
120 char *buf = read_sha1_file(commit->object.sha1, &type, &size);
121 char *ep, *sp;
123 fprintf(stderr, "%c%c%c ",
124 (flags & TREESAME) ? ' ' : 'T',
125 (flags & UNINTERESTING) ? 'U' : ' ',
126 (flags & COUNTED) ? 'C' : ' ');
127 if (commit->util)
128 fprintf(stderr, "%3d", weight(p));
129 else
130 fprintf(stderr, "---");
131 fprintf(stderr, " %.*s", 8, sha1_to_hex(commit->object.sha1));
132 for (pp = commit->parents; pp; pp = pp->next)
133 fprintf(stderr, " %.*s", 8,
134 sha1_to_hex(pp->item->object.sha1));
136 sp = strstr(buf, "\n\n");
137 if (sp) {
138 sp += 2;
139 for (ep = sp; *ep && *ep != '\n'; ep++)
141 fprintf(stderr, " %.*s", (int)(ep - sp), sp);
143 fprintf(stderr, "\n");
146 #endif /* DEBUG_BISECT */
148 static struct commit_list *best_bisection(struct commit_list *list, int nr)
150 struct commit_list *p, *best;
151 int best_distance = -1;
153 best = list;
154 for (p = list; p; p = p->next) {
155 int distance;
156 unsigned flags = p->item->object.flags;
158 if (flags & TREESAME)
159 continue;
160 distance = weight(p);
161 if (nr - distance < distance)
162 distance = nr - distance;
163 if (distance > best_distance) {
164 best = p;
165 best_distance = distance;
169 return best;
172 struct commit_dist {
173 struct commit *commit;
174 int distance;
177 static int compare_commit_dist(const void *a_, const void *b_)
179 struct commit_dist *a, *b;
181 a = (struct commit_dist *)a_;
182 b = (struct commit_dist *)b_;
183 if (a->distance != b->distance)
184 return b->distance - a->distance; /* desc sort */
185 return hashcmp(a->commit->object.sha1, b->commit->object.sha1);
188 static struct commit_list *best_bisection_sorted(struct commit_list *list, int nr)
190 struct commit_list *p;
191 struct commit_dist *array = xcalloc(nr, sizeof(*array));
192 int cnt, i;
194 for (p = list, cnt = 0; p; p = p->next) {
195 int distance;
196 unsigned flags = p->item->object.flags;
198 if (flags & TREESAME)
199 continue;
200 distance = weight(p);
201 if (nr - distance < distance)
202 distance = nr - distance;
203 array[cnt].commit = p->item;
204 array[cnt].distance = distance;
205 cnt++;
207 qsort(array, cnt, sizeof(*array), compare_commit_dist);
208 for (p = list, i = 0; i < cnt; i++) {
209 struct name_decoration *r = xmalloc(sizeof(*r) + 100);
210 struct object *obj = &(array[i].commit->object);
212 sprintf(r->name, "dist=%d", array[i].distance);
213 r->next = add_decoration(&name_decoration, obj, r);
214 p->item = array[i].commit;
215 p = p->next;
217 if (p)
218 p->next = NULL;
219 free(array);
220 return list;
224 * zero or positive weight is the number of interesting commits it can
225 * reach, including itself. Especially, weight = 0 means it does not
226 * reach any tree-changing commits (e.g. just above uninteresting one
227 * but traversal is with pathspec).
229 * weight = -1 means it has one parent and its distance is yet to
230 * be computed.
232 * weight = -2 means it has more than one parent and its distance is
233 * unknown. After running count_distance() first, they will get zero
234 * or positive distance.
236 static struct commit_list *do_find_bisection(struct commit_list *list,
237 int nr, int *weights,
238 int find_all)
240 int n, counted;
241 struct commit_list *p;
243 counted = 0;
245 for (n = 0, p = list; p; p = p->next) {
246 struct commit *commit = p->item;
247 unsigned flags = commit->object.flags;
249 p->item->util = &weights[n++];
250 switch (count_interesting_parents(commit)) {
251 case 0:
252 if (!(flags & TREESAME)) {
253 weight_set(p, 1);
254 counted++;
255 show_list("bisection 2 count one",
256 counted, nr, list);
259 * otherwise, it is known not to reach any
260 * tree-changing commit and gets weight 0.
262 break;
263 case 1:
264 weight_set(p, -1);
265 break;
266 default:
267 weight_set(p, -2);
268 break;
272 show_list("bisection 2 initialize", counted, nr, list);
275 * If you have only one parent in the resulting set
276 * then you can reach one commit more than that parent
277 * can reach. So we do not have to run the expensive
278 * count_distance() for single strand of pearls.
280 * However, if you have more than one parents, you cannot
281 * just add their distance and one for yourself, since
282 * they usually reach the same ancestor and you would
283 * end up counting them twice that way.
285 * So we will first count distance of merges the usual
286 * way, and then fill the blanks using cheaper algorithm.
288 for (p = list; p; p = p->next) {
289 if (p->item->object.flags & UNINTERESTING)
290 continue;
291 if (weight(p) != -2)
292 continue;
293 weight_set(p, count_distance(p));
294 clear_distance(list);
296 /* Does it happen to be at exactly half-way? */
297 if (!find_all && halfway(p, nr))
298 return p;
299 counted++;
302 show_list("bisection 2 count_distance", counted, nr, list);
304 while (counted < nr) {
305 for (p = list; p; p = p->next) {
306 struct commit_list *q;
307 unsigned flags = p->item->object.flags;
309 if (0 <= weight(p))
310 continue;
311 for (q = p->item->parents; q; q = q->next) {
312 if (q->item->object.flags & UNINTERESTING)
313 continue;
314 if (0 <= weight(q))
315 break;
317 if (!q)
318 continue;
321 * weight for p is unknown but q is known.
322 * add one for p itself if p is to be counted,
323 * otherwise inherit it from q directly.
325 if (!(flags & TREESAME)) {
326 weight_set(p, weight(q)+1);
327 counted++;
328 show_list("bisection 2 count one",
329 counted, nr, list);
331 else
332 weight_set(p, weight(q));
334 /* Does it happen to be at exactly half-way? */
335 if (!find_all && halfway(p, nr))
336 return p;
340 show_list("bisection 2 counted all", counted, nr, list);
342 if (!find_all)
343 return best_bisection(list, nr);
344 else
345 return best_bisection_sorted(list, nr);
348 struct commit_list *find_bisection(struct commit_list *list,
349 int *reaches, int *all,
350 int find_all)
352 int nr, on_list;
353 struct commit_list *p, *best, *next, *last;
354 int *weights;
356 show_list("bisection 2 entry", 0, 0, list);
359 * Count the number of total and tree-changing items on the
360 * list, while reversing the list.
362 for (nr = on_list = 0, last = NULL, p = list;
364 p = next) {
365 unsigned flags = p->item->object.flags;
367 next = p->next;
368 if (flags & UNINTERESTING)
369 continue;
370 p->next = last;
371 last = p;
372 if (!(flags & TREESAME))
373 nr++;
374 on_list++;
376 list = last;
377 show_list("bisection 2 sorted", 0, nr, list);
379 *all = nr;
380 weights = xcalloc(on_list, sizeof(*weights));
382 /* Do the real work of finding bisection commit. */
383 best = do_find_bisection(list, nr, weights, find_all);
384 if (best) {
385 if (!find_all)
386 best->next = NULL;
387 *reaches = weight(best);
389 free(weights);
390 return best;
393 static int skipcmp(const void *a, const void *b)
395 return hashcmp(a, b);
398 static void prepare_skipped(void)
400 qsort(skipped_sha1, skipped_sha1_nr, sizeof(*skipped_sha1), skipcmp);
403 static const unsigned char *skipped_sha1_access(size_t index, void *table)
405 unsigned char (*skipped)[20] = table;
406 return skipped[index];
409 static int lookup_skipped(unsigned char *sha1)
411 return sha1_pos(sha1, skipped_sha1, skipped_sha1_nr,
412 skipped_sha1_access);
415 struct commit_list *filter_skipped(struct commit_list *list,
416 struct commit_list **tried,
417 int show_all)
419 struct commit_list *filtered = NULL, **f = &filtered;
421 *tried = NULL;
423 if (!skipped_sha1_nr)
424 return list;
426 prepare_skipped();
428 while (list) {
429 struct commit_list *next = list->next;
430 list->next = NULL;
431 if (0 <= lookup_skipped(list->item->object.sha1)) {
432 /* Move current to tried list */
433 *tried = list;
434 tried = &list->next;
435 } else {
436 if (!show_all)
437 return list;
438 /* Move current to filtered list */
439 *f = list;
440 f = &list->next;
442 list = next;
445 return filtered;