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);