impotent/table.h
2025-08-31 16:22:38 +03:00

108 lines
2.2 KiB
C

#pragma once
#include<stdbool.h>
#include<stdint.h>
#include<stddef.h>
#include<ctype.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<stdatomic.h>
#include<assert.h>
#include"value.h"
typedef struct LTableEntry {
LValue key;
LValue val;
} LTableEntry;
typedef struct LTableBuckets {
size_t capacity;
LTableEntry data[];
} LTableBuckets;
typedef struct LTable {
bool ref;
LTableBuckets *buckets;
} LTable;
static inline LTable *ltable_new(size_t capacity) {
assert(capacity >= 8 && (capacity & (capacity - 1)) == 0);
LTable *tbl = calloc(1, sizeof(*tbl));
tbl->ref = false;
tbl->buckets = calloc(1, sizeof(LTableBuckets) + sizeof(LTableEntry) * capacity);
tbl->buckets->capacity = capacity;
for(int i = 0; i < tbl->buckets->capacity; i++) {
tbl->buckets->data[i] = (LTableEntry) {
.key = {.u = LTAG_NIL},
.val = {.u = LTAG_NIL},
};
}
return tbl;
}
static inline bool ltablebuckets_set(LTableBuckets *self, LValue key, LValue val) {
size_t idx = lvalue_hash(key);
int probe_limit = __builtin_ctz(self->capacity);
probe_limit += probe_limit >> 1;
LTableEntry *current = self->data;
while(1) {
idx &= self->capacity - 1;
LValue prevKey = {.u = LTAG_NIL};
atomic_compare_exchange_strong(&current[idx].key.u, &prevKey.u, key.u);
if(prevKey.u == LTAG_NIL || prevKey.u == key.u) {
atomic_store(&current[idx].val.u, val.u);
break;
}
idx++;
probe_limit--;
if(probe_limit == 0) {
return false;
}
}
return true;
}
static inline void ltable_set(LTable *self, LValue key, LValue val) {
if(!ltablebuckets_set(self->buckets, key, val)) {
assert(0 && "No table resizing");
}
}
static inline LValue ltablebuckets_get(LTableBuckets *self, LValue key) {
size_t idx = lvalue_hash(key);
size_t tries = self->capacity;
while(1) {
idx &= self->capacity - 1;
LValue foundKey;
foundKey.u = atomic_load(&self->data[idx].key.u);
if(lvalue_eq(foundKey, key)) {
return (LValue) {.u = atomic_load(&self->data[idx].val.u)};
} else if(--tries == 0) {
return (LValue) {.u = LTAG_NIL};
}
idx++;
}
}
static inline LValue ltable_get(LTable *self, LValue key) {
return ltablebuckets_get(self->buckets, key);
}