/* * Copyright (C) 2023 Johnny Richard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "hashmap.h" #include #include #include #include #include #include #include static uint32_t u32_fnv1a_hash(const char *s); static void hashmap_init(hashmap_t *map); static char * __strdup(const char *s); hashmap_t * hashmap_new(void) { hashmap_t *map = (hashmap_t *)malloc(sizeof(hashmap_t)); if (map == NULL) { fprintf(stderr, "[FATAL] Out of memory: hashmap_new: %s\n", strerror(errno)); exit(EXIT_FAILURE); } hashmap_init(map); return map; } static void hashmap_init(hashmap_t *map) { assert(map); map->entries = (hashmap_entry_t *)calloc(HASHMAP_INITIAL_CAPACITY, sizeof(hashmap_entry_t)); if (map->entries == NULL) { fprintf(stderr, "[FATAL] Out of memory: hashmap_init: %s\n", strerror(errno)); exit(EXIT_FAILURE); } map->capacity = HASHMAP_INITIAL_CAPACITY; } static uint32_t u32_fnv1a_hash(const char *s) { uint32_t hash = U32_FNV1A_OFFSET_BASIS; size_t len = strlen(s); for (size_t i = 0; i < len; ++i) { hash ^= s[i]; hash *= U32_FNV1A_PRIME; } return hash; } bool hashmap_put(hashmap_t *map, char *key, void *value) { assert(map && key); uint32_t hash = u32_fnv1a_hash(key); hashmap_entry_t *entry = &(map->entries[hash & (map->capacity - 1)]); while (entry != NULL) { if (entry->hash == hash && strcmp(entry->key, key) == 0) { entry->value = value; return true; } if (entry->next == NULL) break; entry = entry->next; } entry->next = (hashmap_entry_t *)malloc(sizeof(hashmap_entry_t)); *entry->next = (hashmap_entry_t){ .key = __strdup(key), .hash = hash, .value = value, .next = NULL }; return true; } void * hashmap_get(hashmap_t *map, char *key) { uint32_t hash = u32_fnv1a_hash(key); hashmap_entry_t *entry = &map->entries[hash & (map->capacity - 1)]; while (entry != NULL) { if (entry->hash == hash && strcmp(entry->key, key) == 0) { return entry->value; } entry = entry->next; } return NULL; } void hashmap_destroy(hashmap_t *map) { for (size_t i = 0; i < map->capacity; ++i) { hashmap_entry_t *entry = &map->entries[i]; while (entry != NULL) { if (entry->key != NULL) free(entry->key); entry = entry->next; } } free(map->entries); free(map); } static char * __strdup(const char *s) { size_t slen = strlen(s); char *result = malloc(slen + 1); if (result == NULL) { return NULL; } memcpy(result, s, slen + 1); return result; }