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:
Dmitry Podgorny
2017-06-24 14:14:08 +03:00
parent 5ecb0c5d0c
commit a845c7ec3d
2 changed files with 40 additions and 34 deletions

View File

@@ -87,8 +87,7 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
head_old = head;
_handler_item_remove(&head, item);
if (head != head_old) {
/* TODO implement hash_replace() */
hash_drop(conn->id_handlers, id);
/* replace old value */
hash_add(conn->id_handlers, id, head);
}
xmpp_free(conn->ctx, item->id);
@@ -677,10 +676,11 @@ void handler_system_delete_all(xmpp_conn_t *conn)
freed memory. */
key = hash_iter_next(iter);
if (head != head_old) {
/* TODO implement hash_replace() to reduce number of allocations */
hash_drop(conn->id_handlers, key2);
/* hash_add() replaces value if the key exists */
if (head != NULL)
hash_add(conn->id_handlers, key2, head);
else
hash_drop(conn->id_handlers, key2);
xmpp_free(conn->ctx, key2);
}
}

View File

@@ -119,6 +119,24 @@ static int _hash_key(hash_t *table, const char *key)
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.
* each key can appear only once; the value of any
* 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;
int table_index = _hash_key(table, key);
/* drop existing entry, if any */
hash_drop(table, key);
/* find and replace existing entry, if any */
entry = _hash_entry_find(table, key);
/* allocate and fill a new entry */
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
if (!entry) return -1;
entry->key = xmpp_strdup(ctx, key);
if (!entry->key) {
xmpp_free(ctx, entry);
return -1;
if (entry == NULL) {
/* allocate and fill a new entry */
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
if (!entry) return -1;
entry->key = xmpp_strdup(ctx, key);
if (!entry->key) {
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;
/* 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;
}
@@ -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)
{
hashentry_t *entry;
int table_index = _hash_key(table, key);
void *result = NULL;
/* 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 */
result = entry->value;
return result;
}
entry = entry->next;
}
/* no match */
return result;
entry = _hash_entry_find(table, key);
return entry == NULL ? NULL : entry->value;
}
/** delete a key from a hash table */
@@ -272,4 +279,3 @@ const char * hash_iter_next(hash_iterator_t *iter)
iter->entry = entry;
return entry->key;
}