This repository has been archived on 2023-11-05. You can view files and clone it, but cannot push or open issues or pull requests.
wrt/utils/tinymap.c

131 lines
3.5 KiB
C
Raw Normal View History

2023-02-06 21:03:06 +08:00
#include <string.h>
#include <stdio.h>
#include "utils/log.h"
#include "wrt/tinymap.h"
#define FOR(i) for (unsigned i = map->head[hash]; i; i = map->node[i].next)
static inline unsigned map_hash(int key) { return (key % BUK_SIZE + BUK_SIZE) % BUK_SIZE; }
void map_init(Map *map) {
map->count = 0;
memset(map->head, 0, sizeof(map->head));
memset(map->node, 0, sizeof(map->node));
}
void *map_get(Map *map, int key) {
if (key == 0) return NULL;
unsigned hash = map_hash(key);
FOR(i) {
if (map->node[i].key == key) return map->node[i].value;
}
return NULL;
}
bool map_set(Map *map, int key, void *value) {
if (key == 0) return false;
unsigned hash = map_hash(key);
FOR(i) {
if (map->node[i].key == key) {
LOG_DBG("map_set: upd key=%d, val=0x%llx, pos=%d", key, (unsigned long long)value, i);
map->node[i].value = value;
return true;
}
}
if (map->count >= NOD_SIZE) {
LOG_DBG("map_set: nod full, compact");
map_compact(map);
if (map->count == NOD_SIZE) return false;
}
map->node[++map->count] = (MapNode){key, value, map->head[hash]};
map->head[hash] = map->count;
LOG_DBG("map_set: ins key=%d, val=0x%llx, pos=%d", key, (unsigned long long)value, map->count);
return true;
}
void map_delete(Map *map, int key) {
if (key == 0) return;
unsigned hash = map_hash(key);
FOR(i) {
if (map->node[i].key == key) {
LOG_DBG("map_delete: del key=%d, pos=%d", key, i);
map->node[i].key = 0;
return;
}
}
}
void map_compact(Map *map) {
LOG_DBG("map_compact: before count=%d", map->count);
{
// compact map->node
// i = last empty node, j = current scanning node
// node[0] is undefined
unsigned i = 1, j = 2;
for (; j <= NOD_SIZE;) {
if (map->node[i].key) {
i++, j++;
continue;
}
if (map->node[j].key) {
LOG_DBG("map_compact: move node[%d] to node[%d]", j, i);
map->node[i] = map->node[j];
map->node[j].key = 0;
i++, j++;
continue;
}
j++;
}
map->count = i - 1;
LOG_DBG("map_compact: after count=%d", map->count);
}
{
// rebuild map->head
for (unsigned i = 0; i <= NOD_SIZE; i++) map->node[i].next = 0;
memset(map->head, 0, sizeof(map->head));
for (unsigned i = 1; i <= NOD_SIZE; i++) {
if (!map->node[i].key) break;
unsigned hash = map_hash(map->node[i].key);
if (map->head[hash] == 0) {
map->head[hash] = i;
} else {
unsigned j = map->head[hash];
map->head[hash] = i;
map->node[i].next = j;
}
}
}
}
void map_dbg(Map *map) {
for (int hash = 0; hash < BUK_SIZE; hash++) {
printf("[+] BUK[%2d]:\n", hash);
int spaces = 5;
FOR(i) {
for (int j = 0; j < spaces; j++) putchar(' ');
printf("└─ NOD[" __COLOR_GREEN "%2d" __COLOR_RESET "]: key=" __COLOR_YELLOW
"%d" __COLOR_RESET ", val=" __COLOR_CYAN "0x%llx" __COLOR_RESET
", nxt=" __COLOR_RED "%d" __COLOR_RESET "\n",
i, map->node[i].key, (unsigned long long)map->node[i].value, map->node[i].next);
spaces += 4;
}
}
}