From c9624690a963954f63a9bf0a0cc3b3170c181ded Mon Sep 17 00:00:00 2001 From: Jakub Klama Date: Sun, 31 Jan 2016 01:51:03 +0100 Subject: [PATCH] Add simple hashtable implementation. This is to replace using inefficient lists to store tags and fids. --- hashtable.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++ hashtable.h | 63 +++++++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 hashtable.c create mode 100644 hashtable.h diff --git a/hashtable.c b/hashtable.c new file mode 100644 index 0000000..d9dc8ed --- /dev/null +++ b/hashtable.c @@ -0,0 +1,172 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include "lib9p_impl.h" +#include "hashtable.h" + +void +ht_init(struct ht *h, size_t size) +{ + size_t i; + + memset(h, 0, sizeof(struct ht)); + h->ht_nentries = size; + h->ht_entries = l9p_calloc(size, sizeof(struct ht_entry)); + + for (i = 0; i < size; i++) + TAILQ_INIT(&h->ht_entries[i].hte_items); +} + +void +ht_destroy(struct ht *h) +{ + struct ht_entry *he; + struct ht_item *hi; + size_t i; + + for (i = 0; i < h->ht_nentries; i++) { + he = &h->ht_entries[i]; + hi = TAILQ_FIRST(&he->hte_items); + + while ((hi = TAILQ_NEXT(hi, hti_link)) != NULL) + TAILQ_REMOVE(&he->hte_items, hi, hti_link); + } + + free(h->ht_entries); + free(h); +} + +void * +ht_find(struct ht *h, uint32_t hash) +{ + struct ht_entry *entry; + struct ht_item *item; + + entry = &h->ht_entries[hash % h->ht_nentries]; + + TAILQ_FOREACH(item, &entry->hte_items, hti_link) { + if (item->hti_hash == hash) + return (item->hti_data); + } + + return (NULL); +} + +int +ht_add(struct ht *h, uint32_t hash, void *value) +{ + struct ht_entry *entry; + struct ht_item *item; + + entry = &h->ht_entries[hash % h->ht_nentries]; + + TAILQ_FOREACH(item, &entry->hte_items, hti_link) { + if (item->hti_hash == hash) { + errno = EEXIST; + return (-1); + } + } + + item = l9p_calloc(1, sizeof(struct ht_item)); + item->hti_hash = hash; + item->hti_data = value; + TAILQ_INSERT_TAIL(&entry->hte_items, item, hti_link); + + return (0); +} + +int +ht_remove(struct ht *h, uint32_t hash) +{ + struct ht_entry *entry; + struct ht_item *item, *tmp; + int slot = hash % h->ht_nentries; + + entry = &h->ht_entries[slot]; + + TAILQ_FOREACH_SAFE(item, &entry->hte_items, hti_link, tmp) { + if (item->hti_hash == hash) { + TAILQ_REMOVE(&entry->hte_items, item, hti_link); + free(item->hti_data); + free(item); + return (0); + } + } + + errno = ENOENT; + return (-1); +} + +int +ht_remove_at_iter(struct ht_iter *iter) +{ + assert(iter != NULL); + + if (iter->htit_cursor == NULL) { + errno = EINVAL; + return (-1); + } + + TAILQ_REMOVE(&iter->htit_parent->ht_entries[iter->htit_slot].hte_items, + iter->htit_cursor, hti_link); + return (0); +} + +void +ht_iter(struct ht *h, struct ht_iter *iter) +{ + iter->htit_parent = h; + iter->htit_slot = 0; + iter->htit_cursor = TAILQ_FIRST(&h->ht_entries[0].hte_items); +} + +void * +ht_next(struct ht_iter *iter) +{ + struct ht_item *item; + + item = iter->htit_cursor; + +retry: + if ((iter->htit_cursor = TAILQ_NEXT(iter->htit_cursor, hti_link)) == NULL) + { + if (iter->htit_slot == iter->htit_parent->ht_nentries) + return (NULL); + + iter->htit_slot++; + goto retry; + + } + + return (item); +} diff --git a/hashtable.h b/hashtable.h new file mode 100644 index 0000000..0b28385 --- /dev/null +++ b/hashtable.h @@ -0,0 +1,63 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef LIB9P_HASHTABLE_H +#define LIB9P_HASHTABLE_H + +#include + +struct ht { + struct ht_entry * ht_entries; + size_t ht_nentries; +}; + +struct ht_entry { + TAILQ_HEAD(, ht_item) hte_items; +}; + +struct ht_item { + uint32_t hti_hash; + void * hti_data; + TAILQ_ENTRY(ht_item) hti_link; +}; + +struct ht_iter { + struct ht * htit_parent; + struct ht_item * htit_cursor; + size_t htit_slot; +}; + +void ht_init(struct ht *h, size_t size); +void ht_destroy(struct ht *h); +void *ht_find(struct ht *h, uint32_t hash); +int ht_add(struct ht *h, uint32_t hash, void *value); +int ht_remove(struct ht *h, uint32_t hash); +int ht_remove_at_iter(struct ht_iter *iter); +void ht_iter(struct ht *h, struct ht_iter *iter); +void *ht_next(struct ht_iter *iter); + +#endif /* LIB9P_HASHTABLE_H */