diff options
author | Cara Salter <cara@devcara.com> | 2023-03-23 15:30:21 -0400 |
---|---|---|
committer | Cara Salter <cara@devcara.com> | 2023-03-23 15:30:21 -0400 |
commit | 192dd9d656742b1931ae44f05e1604ff18d64d3b (patch) | |
tree | 39ffaed9ebe7a951352b8ed654debd01e9ce57c6 /src/hash.c | |
parent | 0a838a6932beb1f89a81b16a568098fb45ecb266 (diff) | |
download | cmud-192dd9d656742b1931ae44f05e1604ff18d64d3b.tar.gz cmud-192dd9d656742b1931ae44f05e1604ff18d64d3b.zip |
Work on game.h
Diffstat (limited to 'src/hash.c')
-rw-r--r-- | src/hash.c | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..edb3139 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,243 @@ +/* + * ===================================================================================== + * + * Filename: hash.c + * + * Description: Implementation of a basic hashmap + * + * Version: 1.0 + * Created: 12/09/2022 07:24:38 PM + * Revision: none + * Compiler: gcc + * + * Author: YOUR NAME (), * Organization: + * + * ===================================================================================== + */ +#include <stdlib.h> +#include <math.h> +#include "hash.h" +#include "clog.h" + + +/*----------------------------------------------------------------------------- + * We're defining the structs inside the .c file because really no one should be + * messing around with the internals except through the exported functions + *-----------------------------------------------------------------------------*/ + +typedef struct _map_element { + int key; + int is_used; + any_type value; +} map_element; + +typedef struct _map { + int max_size; + int cur_size; + map_element* data; +} map; + + +/* + * === FUNCTION ====================================================================== + * Name: map_init + * Description: Initializes a new hashmap + * ===================================================================================== + */ +hash_map map_init () { + map* m = (map*) malloc(sizeof(map)); + + m->data = (map_element*) calloc(512, sizeof(map_element)); + + m->max_size = 512; + m->cur_size = 0; + return m; +} /* ----- end of function map_init ----- */ + + +/* + * === FUNCTION ====================================================================== + * Name: hash_int + * Description: + * ===================================================================================== + */ +unsigned int hash_int (map* ma, unsigned int key) { + + /*----------------------------------------------------------------------------- + * This is a pretty basic hashing function, basically we're still using + * modulo but in such a way that collisions are less likely than if we just + * used it raw. + * + * The advantage of this is that it doesn't matter the max size of the + * hashmap, it doesn't have to be sufficiently removed from a power of 2 + * + * See: Hashing by Multiplication here: https://en.wikipedia.org/wiki/Hash_table#Hash_function + *-----------------------------------------------------------------------------*/ + return fmodf(floor(ma->max_size * (key * fmodf(0.3, 1.0))), ma->max_size); +} /* ----- end of function hash_int ----- */ + + +/* + * === FUNCTION ====================================================================== + * Name: hash_get_idx + * Description: + * ===================================================================================== + */ +int hash_get_idx (hash_map* m, int key) { + int c; + map* ma = (map*) m; + + if (ma->cur_size == ma->max_size) { + // Hash map is full, we need to exit now + return -2; + } + + c = hash_int(ma, key); /* This is the theoretically ideal hash index */ + + /*----------------------------------------------------------------------------- + * Pretty basic collision resolution. Needs to be able to resolve them + *-----------------------------------------------------------------------------*/ + + for(int i = 0; i < ma->max_size; i++) { + if (ma->data[c].is_used == 0) { + /*----------------------------------------------------------------------------- + * This index isn't being used, we can return it + *-----------------------------------------------------------------------------*/ + return c; + } + + if (ma->data[c].key == key && ma->data[c].is_used == 1) { + + /*----------------------------------------------------------------------------- + * This index is being used, but by this key, so we can return it + *-----------------------------------------------------------------------------*/ + return c; + } + + + /*----------------------------------------------------------------------------- + * This index is being used but not by this key. Increment the index + * modulo the map size and try again + *-----------------------------------------------------------------------------*/ + c = (c + 1) % ma->max_size; + } + return -2; +} /* ----- end of function hash_get_idx ----- */ + + +/* + * === FUNCTION ====================================================================== + * Name: map_resize + * Description: + * ===================================================================================== + */ +int map_resize(hash_map in) { + int i; + int old_size; + map_element* cur; + + /* New elements! */ + map *m = (map*) in; + map_element* tmp = (map_element*) calloc(2 * m->max_size, sizeof(map_element)); + if (!tmp) return 4; /* We're out of memory! */ + + cur = m->data; + m->data = tmp; + + old_size = m->max_size; + m->max_size = 2 * old_size; + m->cur_size = 0; + + /* Rehash */ + for (i = 0; i < old_size; i++) { + int status = map_add(m, cur[i].key, cur[i].value); + if (status != 0) { + return status; + } + } + + free(cur); + return 0; +} /* ----- end of function map_resize ----- */ + +/* + * === FUNCTION ====================================================================== + * Name: map_add + * Description: + * ===================================================================================== + */ +int map_add(hash_map m, int key, any_type val) { + map* ma = (map*) m; + + int h = hash_get_idx(m, key); + + while (h == -2) { + if (map_resize(m) == 4) { + return 4; + } + h = hash_get_idx(m, key); + } + + ma->data[h].value = val; + ma->data[h].key = key; + ma->data[h].is_used = 1; + return 0; +} /* ----- end of function map_add ----- */ + + +/* + * === FUNCTION ====================================================================== + * Name: map_get + * Description: + * ===================================================================================== + */ +int map_get (hash_map m, int key, any_type* val) { + map* ma = (map*) m; + + int h = hash_get_idx(m, key); + + if (ma->data[h].is_used == 1 && ma->data[h].key == key) { + *val = ma->data[h].value; + return 0; + } + return -3; +} /* ----- end of function map_get ----- */ + + +/* + * === FUNCTION ====================================================================== + * Name: map_del + * Description: + * ===================================================================================== + */ +int map_del (hash_map m, int key) { + map* ma = (map*) m; + + int h = hash_get_idx(m, key); + + if (ma->data[h].is_used == 1 && ma->data[h].key == key) { + ma->data[h].is_used = 0; + ma->data[h].key = 0; + } + + return 0; +} /* ----- end of function map_del ----- */ + +/* + *map_free cleans up the memory used by a hashmap + */ +void map_free(hash_map m) { + map* ma = (map*) m; + + free(ma->data); + free(ma); +} + +/* + *map_len returns the current length of the hashmap + */ +int map_len(hash_map m) { + map* ma = (map*) m; + + return ma->cur_size; +} |