While reading a data structure book, I have implemented a chained hash table. I want to share the code with you and get your opinion about it.
chained_hash_table.h
#ifndef CHAINED_HASH_TABLE_H_INCLUDED
#define CHAINED_HASH_TABLE_H_INCLUDED
#include <stdlib.h>
#include "../linked_list/linked_list.h"
typedef size_t hkey_t;
typedef struct ChainedHashTable_ {
size_t buckets;
List **table;
hkey_t (*hash)(const void *key);
void (*destroy)(void *data);
int (*compare)(const void *fdata, const void *sdata);
}ChainedHashTable;
ChainedHashTable *chtb_init(size_t buckets,
hkey_t (*hash)(const void *key),
void (*destroy)(void *data),
int (*compare)(const void *fdata, const void *sdata));
void chtb_destroy(ChainedHashTable *chtb);
int chtb_insert(ChainedHashTable *chtb, void *data);
int chtb_remove(ChainedHashTable *chtb, void **data);
int chtb_lookup(const ChainedHashTable *chtb, const void *data);
#endif
chained_hash_table.c
#include <string.h>
#include "chained_hash_table.h"
#define chtb_hash_key(chtb, data) chtb->hash(data) % chtb->buckets
ChainedHashTable *chtb_init(size_t buckets,
hkey_t (*hash)(const void *key),
void (*destroy)(void *data),
int (*compare)(const void *fdata, const void *sdata)) {
ChainedHashTable *chtb;
if( (chtb = malloc(sizeof *chtb)) != NULL ) {
chtb->buckets = buckets;
chtb->hash = hash;
chtb->destroy = destroy;
chtb->compare = compare;
if( (chtb->table = malloc(buckets * sizeof *chtb->table)) == NULL) {
free(chtb);
return NULL;
}
int i;
for(i = 0; i < buckets; ++i) {
if( (chtb->table[i] = list_init(destroy, compare)) == NULL) {
for(--i; i >= 0; --i)
free(chtb->table[i]);
free(chtb);
return NULL;
}
}
}
return chtb;
}
void chtb_destroy(ChainedHashTable *chtb) {
size_t i;
for(i = 0; i < chtb->buckets; ++i)
if(chtb->table[i] != NULL)
list_destroy(chtb->table[i]);
free(chtb->table);
free(chtb);
}
int chtb_insert(ChainedHashTable *chtb, void *data) {
size_t bucket = chtb_hash_key(chtb, data);
if(list_find(chtb->table[bucket], data) != NULL)
return 1;
if(list_prepend(chtb->table[bucket], data) != 0)
return -1;
return 0;
}
int chtb_remove(ChainedHashTable *chtb, void **data) {
size_t bucket = chtb_hash_key(chtb, data);
if(chtb->table[bucket] == NULL)
return -1;
return list_remove(chtb->table[bucket], data);
}
int chtb_lookup(const ChainedHashTable *chtb, const void *data) {
size_t bucket = chtb_hash_key(chtb, data);
return list_find(chtb->table[bucket], data) == NULL ? 0 : 1;
}