aoc-2019-c

git clone https://git.sinitax.com/sinitax/aoc-2019-c
Log | Files | Refs | README | sfeed.txt

commit 621ce7dc93cd7d4ad8ace0842b910ecb2feb151b
parent c8754bf04f3274926474b81b7e28dba748a53eb4
Author: Louis Burda <quent.burda@gmail.com>
Date:   Fri,  5 Nov 2021 22:34:34 +0100

Add hashmap implementation

Diffstat:
Mlibs/Makefile | 2+-
Alibs/include/hashmap.h | 43+++++++++++++++++++++++++++++++++++++++++++
Alibs/src/hashmap.c | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/day6/main.c | 39+++++++++++++++++----------------------
Dsrc/day7/2 | 35-----------------------------------
5 files changed, 186 insertions(+), 58 deletions(-)

diff --git a/libs/Makefile b/libs/Makefile @@ -15,7 +15,7 @@ build/%.o: src/%.c include/%.h | build build/wrapper.o: src/wrapper.c $(CC) -c -o $@ $< $(CFLAGS) $(LDLIBS) -build/libaoc.a: build/util.o build/aoc.o build/wrapper.o build/memvec.o build/icc.o +build/libaoc.a: build/util.o build/aoc.o build/wrapper.o build/memvec.o build/icc.o build/hashmap.o ar rcs $@ $^ build/test_%: tests/%.c diff --git a/libs/include/hashmap.h b/libs/include/hashmap.h @@ -0,0 +1,43 @@ +#include "util.h" + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> + +#define HASHMAP_KEY(v, len) ((struct hashmap_key) { (void*) (v), (len) }) + +struct hashmap_key { + void *key; + int len; +}; + +struct hashmap_link { + struct hashmap_key key; + void *value; + + struct hashmap_link *next; +}; + +struct hashmap_iter { + struct hashmap_link *link; + int bucket; +}; + +struct hashmap { + struct hashmap_link **buckets; + int size; + + uint32_t (*hash)(void *key, int len); +}; + +void hashmap_init(struct hashmap *hm, int size, uint32_t (*hasher)(void *key, int len)); +void hashmap_free(struct hashmap *hm); + +void hashmap_set(struct hashmap *hm, struct hashmap_key key, void *value); +void * hashmap_get(struct hashmap *hm, struct hashmap_key key); +void * hashmap_pop(struct hashmap *hm, struct hashmap_key key); + +struct hashmap_iter hashmap_iter(void); +int hashmap_next(struct hashmap *hm, struct hashmap_iter *next); + +uint32_t hashmap_string_hasher(void *key, int len); diff --git a/libs/src/hashmap.c b/libs/src/hashmap.c @@ -0,0 +1,125 @@ +#include "hashmap.h" + +void +hashmap_init(struct hashmap *hm, int size, uint32_t (*hasher)(void *key, int len)) +{ + if (!size) size = 20; + hm->size = size; + hm->buckets = CHKP(malloc(hm->size * sizeof(struct hashmap_link *))); + hm->hash = hasher; + memset(hm->buckets, 0, hm->size * sizeof(struct hashmap_link *)); +} + +void +hashmap_free(struct hashmap *hm) +{ + struct hashmap_iter iter; + struct hashmap_link *prev; + + prev = NULL; + iter = hashmap_iter(); + while (hashmap_next(hm, &iter)) { + free(iter.link->key.key); + free(prev); + prev = iter.link; + } + free(prev); + free(hm->buckets); + hm->buckets = NULL; +} + +void +hashmap_set(struct hashmap *hm, struct hashmap_key key, void *value) +{ + struct hashmap_link **iter; + + iter = &hm->buckets[hm->hash(key.key, key.len) % hm->size]; + while (*iter) iter = &((*iter)->next); + + *iter = CHKP(malloc(sizeof(struct hashmap_link))); + (*iter)->key = key; + (*iter)->value = value; + (*iter)->next = NULL; +} + +void * +hashmap_get(struct hashmap *hm, struct hashmap_key key) +{ + struct hashmap_link **iter; + struct hashmap_key ckey; + + iter = &hm->buckets[hm->hash(key.key, key.len) % hm->size]; + while (*iter) { + ckey = (*iter)->key; + if (ckey.len == key.len && !memcmp(ckey.key, key.key, key.len)) + return (*iter)->value; + iter = &((*iter)->next); + } + + return NULL; +} + +void * +hashmap_pop(struct hashmap *hm, struct hashmap_key key) +{ + struct hashmap_link **iter; + struct hashmap_key ckey; + void *value; + + iter = &hm->buckets[hm->hash(key.key, key.len) % hm->size]; + while (*iter) { + ckey = (*iter)->key; + if (ckey.len == key.len && !memcmp(ckey.key, key.key, key.len)) { + *iter = (*iter)->next; + value = (*iter)->value; + free(*iter); + return value; + } + iter = &((*iter)->next); + } + + return NULL; +} + +struct hashmap_iter +hashmap_iter(void) +{ + return (struct hashmap_iter) { NULL, -1 }; +} + +int +hashmap_next(struct hashmap *hm, struct hashmap_iter *iter) +{ + int i; + + if (iter->link && iter->link->next) { + iter->link = iter->link->next; + return 1; + } + + for (i = iter->bucket + 1; i < hm->size; i++) { + if (hm->buckets[i]) { + iter->bucket = i; + iter->link = hm->buckets[i]; + return 1; + } + } + + iter->link = NULL; + return 0; +} + +uint32_t +hashmap_string_hasher(void *key, int len) +{ + uint32_t hash; + uint8_t *data; + int i; + + hash = 0; + data = key; + for (i = 0; i < len; i++) + hash = 31 * hash + data[i]; + + return hash; +} diff --git a/src/day6/main.c b/src/day6/main.c @@ -1,8 +1,10 @@ #include "aoc.h" #include "memvec.h" +#include "hashmap.h" #include <stdlib.h> #include <stdio.h> +#include <stdint.h> #include <string.h> struct planet { @@ -11,23 +13,12 @@ struct planet { struct memvec children; }; -struct memvec planets; - -// TODO: implement hashmap to replace array search +struct hashmap planets; struct planet * get_planet(const char *name) { - struct planet *p; - int i; - - for (i = 0; i < memvec_len(&planets); i++) { - p = MEMVEC_GET(&planets, i, struct planet *); - if (!strcmp(p->name, name)) - return p; - } - - return NULL; + return hashmap_get(&planets, HASHMAP_KEY(name, strlen(name))); } struct planet * @@ -39,7 +30,7 @@ add_planet(const char *name) p->name = CHKP(strdup(name)); p->parent = NULL; ASSERT(memvec_init(&p->children, 3, sizeof(struct planet *)) == OK); - CHKP(memvec_add(&planets, &p)); + hashmap_set(&planets, HASHMAP_KEY(CHKP(strdup(name)), strlen(name)), p); return p; } @@ -50,7 +41,7 @@ init_planets() char *tok, *sep, *next; struct planet *parent, *child; - memvec_init(&planets, 100, sizeof(struct planet *)); + hashmap_init(&planets, 100, hashmap_string_hasher); tok = aoc.input; do { @@ -77,29 +68,33 @@ init_planets() void free_planets() { + struct hashmap_iter iter; struct planet *p; - int i; - for (i = 0; i < memvec_len(&planets); i++) { - p = MEMVEC_GET(&planets, i, struct planet *); + iter = hashmap_iter(); + while (hashmap_next(&planets, &iter)) { + p = iter.link->value; memvec_free(&p->children); free(p->name); free(p); } - memvec_free(&planets); + + hashmap_free(&planets); } void part1(void) { + struct hashmap_iter iter; struct planet *p; - int i, orbits; + int orbits; init_planets(); orbits = 0; - for (i = 0; i < memvec_len(&planets); i++) { - p = MEMVEC_GET(&planets, i, struct planet *); + iter = hashmap_iter(); + while (hashmap_next(&planets, &iter)) { + p = iter.link->value; while (p->parent) { orbits += 1; p = p->parent; diff --git a/src/day7/2 b/src/day7/2 @@ -1,35 +0,0 @@ -#include "aoc.h" -#include "icc.h" - -#include <stdlib.h> -#include <stdio.h> - -void -run_amp(int phase, int input, int *out) -{ - -} - -void -part1(void) -{ - struct icc icc; - void *inst; - - ASSERT(icc_init(&icc) == OK); - ASSERT(icc_parse_inst(&icc, aoc.input, aoc.input_size) == OK); - inst = icc_inst_copy(&icc); - - - icc_reset(&icc, inst); - while (icc.status != ICC_HALT) - icc_step_inst(&icc); - - icc_free(&icc); -} - -void -part2(void) -{ - -}