Skip to content

Commit e1980c9

Browse files
committed
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 <[email protected]>
1 parent dd02e72 commit e1980c9

File tree

1 file changed

+23
-9
lines changed

1 file changed

+23
-9
lines changed

refs.c

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,23 @@ static int ref_entry_cmp(const void *a, const void *b)
315315

316316
static void sort_ref_dir(struct ref_dir *dir);
317317

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+
318335
/*
319336
* Return the entry with the given refname from the ref_dir
320337
* (non-recursively), sorting dir if necessary. Return NULL if no
@@ -323,20 +340,17 @@ static void sort_ref_dir(struct ref_dir *dir);
323340
static struct ref_entry *search_ref_dir(struct ref_dir *dir,
324341
const char *refname, size_t len)
325342
{
326-
struct ref_entry *e, **r;
343+
struct ref_entry **r;
344+
struct string_slice key;
327345

328346
if (refname == NULL || !dir->nr)
329347
return NULL;
330348

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

341355
if (r == NULL)
342356
return NULL;

0 commit comments

Comments
 (0)