apfl/src/registry.c
Laria Carolin Chabowski c07caa9aa2 Implement the registry and a agrv getter to test it
The registry is a global dictionary accessible from C that stores arbitrary
apfl values.
2023-03-31 21:31:07 +02:00

133 lines
2.8 KiB
C

#include <assert.h>
#include "apfl.h"
#include "alloc.h"
#include "context.h"
#include "hashmap.h"
struct registry_key {
void *major;
size_t minor;
};
bool
keys_eq(void *opaque, const void *_a, const void *_b)
{
(void)opaque;
const struct registry_key *a = _a;
const struct registry_key *b = _b;
return a->major == b->major && a->minor == b->minor;
}
apfl_hash
calc_hash(void *opaque, const void *_key)
{
(void)opaque;
const struct registry_key *key = _key;
apfl_hash h = apfl_hash_fnv1a(&key->major, sizeof(void *));
h = apfl_hash_fnv1a_add(&key->minor, sizeof(size_t), h);
return h;
}
struct apfl_hashmap *
apfl_registry_new(struct apfl_allocator allocator)
{
struct apfl_hashmap *registry = ALLOC_OBJ(allocator, struct apfl_hashmap);
if (registry == NULL) {
return NULL;
}
if (!apfl_hashmap_init(
registry,
allocator,
(struct apfl_hashmap_callbacks) {
.opaque = NULL,
.keys_eq = keys_eq,
.calc_hash = calc_hash,
},
sizeof(struct registry_key),
sizeof(struct apfl_value)
)) {
FREE_OBJ(allocator, registry);
return NULL;
}
return registry;
}
void
apfl_registry_set(apfl_ctx ctx, void *key_major, size_t key_minor, apfl_stackidx value_stackidx)
{
assert(ctx->registry != NULL);
struct apfl_value value = apfl_stack_must_get(ctx, value_stackidx);
struct registry_key key = {
.major = key_major,
.minor = key_minor,
};
if (!apfl_hashmap_set(ctx->registry, &key, &value)) {
apfl_raise_alloc_error(ctx);
}
apfl_drop(ctx, value_stackidx);
}
void
apfl_registry_delete(apfl_ctx ctx, void *key_major, size_t key_minor)
{
assert(ctx->registry != NULL);
struct registry_key key = {
.major = key_major,
.minor = key_minor,
};
apfl_hashmap_delete(ctx->registry, &key);
}
bool
apfl_registry_try_get(apfl_ctx ctx, void *key_major, size_t key_minor)
{
assert(ctx->registry != NULL);
struct registry_key key = {
.major = key_major,
.minor = key_minor,
};
struct apfl_value value;
if (!apfl_hashmap_get(ctx->registry, &key, &value)) {
return false;
}
apfl_stack_must_push(ctx, apfl_value_set_cow_flag(value));
return true;
}
void
apfl_registry_destroy(struct apfl_hashmap *registry)
{
if (registry == NULL) {
return;
}
struct apfl_allocator allocator = registry->allocator;
apfl_hashmap_deinit(registry);
FREE_OBJ(allocator, registry);
}
void
apfl_registry_visit_gc_objects(struct apfl_hashmap *registry, gc_visitor visitor, void *opaque)
{
if (registry == NULL) {
return;
}
HASHMAP_EACH(registry, cur) {
struct apfl_value *v = apfl_hashmap_cursor_peek_value(cur);
apfl_value_visit_gc_object(*v, visitor, opaque);
}
}