Skip to content

Commit

Permalink
refs: do not create ref_entry when searching
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Junio C Hamano committed May 22, 2012
1 parent dd02e72 commit e1980c9
Showing 1 changed file with 23 additions and 9 deletions.
32 changes: 23 additions & 9 deletions refs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down

0 comments on commit e1980c9

Please sign in to comment.