bisect: refactor sha1_array into a generic sha1 list

This is a generally useful abstraction, so let's let others make use of it. The refactoring is more or less a straight copy; however, functions and struct members have had their names changed to match string_list, which is the most similar data structure. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed May 19, 2011 at 17:34 UTC 902bb3645160cae72fe43b5f7f5289968ac01617
4 files changed +78 -55
Makefile
+2
@@ -547,6 +547,7 @@ LIB_H += rerere.h
547 LIB_H += resolve-undo.h
548 LIB_H += revision.h
549 LIB_H += run-command.h
550 +LIB_H += sha1-array.h
551 LIB_H += sha1-lookup.h
552 LIB_H += sideband.h
553 LIB_H += sigchain.h
@@ -649,6 +650,7 @@ LIB_OBJS += revision.o
650 LIB_OBJS += run-command.o
651 LIB_OBJS += server-info.o
652 LIB_OBJS += setup.o
653 +LIB_OBJS += sha1-array.o
654 LIB_OBJS += sha1-lookup.o
655 LIB_OBJS += sha1_file.o
656 LIB_OBJS += sha1_name.o
bisect.c
+15 -55
@@ -9,13 +9,7 @@
9 #include "run-command.h"
10 #include "log-tree.h"
11 #include "bisect.h"
12 -
13 -struct sha1_array {
14 - unsigned char (*sha1)[20];
15 - int sha1_nr;
16 - int sha1_alloc;
17 - int sorted;
18 -};
12 +#include "sha1-array.h"
13
14 static struct sha1_array good_revs;
15 static struct sha1_array skipped_revs;
@@ -425,22 +419,15 @@ static void argv_array_push_sha1(struct argv_array *array,
419 argv_array_push(array, strbuf_detach(&buf, NULL));
420 }
421
428 -static void sha1_array_push(struct sha1_array *array,
429 - const unsigned char *sha1)
430 -{
431 - ALLOC_GROW(array->sha1, array->sha1_nr + 1, array->sha1_alloc);
432 - hashcpy(array->sha1[array->sha1_nr++], sha1);
433 -}
434 -
422 static int register_ref(const char *refname, const unsigned char *sha1,
423 int flags, void *cb_data)
424 {
425 if (!strcmp(refname, "bad")) {
426 current_bad_sha1 = sha1;
427 } else if (!prefixcmp(refname, "good-")) {
441 - sha1_array_push(&good_revs, sha1);
428 + sha1_array_append(&good_revs, sha1);
429 } else if (!prefixcmp(refname, "skip-")) {
443 - sha1_array_push(&skipped_revs, sha1);
430 + sha1_array_append(&skipped_revs, sha1);
431 }
432
433 return 0;
@@ -477,41 +464,14 @@ static void read_bisect_paths(struct argv_array *array)
464 fclose(fp);
465 }
466
480 -static int array_cmp(const void *a, const void *b)
481 -{
482 - return hashcmp(a, b);
483 -}
484 -
485 -static void sort_sha1_array(struct sha1_array *array)
486 -{
487 - qsort(array->sha1, array->sha1_nr, sizeof(*array->sha1), array_cmp);
488 -
489 - array->sorted = 1;
490 -}
491 -
492 -static const unsigned char *sha1_access(size_t index, void *table)
493 -{
494 - unsigned char (*array)[20] = table;
495 - return array[index];
496 -}
497 -
498 -static int lookup_sha1_array(struct sha1_array *array,
499 - const unsigned char *sha1)
500 -{
501 - if (!array->sorted)
502 - sort_sha1_array(array);
503 -
504 - return sha1_pos(sha1, array->sha1, array->sha1_nr, sha1_access);
505 -}
506 -
467 static char *join_sha1_array_hex(struct sha1_array *array, char delim)
468 {
469 struct strbuf joined_hexs = STRBUF_INIT;
470 int i;
471
512 - for (i = 0; i < array->sha1_nr; i++) {
472 + for (i = 0; i < array->nr; i++) {
473 strbuf_addstr(&joined_hexs, sha1_to_hex(array->sha1[i]));
514 - if (i + 1 < array->sha1_nr)
474 + if (i + 1 < array->nr)
475 strbuf_addch(&joined_hexs, delim);
476 }
477
@@ -546,13 +506,13 @@ struct commit_list *filter_skipped(struct commit_list *list,
506 if (count)
507 *count = 0;
508
549 - if (!skipped_revs.sha1_nr)
509 + if (!skipped_revs.nr)
510 return list;
511
512 while (list) {
513 struct commit_list *next = list->next;
514 list->next = NULL;
555 - if (0 <= lookup_sha1_array(&skipped_revs,
515 + if (0 <= sha1_array_lookup(&skipped_revs,
516 list->item->object.sha1)) {
517 if (skipped_first && !*skipped_first)
518 *skipped_first = 1;
@@ -647,7 +607,7 @@ static struct commit_list *managed_skipped(struct commit_list *list,
607
608 *tried = NULL;
609
650 - if (!skipped_revs.sha1_nr)
610 + if (!skipped_revs.nr)
611 return list;
612
613 list = filter_skipped(list, tried, 0, &count, &skipped_first);
@@ -672,7 +632,7 @@ static void bisect_rev_setup(struct rev_info *revs, const char *prefix,
632 /* rev_argv.argv[0] will be ignored by setup_revisions */
633 argv_array_push(&rev_argv, xstrdup("bisect_rev_setup"));
634 argv_array_push_sha1(&rev_argv, current_bad_sha1, bad_format);
675 - for (i = 0; i < good_revs.sha1_nr; i++)
635 + for (i = 0; i < good_revs.nr; i++)
636 argv_array_push_sha1(&rev_argv, good_revs.sha1[i],
637 good_format);
638 argv_array_push(&rev_argv, xstrdup("--"));
@@ -772,12 +732,12 @@ static struct commit *get_commit_reference(const unsigned char *sha1)
732
733 static struct commit **get_bad_and_good_commits(int *rev_nr)
734 {
775 - int len = 1 + good_revs.sha1_nr;
735 + int len = 1 + good_revs.nr;
736 struct commit **rev = xmalloc(len * sizeof(*rev));
737 int i, n = 0;
738
739 rev[n++] = get_commit_reference(current_bad_sha1);
780 - for (i = 0; i < good_revs.sha1_nr; i++)
740 + for (i = 0; i < good_revs.nr; i++)
741 rev[n++] = get_commit_reference(good_revs.sha1[i]);
742 *rev_nr = n;
743
@@ -840,9 +800,9 @@ static void check_merge_bases(void)
800 const unsigned char *mb = result->item->object.sha1;
801 if (!hashcmp(mb, current_bad_sha1)) {
802 handle_bad_merge_base();
843 - } else if (0 <= lookup_sha1_array(&good_revs, mb)) {
803 + } else if (0 <= sha1_array_lookup(&good_revs, mb)) {
804 continue;
845 - } else if (0 <= lookup_sha1_array(&skipped_revs, mb)) {
805 + } else if (0 <= sha1_array_lookup(&skipped_revs, mb)) {
806 handle_skipped_merge_base(mb);
807 } else {
808 printf("Bisecting: a merge base must be tested\n");
@@ -903,7 +863,7 @@ static void check_good_are_ancestors_of_bad(const char *prefix)
863 return;
864
865 /* Bisecting with no good rev is ok. */
906 - if (good_revs.sha1_nr == 0)
866 + if (good_revs.nr == 0)
867 return;
868
869 /* Check if all good revs are ancestor of the bad rev. */
@@ -968,7 +928,7 @@ int bisect_next_all(const char *prefix)
928 bisect_common(&revs);
929
930 revs.commits = find_bisection(revs.commits, &reaches, &all,
971 - !!skipped_revs.sha1_nr);
931 + !!skipped_revs.nr);
932 revs.commits = managed_skipped(revs.commits, &tried);
933
934 if (!revs.commits) {
sha1-array.c new
+43
@@ -0,0 +1,43 @@
1 +#include "cache.h"
2 +#include "sha1-array.h"
3 +#include "sha1-lookup.h"
4 +
5 +void sha1_array_append(struct sha1_array *array, const unsigned char *sha1)
6 +{
7 + ALLOC_GROW(array->sha1, array->nr + 1, array->alloc);
8 + hashcpy(array->sha1[array->nr++], sha1);
9 + array->sorted = 0;
10 +}
11 +
12 +static int void_hashcmp(const void *a, const void *b)
13 +{
14 + return hashcmp(a, b);
15 +}
16 +
17 +void sha1_array_sort(struct sha1_array *array)
18 +{
19 + qsort(array->sha1, array->nr, sizeof(*array->sha1), void_hashcmp);
20 + array->sorted = 1;
21 +}
22 +
23 +static const unsigned char *sha1_access(size_t index, void *table)
24 +{
25 + unsigned char (*array)[20] = table;
26 + return array[index];
27 +}
28 +
29 +int sha1_array_lookup(struct sha1_array *array, const unsigned char *sha1)
30 +{
31 + if (!array->sorted)
32 + sha1_array_sort(array);
33 + return sha1_pos(sha1, array->sha1, array->nr, sha1_access);
34 +}
35 +
36 +void sha1_array_clear(struct sha1_array *array)
37 +{
38 + free(array->sha1);
39 + array->sha1 = NULL;
40 + array->nr = 0;
41 + array->alloc = 0;
42 + array->sorted = 0;
43 +}
sha1-array.h new
+18
@@ -0,0 +1,18 @@
1 +#ifndef SHA1_ARRAY_H
2 +#define SHA1_ARRAY_H
3 +
4 +struct sha1_array {
5 + unsigned char (*sha1)[20];
6 + int nr;
7 + int alloc;
8 + int sorted;
9 +};
10 +
11 +#define SHA1_ARRAY_INIT { NULL, 0, 0, 0 }
12 +
13 +void sha1_array_append(struct sha1_array *array, const unsigned char *sha1);
14 +void sha1_array_sort(struct sha1_array *array);
15 +int sha1_array_lookup(struct sha1_array *array, const unsigned char *sha1);
16 +void sha1_array_clear(struct sha1_array *array);
17 +
18 +#endif /* SHA1_ARRAY_H */