1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-24 17:27:18 +00:00
janet/core/stringcache.c
2017-03-22 00:27:18 -04:00

121 lines
3.6 KiB
C

#include <gst/gst.h>
#include "stringcache.h"
/* Dud pointer to serve as deletion marker */
static uint8_t *deleted = (uint8_t *) "DELETED";
/* Initialize the string cache for a vm */
void gst_stringcache_init(Gst *vm, uint32_t capacity) {
vm->strings = gst_raw_calloc(1, capacity * sizeof(uint8_t *));
if (vm->strings == NULL)
GST_OUT_OF_MEMORY;
vm->stringsCapacity = capacity;
vm->stringsCount = 0;
vm->stringsDeleted = 0;
}
/* Deinitialize the stringcache for a vm */
void gst_stringcache_deinit(Gst *vm) {
gst_raw_free(vm->strings);
vm->stringsCapacity = 0;
vm->stringsCount = 0;
vm->stringsDeleted = 0;
}
/* Find a string in the hashtable. Returns null if
* not found. */
static uint8_t **gst_stringcache_find(Gst *vm, uint8_t *str, int *success) {
uint32_t bounds[4];
uint32_t i, j, index, hash;
uint8_t **firstEmpty = NULL;
hash = gst_string_hash(str);
if (!hash) {
hash = gst_string_hash(str) = gst_string_calchash(str);
}
index = hash % vm->stringsCapacity;
bounds[0] = index;
bounds[1] = vm->stringsCapacity;
bounds[2] = 0;
bounds[3] = index;
for (j = 0; j < 4; j += 2)
for (i = bounds[j]; i < bounds[j+1]; ++i) {
uint8_t *testStr = vm->strings[i];
/* Check empty spots */
if (testStr == NULL) {
if (firstEmpty == NULL)
firstEmpty = vm->strings + i;
goto notfound;
}
if (testStr == deleted) {
if (firstEmpty == NULL)
firstEmpty = vm->strings + i;
continue;
}
if (gst_string_equal(testStr, str)) {
/* Replace first deleted */
*success = 1;
if (firstEmpty != NULL) {
*firstEmpty = testStr;
vm->strings[i] = deleted;
return firstEmpty;
}
return vm->strings + i;
}
}
notfound:
*success = 0;
return firstEmpty;
}
/* Resize the hashtable. */
static void gst_stringcache_resize(Gst *vm, uint32_t newCapacity) {
uint32_t i, oldCapacity;
uint8_t **oldCache = vm->strings;
uint8_t **newCache = gst_raw_calloc(1, newCapacity * sizeof(uint8_t *));
if (newCache == NULL)
GST_OUT_OF_MEMORY;
oldCapacity = vm->stringsCapacity;
vm->strings = newCache;
vm->stringsCapacity = newCapacity;
vm->stringsCount = 0;
vm->stringsDeleted = 0;
/* Add all of the old strings back */
for (i = 0; i < oldCapacity; ++i) {
uint8_t *str = oldCache[i];
if (str != NULL && str != deleted)
gst_stringcache_get(vm, str);
}
/* Free the old cache */
gst_raw_free(oldCache);
}
/* Get a string from the string cache */
uint8_t *gst_stringcache_get(Gst *vm, uint8_t *str) {
int status = 0;
uint8_t **bucket = gst_stringcache_find(vm, str, &status);
if (status) {
return *bucket;
} else {
if ((vm->stringsCount + vm->stringsDeleted) * 2 > vm->stringsCapacity) {
gst_stringcache_resize(vm, vm->stringsCount * 4);
bucket = gst_stringcache_find(vm, str, &status);
}
vm->stringsCount++;
*bucket = str;
/* Mark the memory as string memory */
gst_mem_tag(gst_string_raw(str), GST_MEMTAG_STRING);
return str;
}
}
/* Remove a string from the cache */
void gst_stringcache_remove(Gst *vm, uint8_t *str) {
int status = 0;
uint8_t **bucket = gst_stringcache_find(vm, str, &status);
if (status) {
vm->stringsCount--;
vm->stringsDeleted++;
*bucket = deleted;
}
}