#include #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); } }