hash: avoid allocation when replace value in hash_add()
Memory allocation may fail. We don't need to allocate new entry when we already have one.
This commit is contained in:
@@ -87,8 +87,7 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
|
|||||||
head_old = head;
|
head_old = head;
|
||||||
_handler_item_remove(&head, item);
|
_handler_item_remove(&head, item);
|
||||||
if (head != head_old) {
|
if (head != head_old) {
|
||||||
/* TODO implement hash_replace() */
|
/* replace old value */
|
||||||
hash_drop(conn->id_handlers, id);
|
|
||||||
hash_add(conn->id_handlers, id, head);
|
hash_add(conn->id_handlers, id, head);
|
||||||
}
|
}
|
||||||
xmpp_free(conn->ctx, item->id);
|
xmpp_free(conn->ctx, item->id);
|
||||||
@@ -677,10 +676,11 @@ void handler_system_delete_all(xmpp_conn_t *conn)
|
|||||||
freed memory. */
|
freed memory. */
|
||||||
key = hash_iter_next(iter);
|
key = hash_iter_next(iter);
|
||||||
if (head != head_old) {
|
if (head != head_old) {
|
||||||
/* TODO implement hash_replace() to reduce number of allocations */
|
/* hash_add() replaces value if the key exists */
|
||||||
hash_drop(conn->id_handlers, key2);
|
|
||||||
if (head != NULL)
|
if (head != NULL)
|
||||||
hash_add(conn->id_handlers, key2, head);
|
hash_add(conn->id_handlers, key2, head);
|
||||||
|
else
|
||||||
|
hash_drop(conn->id_handlers, key2);
|
||||||
xmpp_free(conn->ctx, key2);
|
xmpp_free(conn->ctx, key2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
66
src/hash.c
66
src/hash.c
@@ -119,6 +119,24 @@ static int _hash_key(hash_t *table, const char *key)
|
|||||||
return hash % (unsigned)table->length;
|
return hash % (unsigned)table->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hashentry_t *_hash_entry_find(hash_t *table, const char *key)
|
||||||
|
{
|
||||||
|
hashentry_t *entry;
|
||||||
|
int table_index = _hash_key(table, key);
|
||||||
|
|
||||||
|
/* look up the hash entry */
|
||||||
|
entry = table->entries[table_index];
|
||||||
|
while (entry != NULL) {
|
||||||
|
/* traverse the linked list looking for the key */
|
||||||
|
if (!strcmp(key, entry->key)) {
|
||||||
|
/* match */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
/** add a key, value pair to a hash table.
|
/** add a key, value pair to a hash table.
|
||||||
* each key can appear only once; the value of any
|
* each key can appear only once; the value of any
|
||||||
* identical key will be replaced
|
* identical key will be replaced
|
||||||
@@ -129,23 +147,25 @@ int hash_add(hash_t *table, const char * const key, void *data)
|
|||||||
hashentry_t *entry = NULL;
|
hashentry_t *entry = NULL;
|
||||||
int table_index = _hash_key(table, key);
|
int table_index = _hash_key(table, key);
|
||||||
|
|
||||||
/* drop existing entry, if any */
|
/* find and replace existing entry, if any */
|
||||||
hash_drop(table, key);
|
entry = _hash_entry_find(table, key);
|
||||||
|
|
||||||
/* allocate and fill a new entry */
|
if (entry == NULL) {
|
||||||
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
|
/* allocate and fill a new entry */
|
||||||
if (!entry) return -1;
|
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
|
||||||
entry->key = xmpp_strdup(ctx, key);
|
if (!entry) return -1;
|
||||||
if (!entry->key) {
|
entry->key = xmpp_strdup(ctx, key);
|
||||||
xmpp_free(ctx, entry);
|
if (!entry->key) {
|
||||||
return -1;
|
xmpp_free(ctx, entry);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* insert ourselves in the linked list */
|
||||||
|
entry->next = table->entries[table_index];
|
||||||
|
table->entries[table_index] = entry;
|
||||||
|
table->num_keys++;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->value = data;
|
entry->value = data;
|
||||||
/* insert ourselves in the linked list */
|
|
||||||
/* TODO: this leaks duplicate keys */
|
|
||||||
entry->next = table->entries[table_index];
|
|
||||||
table->entries[table_index] = entry;
|
|
||||||
table->num_keys++;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -154,22 +174,9 @@ int hash_add(hash_t *table, const char * const key, void *data)
|
|||||||
void *hash_get(hash_t *table, const char *key)
|
void *hash_get(hash_t *table, const char *key)
|
||||||
{
|
{
|
||||||
hashentry_t *entry;
|
hashentry_t *entry;
|
||||||
int table_index = _hash_key(table, key);
|
|
||||||
void *result = NULL;
|
|
||||||
|
|
||||||
/* look up the hash entry */
|
entry = _hash_entry_find(table, key);
|
||||||
entry = table->entries[table_index];
|
return entry == NULL ? NULL : entry->value;
|
||||||
while (entry != NULL) {
|
|
||||||
/* traverse the linked list looking for the key */
|
|
||||||
if (!strcmp(key, entry->key)) {
|
|
||||||
/* match */
|
|
||||||
result = entry->value;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
|
||||||
/* no match */
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** delete a key from a hash table */
|
/** delete a key from a hash table */
|
||||||
@@ -272,4 +279,3 @@ const char * hash_iter_next(hash_iterator_t *iter)
|
|||||||
iter->entry = entry;
|
iter->entry = entry;
|
||||||
return entry->key;
|
return entry->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user