diff options
| author | KonAki <konaki@anokonaki.org> | 2026-10-09 18:21:49 +0800 |
|---|---|---|
| committer | KonAki <konaki@anokonaki.org> | 2026-10-09 18:21:49 +0800 |
| commit | f6003ea8bce29b930ca03687c1e9088858680415 (patch) | |
| tree | f5bfde525591fadd91eb12e69d5012d36858a4e2 /kon/konassets.c | |
| parent | 0d73e4712f8472bf8e004faadc79dab453684866 (diff) | |
Add hashed asset lookup, kon_assetFind and kon_assetUnload
Diffstat (limited to 'kon/konassets.c')
| -rw-r--r-- | kon/konassets.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/kon/konassets.c b/kon/konassets.c index 75b2fae..b55a25a 100644 --- a/kon/konassets.c +++ b/kon/konassets.c @@ -58,6 +58,8 @@ struct kon_assets { int nextCustom; kon_assetEntry_t *entries; int count, capacity; + int *table; /* hash of name to entry number plus one, 0 is empty. the size is a power of two */ + int tableSize; const char *error; }; @@ -237,7 +239,58 @@ static int kon_typeForName_(const kon_assets_t *assets, const char *name) { return KON_ASSET_BLOB; } +static uint32_t kon_hashName_(const char *name) { + uint32_t hash = 2166136261u; + + while (*name) { + hash ^= (uint8_t)*name++; + hash *= 16777619u; + } + return hash; +} + +static void kon_tableInsert_(kon_assets_t *assets, int index) { + uint32_t mask = (uint32_t)assets->tableSize - 1; + uint32_t slot = kon_hashName_(assets->entries[index].name) & mask; + + while (assets->table[slot]) slot = (slot + 1) & mask; + assets->table[slot] = index + 1; +} + +/* the table is built again whenever entries move or it gets too full. if it can't be built, lookups just search the list */ +static void kon_tableRebuild_(kon_assets_t *assets) { + int size = 64; + int *table; + + while (size < assets->count * 2 + 2) size *= 2; + if (size != assets->tableSize) { + table = realloc(assets->table, (size_t)size * sizeof *table); + if (!table) { + free(assets->table); + assets->table = NULL; + assets->tableSize = 0; + return; + } + assets->table = table; + assets->tableSize = size; + } + memset(assets->table, 0, (size_t)assets->tableSize * sizeof *assets->table); + for (int i = 0; i < assets->count; i++) kon_tableInsert_(assets, i); +} + static kon_assetEntry_t *kon_findEntry_(const kon_assets_t *assets, const char *name) { + if (assets->tableSize) { + uint32_t mask = (uint32_t)assets->tableSize - 1; + uint32_t slot = kon_hashName_(name) & mask; + + while (assets->table[slot]) { + kon_assetEntry_t *entry = &assets->entries[assets->table[slot] - 1]; + if (strcmp(entry->name, name) == 0) return entry; + slot = (slot + 1) & mask; + } + return NULL; + } + for (int i = 0; i < assets->count; i++) { if (strcmp(assets->entries[i].name, name) == 0) return &assets->entries[i]; } @@ -353,6 +406,7 @@ void kon_assetsDestroy(kon_assets_t *assets) { for (int i = 0; i < assets->count; i++) kon_unloadEntry_(assets, &assets->entries[i]); free(assets->entries); + free(assets->table); free(assets->looseDir); free(assets); } @@ -440,6 +494,8 @@ void *kon_assetGetAs(kon_assets_t *assets, const char *name, int type) { entry->loose = loose; entry->unbound = 0; assets->count++; + if (assets->tableSize && assets->count * 2 <= assets->tableSize) kon_tableInsert_(assets, assets->count - 1); + else kon_tableRebuild_(assets); /* this can load more assets and move the entries, so entry is not used after it */ if (assets->loaders[found].bind) assets->loaders[found].bind(object, assets); @@ -447,6 +503,14 @@ void *kon_assetGetAs(kon_assets_t *assets, const char *name, int type) { return object; } +void *kon_assetFind(const kon_assets_t *assets, const char *name) { + kon_assetEntry_t *entry; + + if (!assets || !name) return NULL; + entry = kon_findEntry_(assets, name); + return entry ? entry->object : NULL; +} + void kon_assetRelease(kon_assets_t *assets, const char *name) { kon_assetEntry_t *entry; @@ -455,6 +519,27 @@ void kon_assetRelease(kon_assets_t *assets, const char *name) { if (entry && entry->refs > 0) entry->refs--; } +int kon_assetUnload(kon_assets_t *assets, const char *name) { + kon_assetEntry_t *entry; + int index; + + if (!assets || !name) return 0; + entry = kon_findEntry_(assets, name); + if (!entry) return 0; + if (entry->refs > 0) entry->refs--; + if (entry->refs > 0) return 0; + + /* unbind can give back uses of other assets, which never moves the entries, so this one is still where it was */ + index = (int)(entry - assets->entries); + if (assets->loaders[entry->type].unbind) assets->loaders[entry->type].unbind(entry->object, assets); + entry = &assets->entries[index]; + kon_unloadEntry_(assets, entry); + memmove(entry, entry + 1, (size_t)(assets->count - index - 1) * sizeof *entry); + assets->count--; + kon_tableRebuild_(assets); + return 1; +} + int kon_assetsCollect(kon_assets_t *assets) { int freed = 0, again; @@ -481,6 +566,7 @@ int kon_assetsCollect(kon_assets_t *assets) { } } assets->count = kept; + kon_tableRebuild_(assets); /* something that just became unused has to be looked at again */ again = freed != before; |
