From fbb340d465bc3cc3729deb7c98e0bed2e2f4c90c Mon Sep 17 00:00:00 2001 From: Ivar Fatland Date: Tue, 24 Feb 2026 22:42:48 +0100 Subject: [PATCH] WIP hashmap --- .clangd | 2 ++ cig.h | 54 +++++++++++++++++++++++++++++++++++++----------------- hashmap.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 .clangd create mode 100644 hashmap.c diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..024b5a7 --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + Add: [-xc, -std=c99] diff --git a/cig.h b/cig.h index 8972e64..40fb13f 100644 --- a/cig.h +++ b/cig.h @@ -162,6 +162,15 @@ void *dyn_array_create_func(dyn_array_create_func_args_t args); .allocator = __VA_ARGS__, \ })) +#define init_arr(PTR, ...) do { \ + PTR = dyn_array_create_func((dyn_array_create_func_args_t){ \ + .itemsize = sizeof(*PTR), \ + .file = __FILE__, \ + .line = __LINE__, \ + .allocator = __VA_ARGS__, \ + }); \ +} while(0); + // Always reassign the array. if multiple variables reference the same growing // array, then you should be using pointer pointers. void *dyn_array_grow_func(void *this, size_t n_new_items, const char *file, int line); @@ -228,39 +237,50 @@ void arr_qsort(void *this, dyn_array_cmp_fn cmp_fn); typedef int (*hash_func_t)(void *key); typedef int (*equals_func_t)(void *key1, void *key2); +// TODO: after this comes the actual hash map. it maps keys to indexes into the +// key-value pair array. (which does not actually need values, only a key +// field.) +// TODO: This means that when allocating memory for the array of key-value +// pairs, we actually need to allocate it in terms of the max_align type, and +// increase in size by using that size as the smallest increment. Which will +// keep the hash array aligned properly in memory. + typedef struct hashmap_header { - size_t n_items, capacity, itemsize, keysize; + int n_items, capacity, itemsize, keysize; allocator_t allocator; - hash_func_t hash_func; - equals_func_t equals_func; + hash_func_t hash; + equals_func_t equals; union { uint8_t bytes[1]; any_align_t _[1]; }; - // TODO: after this comes the actual hash map. it maps keys to indexes into - // the key-value pair array. (which does not actually need values, only a - // key field.) + // The above union is actually a different size. Then comes an array of + // integers which is double the size of n_items * sizeof(int). int + // indexes[...]; } hashmap_header_t; typedef struct hashmap_create_func_args { allocator_t allocator; - size_t itemsize; - size_t initial_capacity; const char *file; - hash_func_t hash_func; - equals_func_t equals_func; + hash_func_t hash; // OPTIONAL + equals_func_t equals; // OPTIONAL + int initial_capacity; // OPTIONAL + int itemsize; int keysize; int line; } hashmap_create_func_args_t; + void *hashmap_create_func(hashmap_create_func_args_t args); -// TODO: use sizeof on a declared variable in this and arrays. e.g. -// char *charlist; -// init_arr(charlist, allocator, .initial_capacity=10); -// so I can do: -// struct {int key; int val;} *my_map; -// init_map(my_map, allocator, .initial_capacity=10); -#define make_map() +#define init_map(PTR, ...) do { \ + PTR = hashmap_create_func((hashmap_create_func_args_t) { \ + .itemsize=sizeof(*PTR), \ + .keysize=sizeof(PTR->key), \ + .file=__FILE__, \ + .line=__LINE__, \ + .allocator=__VA_ARGS__ \ + }); \ +} while(0); // TODO this shite diff --git a/hashmap.c b/hashmap.c new file mode 100644 index 0000000..57dcc42 --- /dev/null +++ b/hashmap.c @@ -0,0 +1,28 @@ +#include "cig.h" + +void *hashmap_create_func( + hashmap_create_func_args_t args +) { + size_t size_of_index_arr = sizeof(int) * args.initial_capacity * 2; + size_t INC = sizeof(any_align_t); + size_t SIZE = args.itemsize * args.initial_capacity; + size_t size_of_items_arr = (SIZE + INC - 1) / INC; + size_t bytes = sizeof(hashmap_header_t) + size_of_items_arr + size_of_index_arr; + + hashmap_header_t *header = allocator_alloc_func( + args.allocator, + bytes, + args.file, + args.line + ); + + header->n_items = 0; + header->capacity = args.initial_capacity; + header->itemsize = args.itemsize; + header->keysize = args.keysize; + header->allocator = args.allocator; + header->hash = args.hash; + header->equals = args.equals; + + return header->bytes; +}