refs: do not create ref_entry when searching

The search_ref_dir() function is about looking up an existing ref_entry in a sorted array of ref_entry stored in dir->entries, but it still allocates a new ref_entry and frees it before returning. This is only because the call to bsearch(3) was coded in a suboptimal way. Unlike the comparison function given to qsort(3), the first parameter to its comparison function does not need to point at an object that is shaped like an element in the array. Introduce a new comparison function that takes a counted string as the key and an element in an array of ref_entry and give it to bsearch(), so that we do not have to allocate a new ref_entry that we will never return to the caller anyway. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed May 22, 2012 at 14:03 UTC e1980c9d23c22ecfbcadbe91d304ba778b84b457
1 file changed +23 -9
refs.c
+23 -9
@@ -315,6 +315,23 @@ static int ref_entry_cmp(const void *a, const void *b)
315
316 static void sort_ref_dir(struct ref_dir *dir);
317
318 +struct string_slice {
319 + size_t len;
320 + const char *str;
321 +};
322 +
323 +static int ref_entry_cmp_sslice(const void *key_, const void *ent_)
324 +{
325 + struct string_slice *key = (struct string_slice *)key_;
326 + struct ref_entry *ent = *(struct ref_entry **)ent_;
327 + int entlen = strlen(ent->name);
328 + int cmplen = key->len < entlen ? key->len : entlen;
329 + int cmp = memcmp(key->str, ent->name, cmplen);
330 + if (cmp)
331 + return cmp;
332 + return key->len - entlen;
333 +}
334 +
335 /*
336 * Return the entry with the given refname from the ref_dir
337 * (non-recursively), sorting dir if necessary. Return NULL if no
@@ -323,20 +340,17 @@ static void sort_ref_dir(struct ref_dir *dir);
340 static struct ref_entry *search_ref_dir(struct ref_dir *dir,
341 const char *refname, size_t len)
342 {
326 - struct ref_entry *e, **r;
343 + struct ref_entry **r;
344 + struct string_slice key;
345
346 if (refname == NULL || !dir->nr)
347 return NULL;
348
349 sort_ref_dir(dir);
332 -
333 - e = xmalloc(sizeof(struct ref_entry) + len + 1);
334 - memcpy(e->name, refname, len);
335 - e->name[len] = '\0';
336 -
337 - r = bsearch(&e, dir->entries, dir->nr, sizeof(*dir->entries), ref_entry_cmp);
338 -
339 - free(e);
350 + key.len = len;
351 + key.str = refname;
352 + r = bsearch(&key, dir->entries, dir->nr, sizeof(*dir->entries),
353 + ref_entry_cmp_sslice);
354
355 if (r == NULL)
356 return NULL;