/* Copyright (c) 2008, Sandia National Laboratories */ #include #include #include #include struct htable { size_t tbl_order; struct hlist_head * tbl; size_t obj_key_offset; size_t obj_link_offset; size_t num_entries; }; static id_t obj2key(const struct htable *ht, const void *obj) { return *((id_t *)((uintptr_t)obj + ht->obj_key_offset)); } static struct hlist_node * obj2node(const struct htable *ht, const void *obj) { return (struct hlist_node *)((uintptr_t)obj + ht->obj_link_offset); } static void * node2obj(const struct htable *ht, const struct hlist_node *node) { return (void *)((uintptr_t)node - ht->obj_link_offset); } static id_t node2key(const struct htable *ht, const struct hlist_node *node) { return obj2key(ht, node2obj(ht, node)); } static struct hlist_head * key2head(const struct htable *ht, id_t key) { return &ht->tbl[hash_long(key, ht->tbl_order)]; } static struct hlist_head * obj2head(const struct htable *ht, const void *obj) { return &ht->tbl[hash_long(obj2key(ht, obj), ht->tbl_order)]; } int htable_create(size_t tbl_order, size_t obj_key_offset, size_t obj_link_offset, htable_t *tbl) { struct htable *ht; size_t tbl_size; if (!(ht = kmem_alloc(sizeof(*ht)))) return -ENOMEM; ht->tbl_order = tbl_order; tbl_size = (1 << tbl_order); if (!(ht->tbl = kmem_alloc(tbl_size * sizeof(struct hlist_head)))) return -ENOMEM; ht->obj_key_offset = obj_key_offset; ht->obj_link_offset = obj_link_offset; ht->num_entries = 0; *tbl = ht; return 0; } int htable_destroy(htable_t tbl) { struct htable *ht = tbl; if (ht->num_entries) return -EEXIST; kmem_free(ht->tbl); kmem_free(ht); return 0; } int htable_add(htable_t tbl, void *obj) { struct htable *ht = tbl; hlist_add_head(obj2node(ht, obj), obj2head(ht, obj)); ++ht->num_entries; return 0; } int htable_del(htable_t tbl, void *obj) { struct htable *ht = tbl; struct hlist_node *node; hlist_for_each(node, obj2head(ht, obj)) { if (obj == node2obj(ht, node)) { hlist_del(node); --ht->num_entries; return 0; } } return -ENOENT; } void * htable_lookup(htable_t tbl, id_t key) { struct htable *ht = tbl; struct hlist_node *node; hlist_for_each(node, key2head(ht, key)) { if (key == node2key(ht, node)) return node2obj(ht, node); } return NULL; }