239 lines
5.6 KiB
C
239 lines
5.6 KiB
C
/**
|
|
* @file datastructures/name_index.c
|
|
* @brief Data structure for resolving 64bit keys by string (name).
|
|
*/
|
|
|
|
#include "../private_api.h"
|
|
|
|
static
|
|
uint64_t flecs_name_index_hash(
|
|
const void *ptr)
|
|
{
|
|
const ecs_hashed_string_t *str = ptr;
|
|
ecs_assert(str->hash != 0, ECS_INTERNAL_ERROR, NULL);
|
|
return str->hash;
|
|
}
|
|
|
|
static
|
|
int flecs_name_index_compare(
|
|
const void *ptr1,
|
|
const void *ptr2)
|
|
{
|
|
const ecs_hashed_string_t *str1 = ptr1;
|
|
const ecs_hashed_string_t *str2 = ptr2;
|
|
ecs_size_t len1 = str1->length;
|
|
ecs_size_t len2 = str2->length;
|
|
if (len1 != len2) {
|
|
return (len1 > len2) - (len1 < len2);
|
|
}
|
|
|
|
return ecs_os_memcmp(str1->value, str2->value, len1);
|
|
}
|
|
|
|
void flecs_name_index_init(
|
|
ecs_hashmap_t *hm,
|
|
ecs_allocator_t *allocator)
|
|
{
|
|
flecs_hashmap_init_(hm,
|
|
ECS_SIZEOF(ecs_hashed_string_t), ECS_SIZEOF(uint64_t),
|
|
flecs_name_index_hash,
|
|
flecs_name_index_compare,
|
|
allocator);
|
|
}
|
|
|
|
void flecs_name_index_init_if(
|
|
ecs_hashmap_t *hm,
|
|
ecs_allocator_t *allocator)
|
|
{
|
|
if (!hm->compare) {
|
|
flecs_name_index_init(hm, allocator);
|
|
}
|
|
}
|
|
|
|
bool flecs_name_index_is_init(
|
|
const ecs_hashmap_t *hm)
|
|
{
|
|
return hm->compare != NULL;
|
|
}
|
|
|
|
ecs_hashmap_t* flecs_name_index_new(
|
|
ecs_world_t *world,
|
|
ecs_allocator_t *allocator)
|
|
{
|
|
ecs_hashmap_t *result = flecs_bcalloc(&world->allocators.hashmap);
|
|
flecs_name_index_init(result, allocator);
|
|
result->hashmap_allocator = &world->allocators.hashmap;
|
|
return result;
|
|
}
|
|
|
|
void flecs_name_index_fini(
|
|
ecs_hashmap_t *map)
|
|
{
|
|
flecs_hashmap_fini(map);
|
|
}
|
|
|
|
void flecs_name_index_free(
|
|
ecs_hashmap_t *map)
|
|
{
|
|
if (map) {
|
|
flecs_name_index_fini(map);
|
|
flecs_bfree(map->hashmap_allocator, map);
|
|
}
|
|
}
|
|
|
|
ecs_hashmap_t* flecs_name_index_copy(
|
|
ecs_hashmap_t *map)
|
|
{
|
|
ecs_hashmap_t *result = flecs_bcalloc(map->hashmap_allocator);
|
|
result->hashmap_allocator = map->hashmap_allocator;
|
|
flecs_hashmap_copy(result, map);
|
|
return result;
|
|
}
|
|
|
|
ecs_hashed_string_t flecs_get_hashed_string(
|
|
const char *name,
|
|
ecs_size_t length,
|
|
uint64_t hash)
|
|
{
|
|
if (!length) {
|
|
length = ecs_os_strlen(name);
|
|
} else {
|
|
ecs_assert(length == ecs_os_strlen(name), ECS_INTERNAL_ERROR, NULL);
|
|
}
|
|
|
|
if (!hash) {
|
|
hash = flecs_hash(name, length);
|
|
} else {
|
|
ecs_assert(hash == flecs_hash(name, length), ECS_INTERNAL_ERROR, NULL);
|
|
}
|
|
|
|
return (ecs_hashed_string_t) {
|
|
.value = ECS_CONST_CAST(char*, name),
|
|
.length = length,
|
|
.hash = hash
|
|
};
|
|
}
|
|
|
|
const uint64_t* flecs_name_index_find_ptr(
|
|
const ecs_hashmap_t *map,
|
|
const char *name,
|
|
ecs_size_t length,
|
|
uint64_t hash)
|
|
{
|
|
ecs_hashed_string_t hs = flecs_get_hashed_string(name, length, hash);
|
|
ecs_hm_bucket_t *b = flecs_hashmap_get_bucket(map, hs.hash);
|
|
if (!b) {
|
|
return NULL;
|
|
}
|
|
|
|
ecs_hashed_string_t *keys = ecs_vec_first(&b->keys);
|
|
int32_t i, count = ecs_vec_count(&b->keys);
|
|
|
|
for (i = 0; i < count; i ++) {
|
|
ecs_hashed_string_t *key = &keys[i];
|
|
ecs_assert(key->hash == hs.hash, ECS_INTERNAL_ERROR, NULL);
|
|
|
|
if (hs.length != key->length) {
|
|
continue;
|
|
}
|
|
|
|
if (!ecs_os_strcmp(name, key->value)) {
|
|
uint64_t *e = ecs_vec_get_t(&b->values, uint64_t, i);
|
|
ecs_assert(e != NULL, ECS_INTERNAL_ERROR, NULL);
|
|
return e;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
uint64_t flecs_name_index_find(
|
|
const ecs_hashmap_t *map,
|
|
const char *name,
|
|
ecs_size_t length,
|
|
uint64_t hash)
|
|
{
|
|
const uint64_t *id = flecs_name_index_find_ptr(map, name, length, hash);
|
|
if (id) {
|
|
return id[0];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void flecs_name_index_remove(
|
|
ecs_hashmap_t *map,
|
|
uint64_t e,
|
|
uint64_t hash)
|
|
{
|
|
ecs_hm_bucket_t *b = flecs_hashmap_get_bucket(map, hash);
|
|
if (!b) {
|
|
return;
|
|
}
|
|
|
|
uint64_t *ids = ecs_vec_first(&b->values);
|
|
int32_t i, count = ecs_vec_count(&b->values);
|
|
for (i = 0; i < count; i ++) {
|
|
if (ids[i] == e) {
|
|
flecs_hm_bucket_remove(map, b, hash, i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void flecs_name_index_update_name(
|
|
ecs_hashmap_t *map,
|
|
uint64_t e,
|
|
uint64_t hash,
|
|
const char *name)
|
|
{
|
|
ecs_hm_bucket_t *b = flecs_hashmap_get_bucket(map, hash);
|
|
if (!b) {
|
|
return;
|
|
}
|
|
|
|
uint64_t *ids = ecs_vec_first(&b->values);
|
|
int32_t i, count = ecs_vec_count(&b->values);
|
|
for (i = 0; i < count; i ++) {
|
|
if (ids[i] == e) {
|
|
ecs_hashed_string_t *key = ecs_vec_get_t(
|
|
&b->keys, ecs_hashed_string_t, i);
|
|
key->value = ECS_CONST_CAST(char*, name);
|
|
ecs_assert(ecs_os_strlen(name) == key->length,
|
|
ECS_INTERNAL_ERROR, NULL);
|
|
ecs_assert(flecs_hash(name, key->length) == key->hash,
|
|
ECS_INTERNAL_ERROR, NULL);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Record must already have been in the index */
|
|
ecs_abort(ECS_INTERNAL_ERROR, NULL);
|
|
}
|
|
|
|
void flecs_name_index_ensure(
|
|
ecs_hashmap_t *map,
|
|
uint64_t id,
|
|
const char *name,
|
|
ecs_size_t length,
|
|
uint64_t hash)
|
|
{
|
|
ecs_check(name != NULL, ECS_INVALID_PARAMETER, NULL);
|
|
|
|
ecs_hashed_string_t key = flecs_get_hashed_string(name, length, hash);
|
|
|
|
uint64_t existing = flecs_name_index_find(
|
|
map, name, key.length, key.hash);
|
|
if (existing) {
|
|
if (existing != id) {
|
|
ecs_abort(ECS_ALREADY_DEFINED,
|
|
"conflicting id registered with name '%s'", name);
|
|
}
|
|
}
|
|
|
|
flecs_hashmap_result_t hmr = flecs_hashmap_ensure(
|
|
map, &key, uint64_t);
|
|
*((uint64_t*)hmr.value) = id;
|
|
error:
|
|
return;
|
|
}
|