diff options
| author | Douglas B. Rumbaugh <doug@douglasrumbaugh.com> | 2025-11-01 13:31:38 -0400 |
|---|---|---|
| committer | Douglas B. Rumbaugh <doug@douglasrumbaugh.com> | 2025-11-01 13:31:38 -0400 |
| commit | 6338ac827b15787a0d83136eac9d681588f07f9a (patch) | |
| tree | f808100cd52e54c632b31b8a42f3bdb703f3d31a /src/strmap.c | |
| download | libmap-6338ac827b15787a0d83136eac9d681588f07f9a.tar.gz | |
Initial commit
Diffstat (limited to 'src/strmap.c')
| -rwxr-xr-x | src/strmap.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/src/strmap.c b/src/strmap.c new file mode 100755 index 0000000..c3d0261 --- /dev/null +++ b/src/strmap.c @@ -0,0 +1,157 @@ +/* + * strmap.c + * + * A closed-addressing based string -> string hash map + * for CISC 301: Operating Systems + */ + +#include "strmap.h" + +struct node { + char *key; + char *value; + struct node *next; +}; + +struct bucket { + struct node *node; +}; + +struct strmap { + struct bucket *buckets; + size_t bucket_cnt; + size_t node_cnt; + hash_func hash; +}; + +static const size_t BCKT_CNT = 101; + +static void _destroy_node(struct node *nd) { + free(nd->key); + free(nd->value); + free(nd); +} + +strmap *strmap_create(hash_func hash) { + strmap *map = calloc(1, sizeof(*map)); + if (!map) + return NULL; + + map->buckets = calloc(BCKT_CNT, sizeof(struct bucket)); + + if (!map->buckets) { + free(map); + return NULL; + } + + map->bucket_cnt = BCKT_CNT; + map->node_cnt = 0; + map->hash = hash; + + return map; +} + +void strmap_destroy(strmap *map) { + for (size_t i = 0; i < map->bucket_cnt; i++) { + struct node *nd = map->buckets[i].node; + while (nd) { + struct node *nd2 = nd->next; + _destroy_node(nd); + nd = nd2; + } + } + + free(map->buckets); + free(map); +} + +strmap_status strmap_put(strmap *map, const char *key, const char *value) { + if (!key || !value) + return STRMAP_ERR; + struct bucket *bckt = map->buckets + map->hash(key, map->bucket_cnt); + + /* + * check if the key already exists in the bucket, in which case we + * do an update, rather than allocating a new node + */ + for (struct node *nd = bckt->node; nd; nd = nd->next) { + if (!strcmp(nd->key, key)) { + char *old_value = nd->value; + nd->value = strdup(value); + /* if the allocation fails, put the old value back */ + if (!nd->value) { + nd->value = old_value; + return STRMAP_ERR; + } + + free(old_value); + return STRMAP_OK; + } + } + + struct node *nd = malloc(sizeof(struct node)); + if (!nd) { + /* node allocation failed */ + goto error_nodealloc; + } + + nd->key = strdup(key); + nd->value = strdup(value); + + if (nd->key == NULL || nd->value == NULL) { + /* string allocation failed */ + goto error_stringalloc; + } + + nd->next = bckt->node; + bckt->node = nd; + map->node_cnt++; + return STRMAP_OK; + +error_stringalloc: + free(nd->key); + free(nd->value); +error_nodealloc: + free(nd); + return STRMAP_ERR; +} + +strmap_status strmap_get(const strmap *map, const char *key, + const char **value) { + if (!key) + return STRMAP_NOTFOUND; + + size_t idx = map->hash(key, map->bucket_cnt); + + struct node *nd; + for (nd = map->buckets[idx].node; nd; nd = nd->next) { + if (!strcmp(nd->key, key)) { + *value = nd->value; + return STRMAP_OK; + } + } + + return STRMAP_NOTFOUND; +} + +strmap_status strmap_delete(strmap *map, const char *key) { + if (!key) + return STRMAP_NOTFOUND; + struct node **nd_ptr = &(map->buckets[map->hash(key, map->bucket_cnt)].node); + + while (*nd_ptr) { + struct node *nd = *nd_ptr; + if (!strcmp(nd->key, key)) { + *nd_ptr = nd->next; + _destroy_node(nd); + map->node_cnt--; + return STRMAP_OK; + } + + nd_ptr = &nd->next; + } + + return STRMAP_NOTFOUND; +} + +size_t strmap_size(const strmap *map) { return map->node_cnt; } |