From e1980c9d23c22ecfbcadbe91d304ba778b84b457 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 22 May 2012 14:03:29 -0700 Subject: 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 --- refs.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/refs.c b/refs.c index 96e943c368..52709ab7fc 100644 --- a/refs.c +++ b/refs.c @@ -315,6 +315,23 @@ static int ref_entry_cmp(const void *a, const void *b) static void sort_ref_dir(struct ref_dir *dir); +struct string_slice { + size_t len; + const char *str; +}; + +static int ref_entry_cmp_sslice(const void *key_, const void *ent_) +{ + struct string_slice *key = (struct string_slice *)key_; + struct ref_entry *ent = *(struct ref_entry **)ent_; + int entlen = strlen(ent->name); + int cmplen = key->len < entlen ? key->len : entlen; + int cmp = memcmp(key->str, ent->name, cmplen); + if (cmp) + return cmp; + return key->len - entlen; +} + /* * Return the entry with the given refname from the ref_dir * (non-recursively), sorting dir if necessary. Return NULL if no @@ -323,20 +340,17 @@ static void sort_ref_dir(struct ref_dir *dir); static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname, size_t len) { - struct ref_entry *e, **r; + struct ref_entry **r; + struct string_slice key; if (refname == NULL || !dir->nr) return NULL; sort_ref_dir(dir); - - e = xmalloc(sizeof(struct ref_entry) + len + 1); - memcpy(e->name, refname, len); - e->name[len] = '\0'; - - r = bsearch(&e, dir->entries, dir->nr, sizeof(*dir->entries), ref_entry_cmp); - - free(e); + key.len = len; + key.str = refname; + r = bsearch(&key, dir->entries, dir->nr, sizeof(*dir->entries), + ref_entry_cmp_sslice); if (r == NULL) return NULL; -- cgit v1.2.3