// MIT License // // Copyright (c) 2025 Lakshay Chauhan // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // Available at #ifndef STEEL_HASHMAP_H_ #define STEEL_HASHMAP_H_ #include #include #ifndef STEEL_HASH_H_ #define STEEL_HASH_H_ unsigned int Steel_Hash_SDBM(void *key); // Reference: http://www.cse.yorku.ca/~oz/hash.html#sdbm unsigned int Steel_Hash_SDBM(void *key) { char *data = (char *)key; unsigned long long hash = 0; for (unsigned int i = 0; i < strlen(data); ++i) hash = data[i] + (hash << 6) + (hash << 16) - hash; return hash; } #endif // STEEL_HASH_H_ #ifndef STEEL_ERROR_H_ #define STEEL_ERROR_H_ #include #define Steel_Error(fmt, ...) \ do { \ fprintf(stderr, "error: %s\n", fmt, ##__VA_ARGS__); \ exit(EXIT_FAILURE); \ } while (0) #define Steel_MallocError Steel_Error("memory allocation failed") #endif // STEEL_ERROR_H_ #define Steel_Hashmap_Size 4096 typedef struct Steel_Hashmap_Entry { void *key; void *value; struct Steel_Hashmap_Entry *next; } Steel_Hashmap_Entry; typedef struct Steel_Hashmap { Steel_Hashmap_Entry *table[Steel_Hashmap_Size]; unsigned int (*HashKey)(void *key); void *(*DupKey)(void *key); void *(*DupValue)(void *value); int (*CmpKey)(void *key1, void *key2); } Steel_Hashmap; Steel_Hashmap *Steel_Hashmap_Init(); void Steel_Hashmap_Insert(Steel_Hashmap *hashmap, void *key, void *value); int Steel_Hashmap_Find(Steel_Hashmap *hashmap, void *key); void *Steel_Hashmap_Lookup(Steel_Hashmap *hashmap, void *key); void Steel_Hashmap_Free(Steel_Hashmap *hashmap); static void *Steel_Dup_String(void *data); static int Steel_Str_Cmp(void *s1, void *s2); static void *Steel_Dup_String(void *data) { return (void *)strdup((char *)data); } static int Steel_Str_Cmp(void *s1, void *s2) { return strcmp((char *)s1, (char *)s2); } // Initializes 'Steel_Hashmap' object. // Must call 'Steel_Hashmap_Free' API to free it afterwards. Steel_Hashmap *Steel_Hashmap_Init() { Steel_Hashmap *hashmap = (Steel_Hashmap *)malloc(sizeof(Steel_Hashmap)); if (!hashmap) { Steel_MallocError; } for (size_t i = 0; i < Steel_Hashmap_Size; ++i) { hashmap->table[i] = NULL; } hashmap->HashKey = &Steel_Hash_SDBM; hashmap->DupKey = &Steel_Dup_String; hashmap->DupValue = &Steel_Dup_String; hashmap->CmpKey = &Steel_Str_Cmp; return hashmap; } // Inserts a copy of key and value into hashmap. // Copy is based of 'DupKey' and 'DupValue' fields inside 'Steel_Hashmap'. void Steel_Hashmap_Insert(Steel_Hashmap *hashmap, void *key, void *value) { unsigned int hash = hashmap->HashKey(key) % Steel_Hashmap_Size; Steel_Hashmap_Entry *entry = (Steel_Hashmap_Entry *)malloc(sizeof(Steel_Hashmap_Entry)); if (!entry) { Steel_MallocError; } entry->key = hashmap->DupKey(key); entry->value = hashmap->DupValue(value); entry->next = hashmap->table[hash]; hashmap->table[hash] = entry; } // Returns '1' if key is present in hashmap otherwise '0'. int Steel_Hashmap_Find(Steel_Hashmap *hashmap, void *key) { unsigned int hash = hashmap->HashKey(key) % Steel_Hashmap_Size; Steel_Hashmap_Entry *itr = hashmap->table[hash]; while (itr) { if (hashmap->CmpKey(itr->key, key) == 0) return 1; itr = itr->next; } return 0; } // // Returns 'hashmap[key]' if key is present in hashmap otherwise 'NULL'. void *Steel_Hashmap_Lookup(Steel_Hashmap *hashmap, void *key) { unsigned int hash = hashmap->HashKey(key) % Steel_Hashmap_Size; Steel_Hashmap_Entry *itr = hashmap->table[hash]; while (itr) { if (hashmap->CmpKey(itr->key, key) == 0) return itr->value; itr = itr->next; } return NULL; } // Frees the 'Steel_Hashmap' object. void Steel_Hashmap_Free(Steel_Hashmap *hashmap) { if (!hashmap) { return; } for (size_t i = 0; i < Steel_Hashmap_Size; ++i) { Steel_Hashmap_Entry *entry = hashmap->table[i]; while (entry != NULL) { Steel_Hashmap_Entry *next = entry->next; free(entry->key); free(entry->value); free(entry); entry = next; } } free(hashmap); } #endif // STEEL_HASHMAP_H_