void *hash_find(const struct hash *hash, const char *key) { unsigned int keylen = strlen(key); unsigned int hashval = hash_superfast(key, keylen); unsigned int pos = hashval % hash->n_buckets; const struct hash_bucket *bucket = hash->buckets + pos; const struct hash_entry se = { .key = key, .value = NULL }; const struct hash_entry *entry = bsearch( &se, bucket->entries, bucket->used, sizeof(struct hash_entry), hash_entry_cmp); if (entry == NULL) return NULL; return (void *)entry->value; }
int hash_del(struct hash *hash, const char *key) { unsigned int keylen = strlen(key); unsigned int hashval = hash_superfast(key, keylen); unsigned int pos = hashval % hash->n_buckets; unsigned int steps_used, steps_total; struct hash_bucket *bucket = hash->buckets + pos; struct hash_entry *entry, *entry_end; const struct hash_entry se = { .key = key, .value = NULL }; entry = bsearch(&se, bucket->entries, bucket->used, sizeof(struct hash_entry), hash_entry_cmp); if (entry == NULL) return -ENOENT; if (hash->free_value) hash->free_value((void *)entry->value); entry_end = bucket->entries + bucket->used; memmove(entry, entry + 1, (entry_end - entry) * sizeof(struct hash_entry)); bucket->used--; hash->count--; steps_used = bucket->used / hash->step; steps_total = bucket->total / hash->step; if (steps_used + 1 < steps_total) { size_t size = (steps_used + 1) * hash->step * sizeof(struct hash_entry); struct hash_entry *tmp = realloc(bucket->entries, size); if (tmp) { bucket->entries = tmp; bucket->total = (steps_used + 1) * hash->step; } } return 0; }
/* * add or replace key in hash map. * * none of key or value are copied, just references are remembered as is, * make sure they are live while pair exists in hash! */ int hash_add(struct hash *hash, const char *key, const void *value) { unsigned int keylen = strlen(key); unsigned int hashval = hash_superfast(key, keylen); unsigned int pos = hashval & (hash->n_buckets - 1); struct hash_bucket *bucket = hash->buckets + pos; struct hash_entry *entry, *entry_end; if (bucket->used + 1 >= bucket->total) { unsigned new_total = bucket->total + hash->step; size_t size = new_total * sizeof(struct hash_entry); struct hash_entry *tmp = realloc(bucket->entries, size); if (tmp == NULL) return -errno; bucket->entries = tmp; bucket->total = new_total; } entry = bucket->entries; entry_end = entry + bucket->used; for (; entry < entry_end; entry++) { int c = strcmp(key, entry->key); if (c == 0) { if (hash->free_value) hash->free_value((void *)entry->value); entry->key = key; entry->value = value; return 0; } else if (c < 0) { memmove(entry + 1, entry, (entry_end - entry) * sizeof(struct hash_entry)); break; } } entry->key = key; entry->value = value; bucket->used++; hash->count++; return 0; }