146 lines
3.8 KiB
C
146 lines
3.8 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) {
|
|
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);
|
|
}
|
|
}
|