Files
advent-of-code-2023/map.c

144 lines
3.7 KiB
C

//
// Created by lennart on 12/8/23.
//
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include "map.h"
#include <stdlib.h>
// Load factor. Targets how much space is used under ideal conditions
#define LOAD_FACTOR 0.5
typedef struct MapNode_struct {
struct MapNode_struct *next;
int key;
int value;
} MapNode;
struct Map_struct {
MapNode *nodes;
uint32_t size;
uint32_t capacity;
};
static uint32_t map_index(Map *map, int key);
static void map_set_node(Map *map, MapNode node);
static void map_ensure_capacity(Map *map);
__inline Map* map_create() {
Map *map = malloc(sizeof (Map));
map->size = 0;
map->capacity = 1 << 4;
map->nodes = calloc(sizeof (MapNode), map->capacity);
return map;
}
void map_put(Map *map, int key, int value) {
map_ensure_capacity(map);
MapNode node;
node.key = key;
node.value = value;
node.next = NULL;
map_set_node(map, node);
}
__inline int map_get(Map *map, int key) {
MapNode node = map->nodes[map_index(map, key)];
int value = node.value;
MapNode *next = node.next;
while(__glibc_unlikely(next != NULL && (size_t) next != UINTPTR_MAX)) {
if(next->key == key) {
value = next->value;
break;
}
next = next->next;
}
return value;
}
bool map_has(Map *map, int key) {
MapNode node = map->nodes[map_index(map, key)];
bool value = node.next != NULL && node.key == key;
MapNode *next = node.next;
while(__glibc_unlikely(!value && next != NULL && (size_t) next != UINTPTR_MAX)) {
if(next->key == key) {
value = true;
}
next = next->next;
}
return value;
}
void map_free(Map *map) {
for(int i = 0; i < map->capacity; i++) {
MapNode *next = map->nodes[i].next;
if(next != NULL) {
while((size_t) next != UINTPTR_MAX) {
MapNode *after = next->next;
free(next);
next = after;
}
}
}
free(map->nodes);
free(map);
}
static __inline uint32_t map_index(Map *map, int key) {
return key & (map->capacity - 1);
}
__inline void map_set_node(Map *map, MapNode node) {
MapNode *current = &map->nodes[map_index(map, node.key)];
if(current->next == NULL || current->key == node.key) {
if(current->next == NULL) map->size++;
current->key = node.key;
current->value = node.value;
current->next = (MapNode*) UINTPTR_MAX;
} else {
while((size_t) current->next != UINTPTR_MAX) {
current = current->next;
if(current->key == node.key) break;
}
if(current->key == node.key) {
current->value = node.value;
} else {
MapNode *copy = malloc(sizeof (MapNode));
*copy = node;
copy->next = (MapNode*) UINTPTR_MAX;
current->next = copy;
map->size++;
}
}
}
__inline void map_ensure_capacity(Map *map) {
uint32_t capacity = map->capacity;
if(__glibc_unlikely(map->size >= capacity * LOAD_FACTOR)) {
map->capacity <<= 1;
map->size = 0; // Re-add all nodes
MapNode *nodes = map->nodes;
map->nodes = calloc(sizeof (MapNode), map->capacity);
for(int i = 0; i < capacity; i++) {
MapNode node = nodes[i];
MapNode *next = node.next;
if(next == NULL) {
continue;
}
map_set_node(map, node);
while((size_t) next != UINTPTR_MAX) {
map_set_node(map, *next);
MapNode *after = next->next;
assert(after != NULL);
free(next);
next = after;
}
}
free(nodes);
}
}