fetch-pack: avoid quadratic loop in filter_refs

We have a list of refs that we want to compare against the "match" array. The current code searches the match list linearly, giving quadratic behavior over the number of refs when you want to fetch all of them. Instead, we can compare the lists as we go, giving us linear behavior. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed May 21, 2012 at 18:23 UTC a0de28805dceaca86a6f7bedfd3e8c227b781d9d
1 file changed +13 -6
builtin/fetch-pack.c
+13 -6
@@ -528,6 +528,7 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
528 struct ref **newtail = &newlist;
529 struct ref *ref, *next;
530 struct ref *fastarray[32];
531 + int match_pos;
532
533 if (nr_match && !args.fetch_all) {
534 if (ARRAY_SIZE(fastarray) < nr_match)
@@ -540,6 +541,7 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
541 else
542 return_refs = NULL;
543
544 + match_pos = 0;
545 for (ref = *refs; ref; ref = next) {
546 next = ref->next;
547 if (!memcmp(ref->name, "refs/", 5) &&
@@ -553,15 +555,20 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
555 continue;
556 }
557 else {
556 - int i;
557 - for (i = 0; i < nr_match; i++) {
558 - if (!strcmp(ref->name, match[i])) {
559 - match[i][0] = '\0';
560 - return_refs[i] = ref;
558 + int cmp = -1;
559 + while (match_pos < nr_match) {
560 + cmp = strcmp(ref->name, match[match_pos]);
561 + if (cmp < 0) /* definitely do not have it */
562 + break;
563 + else if (cmp == 0) { /* definitely have it */
564 + match[match_pos][0] = '\0';
565 + return_refs[match_pos] = ref;
566 break;
567 }
568 + else /* might have it; keep looking */
569 + match_pos++;
570 }
564 - if (i < nr_match)
571 + if (!cmp)
572 continue; /* we will link it later */
573 }
574 free(ref);