Files
armorpaint/base/sources/iron_map.c
T
2025-08-13 20:18:49 +02:00

238 lines
5.2 KiB
C

#include "iron_map.h"
#include "iron_gc.h"
#include "iron_string.h"
static size_t hash(const char *k) {
// fnv1a
size_t hash = 0x811c9dc5;
while (*k) {
hash ^= (unsigned char) *k++;
hash *= 0x01000193;
}
return hash;
}
static size_t index_set(any_map_t *m, char *k) {
size_t i = hash(k) & (m->keys->capacity - 1); // % m->keys->capacity
while (true) {
if (m->keys->buffer[i] == NULL) {
m->keys->length++;
break;
}
if (string_equals(k, m->keys->buffer[i])) {
break;
}
++i;
if (i > m->keys->capacity - 1) {
i = 0;
}
}
return i;
}
static size_t index_get(char_ptr_array_t *keys, char *k) {
if (k == NULL || keys->capacity == 0) {
return -1;
}
size_t i = hash(k) & (keys->capacity - 1);
while (!string_equals(k, keys->buffer[i])) {
if (keys->buffer[i] == NULL) {
return -1;
}
++i;
if (i > keys->capacity - 1) {
i = 0;
}
}
return i;
}
static void resize(any_map_t *m, int elem_size) {
if (m->keys->length < m->keys->capacity * 0.5) {
return;
}
int cap = m->keys->capacity == 0 ? 16 : m->keys->capacity * 2;
any_map_t *tmp = any_map_create();
tmp->keys->capacity = cap;
tmp->keys->buffer = gc_realloc(tmp->keys->buffer, cap * sizeof(void *));
tmp->values->capacity = cap;
tmp->values->buffer = gc_realloc(tmp->values->buffer, cap * elem_size);
if (elem_size < 8) {
gc_leaf(tmp->values->buffer);
}
any_array_t *old_keys = map_keys(m);
for (int i = 0; i < old_keys->length; ++i) {
char *k = old_keys->buffer[i];
size_t j = index_set(tmp, k);
tmp->keys->buffer[j] = k;
if (elem_size == 8) {
void **buf = tmp->values->buffer;
buf[j] = any_map_get(m, k);
}
else {
int32_t *buf = tmp->values->buffer;
buf[j] = i32_map_get(m, k);
}
}
m->keys = tmp->keys;
m->values = tmp->values;
}
void i32_map_set(i32_map_t *m, char *k, int v) {
resize(m, 4);
size_t i = index_set(m, k);
m->keys->buffer[i] = k;
m->values->buffer[i] = v;
}
void f32_map_set(f32_map_t *m, char *k, float v) {
resize(m, 4);
size_t i = index_set(m, k);
m->keys->buffer[i] = k;
m->values->buffer[i] = v;
}
void any_map_set(any_map_t *m, char *k, void *v) {
resize(m, 8);
size_t i = index_set(m, k);
m->keys->buffer[i] = k;
m->values->buffer[i] = v;
}
int32_t i32_map_get(i32_map_t *m, char *k) {
size_t i = index_get(m->keys, k);
return i == -1 ? -1 : m->values->buffer[i];
}
float f32_map_get(f32_map_t *m, char *k) {
size_t i = index_get(m->keys, k);
return i == -1 ? -1.0 : m->values->buffer[i];
}
void *any_map_get(any_map_t *m, char *k) {
size_t i = index_get(m->keys, k);
return i == -1 ? NULL : m->values->buffer[i];
}
static int next_pos(any_map_t *m, int i) {
return i == m->keys->capacity - 1 ? 0 : i + 1;
}
void map_delete(any_map_t *m, char *k) {
size_t i = index_get(m->keys, k);
if (i != -1) {
m->keys->buffer[i] = NULL;
m->values->buffer[i] = NULL;
m->keys->length--;
int next = next_pos(m, i);
while (m->keys->buffer[next] != NULL && next != i) {
int j = index_set(m, m->keys->buffer[next]);
if (j != next) {
m->keys->buffer[j] = m->keys->buffer[next];
m->values->buffer[j] = m->values->buffer[next];
m->keys->buffer[next] = NULL;
m->values->buffer[next] = NULL;
}
next = next_pos(m, next);
}
}
}
any_array_t *map_keys(any_map_t *m) {
char_ptr_array_t *keys = gc_alloc(sizeof(char_ptr_array_t));
char_ptr_array_resize(keys, m->keys->length);
for (int i = 0; i < m->keys->capacity; ++i) {
if (m->keys->buffer[i] != NULL) {
char_ptr_array_push(keys, m->keys->buffer[i]);
}
}
return keys;
}
i32_map_t *i32_map_create() {
i32_map_t *r = gc_alloc(sizeof(i32_map_t));
r->keys = gc_alloc(sizeof(char_ptr_array_t));
r->values = gc_alloc(sizeof(i32_array_t));
return r;
}
any_map_t *any_map_create() {
any_map_t *r = gc_alloc(sizeof(any_map_t));
r->keys = gc_alloc(sizeof(char_ptr_array_t));
r->values = gc_alloc(sizeof(any_array_t));
return r;
}
// imap
void i32_imap_set(i32_imap_t *m, int k, int v) {
int i = i32_array_index_of(m->keys, k);
if (i == -1) {
i32_array_push(m->keys, k);
i32_array_push(m->values, v);
}
else {
m->keys->buffer[i] = k;
m->values->buffer[i] = v;
}
}
void any_imap_set(any_imap_t *m, int k, void *v) {
int i = i32_array_index_of(m->keys, k);
if (i == -1) {
i32_array_push(m->keys, k);
any_array_push(m->values, v);
}
else {
m->keys->buffer[i] = k;
m->values->buffer[i] = v;
}
}
int32_t i32_imap_get(i32_imap_t *m, int k) {
int i = i32_array_index_of(m->keys, k);
if (i > -1) {
return m->values->buffer[i];
}
return -1;
}
void *any_imap_get(any_imap_t *m, int k) {
int i = i32_array_index_of(m->keys, k);
if (i > -1) {
return m->values->buffer[i];
}
return NULL;
}
void imap_delete(any_imap_t *m, int k) {
int i = i32_array_index_of(m->keys, k);
if (i > -1) {
i32_array_splice(m->keys, i, 1);
array_splice(m->values, i, 1);
}
}
i32_array_t *imap_keys(any_imap_t *m) {
return m->keys;
}
i32_imap_t *i32_imap_create() {
i32_imap_t *r = gc_alloc(sizeof(i32_imap_t));
r->keys = gc_alloc(sizeof(i32_array_t));
r->values = gc_alloc(sizeof(i32_array_t));
return r;
}
any_imap_t *any_imap_create() {
any_imap_t *r = gc_alloc(sizeof(any_imap_t));
r->keys = gc_alloc(sizeof(i32_array_t));
r->values = gc_alloc(sizeof(any_array_t));
return r;
}