134 lines
2.8 KiB
C
134 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);
|
||
|
|
}
|
||
|
|
}
|