// // Created by lennart on 12/8/23. // #include #include #include #include #include #include "map.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) { current->key = node.key; current->value = node.value; if(current->next == NULL) { map->size++; 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); } }