131 lines
3.5 KiB
C
131 lines
3.5 KiB
C
|
#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;
|
||
|
}
|
||
|
}
|
||
|
}
|