hashmapification

This commit is contained in:
2026-03-16 12:48:37 +01:00
parent bb1307900a
commit 841241833d
3 changed files with 276 additions and 212 deletions

View File

@@ -280,9 +280,7 @@ fail:
static int luaArch_component_list(lua_State *L) {
luaArch *arch = luaArch_from(L);
lua_createtable(L, 64, 0);
for(size_t i = 0; true; i++) {
const char *addr = nn_getComponentAddress(arch->computer, i);
if(addr == NULL) break;
for(const char *addr = nn_getNextComponent(arch->computer, NULL); addr != NULL; addr = nn_getNextComponent(arch->computer, addr)) {
lua_pushstring(L, nn_getComponentType(arch->computer, addr));
lua_setfield(L, -2, addr);
}
@@ -378,14 +376,13 @@ static int luaArch_component_methods(lua_State *L) {
lua_pushstring(L, "no such component");
return 2;
}
size_t len;
const nn_Method *methods = nn_getComponentMethods(arch->computer, address, &len);
lua_createtable(L, 0, len);
for(size_t i = 0; i < len; i++) {
if(methods[i].flags & NN_FIELD_MASK) continue; // skip
const nn_Method *method = nn_nextComponentMethod(arch->computer, address, NULL);
lua_createtable(L, 0, 0);
for(; method != NULL; method = nn_nextComponentMethod(arch->computer, address, method)) {
if(method->flags & NN_FIELD_MASK) continue; // skip
lua_pushboolean(L, (methods[i].flags & NN_DIRECT) != 0);
lua_setfield(L, -2, methods[i].name);
lua_pushboolean(L, (method->flags & NN_DIRECT) != 0);
lua_setfield(L, -2, method->name);
}
return 1;
}
@@ -399,20 +396,19 @@ static int luaArch_component_fields(lua_State *L) {
lua_pushstring(L, "no such component");
return 2;
}
size_t len;
const nn_Method *methods = nn_getComponentMethods(arch->computer, address, &len);
lua_createtable(L, 0, len);
for(size_t i = 0; i < len; i++) {
if((methods[i].flags & NN_FIELD_MASK) == 0) continue; // skip
const nn_Method *method = nn_nextComponentMethod(arch->computer, address, NULL);
lua_createtable(L, 0, 0);
for(; method != NULL; method = nn_nextComponentMethod(arch->computer, address, method)) {
if((method->flags & NN_FIELD_MASK) == 0) continue; // skip
lua_createtable(L, 0, 3);
lua_pushboolean(L, (methods[i].flags & NN_DIRECT) != 0);
lua_pushboolean(L, (method->flags & NN_DIRECT) != 0);
lua_setfield(L, -2, "direct");
lua_pushboolean(L, (methods[i].flags & NN_GETTER) != 0);
lua_pushboolean(L, (method->flags & NN_GETTER) != 0);
lua_setfield(L, -2, "getter");
lua_pushboolean(L, (methods[i].flags & NN_SETTER) != 0);
lua_pushboolean(L, (method->flags & NN_SETTER) != 0);
lua_setfield(L, -2, "setter");
lua_setfield(L, -2, methods[i].name);
lua_setfield(L, -2, method->name);
}
return 1;
}

View File

@@ -309,6 +309,8 @@ void nn_crc32ChecksumBytes(unsigned int checksum, char out[8]) {
}
}
// TODO: rework completely
// apparently can overflow??
bool nn_simplifyPath(const char original[NN_MAX_PATH], char simplified[NN_MAX_PATH]) {
// pass 1: check for valid characters, and \ becomes /
for(size_t i = 0; true; i++) {
@@ -572,6 +574,7 @@ typedef enum nn_HashAction {
// slot is the memory in the hashmap.
// for NN_HASH_CMP, entry is the key, and may be NULL if we are only trying to get the state of a slot for iteration.
// if entry is NULL, NN_HASH_EQUAL is invalid and NN_HASH_DIFFERENT means it is used up.
// for NN_HASH_CMP, a HashEntryState should be returned.
typedef size_t (nn_HashHandler)(nn_HashAction action, void *slot, void *entry);
@@ -587,10 +590,10 @@ typedef struct nn_HashMap {
void *buf;
size_t bufsize;
nn_Context *ctx;
nn_HashContext *hash;
const nn_HashContext *hash;
} nn_HashMap;
nn_Exit nn_hashInit(nn_HashMap *map, size_t capacity, nn_Context *ctx, nn_HashContext *hash) {
nn_Exit nn_hashInit(nn_HashMap *map, size_t capacity, nn_Context *ctx, const nn_HashContext *hash) {
void *buf = nn_alloc(ctx, hash->entSize * capacity);
if(buf == NULL) return NN_ENOMEM;
map->buf = buf;
@@ -616,10 +619,60 @@ void *nn_hashGetAt(nn_HashMap *map, size_t idx) {
}
// get by entry by key. It is assumed that the entry is NULL.
void *nn_hashGet(nn_HashMap *map, void *entry);
void *nn_hashGet(nn_HashMap *map, void *entry) {
if(entry == NULL) return NULL;
size_t len = map->bufsize;
if(len == 0) return NULL;
size_t base = nn_hashGetHash(map, entry) % len;
size_t entSize = map->hash->entSize;
for(size_t i = 0; i < len; i++) {
size_t j = (base + i) % len;
void *slot = NN_PTROFF(map->buf, j, entSize);
nn_HashEntryState state = map->hash->handler(NN_HASH_CMP, slot, entry);
switch(state) {
case NN_HASH_EQUAL:
return slot;
case NN_HASH_DIFFERENT:
case NN_HASH_REMOVED:
continue;
case NN_HASH_FREE:
break;
}
}
return NULL;
}
// should put the entire entry over there.
void *nn_hashPut(nn_HashMap *map, void *entry);
void *nn_hashRemove(nn_HashMap *map, void *entry);
// False on ENOSPC.
bool nn_hashPut(nn_HashMap *map, void *entry) {
if(entry == NULL) return false;
size_t len = map->bufsize;
if(len == 0) return false;
size_t base = nn_hashGetHash(map, entry) % len;
size_t entSize = map->hash->entSize;
for(size_t i = 0; i < len; i++) {
size_t j = (base + i) % len;
void *slot = NN_PTROFF(map->buf, j, entSize);
nn_HashEntryState state = map->hash->handler(NN_HASH_CMP, slot, entry);
switch(state) {
case NN_HASH_EQUAL:
case NN_HASH_REMOVED:
case NN_HASH_FREE:
nn_memcpy(slot, entry, entSize);
return true;
case NN_HASH_DIFFERENT:
continue;
}
}
return false;
}
// remove an entry
void nn_hashRemove(nn_HashMap *map, void *entry) {
void *mem = nn_hashGet(map, entry);
if(mem == NULL) return;
map->hash->handler(NN_HASH_REMOVE, mem, NULL);
}
// takes in an entry and returns the next one. If entry is NULL, it will return the first one.
// Returns NULL on empty.
@@ -633,6 +686,23 @@ void *nn_hashIterate(nn_HashMap *map, void *entry) {
} else {
entry = NN_PTROFF(entry, 1, entSize);
}
while(true) {
if(entry == bufEnd) return NULL;
nn_HashEntryState state = map->hash->handler(NN_HASH_CMP, entry, NULL);
if(state == NN_HASH_DIFFERENT) break;
entry = NN_PTROFF(entry, 1, entSize);
}
return entry;
}
// from https://gist.github.com/MohamedTaha98/ccdf734f13299efb73ff0b12f7ce429f
// TODO: experiment with better ones
size_t nn_strhash(const char *s) {
size_t hash = 5381;
int c;
while ((c = *s++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
// real stuff
@@ -643,11 +713,36 @@ typedef struct nn_ComponentState {
nn_Arena arena;
const char *name;
nn_ComponentHandler *handler;
// NULL-terminated
nn_Method *methods;
size_t methodCount;
nn_HashMap methods;
} nn_ComponentState;
static size_t nn_methodHash(nn_HashAction act, nn_Method *slot, nn_Method *ent) {
switch(act) {
case NN_HASH_INIT:
slot->name = NULL;
slot->flags = -1;
break;
case NN_HASH_HASH:
return nn_strhash(slot->name);
case NN_HASH_REMOVE:
slot->flags = -1;
break;
case NN_HASH_CMP:
if(slot->name == NULL) return NN_HASH_FREE;
if(slot->flags == -1) return NN_HASH_REMOVED;
if(ent == NULL) {
return NN_HASH_DIFFERENT;
}
return nn_strcmp(slot->name, ent->name) == 0 ? NN_HASH_EQUAL : NN_HASH_DIFFERENT;
}
return 0;
}
static const nn_HashContext nn_methodHasher = {
.entSize = sizeof(nn_Method),
.handler = (nn_HashHandler *)nn_methodHash,
};
// currently just a wrapper around a context
// but will be way more in the future
typedef struct nn_Universe {
@@ -663,6 +758,31 @@ typedef struct nn_Component {
void *state;
} nn_Component;
static size_t nn_componentHash(nn_HashAction act, nn_Component *slot, nn_Component *ent) {
switch(act) {
case NN_HASH_INIT:
slot->address = NULL;
slot->cstate = NULL;
break;
case NN_HASH_HASH:
return nn_strhash(slot->address);
case NN_HASH_REMOVE:
slot->cstate = NULL;
break;
case NN_HASH_CMP:
if(slot->address == NULL) return NN_HASH_FREE;
if(slot->cstate == NULL) return NN_HASH_REMOVED;
if(ent == NULL) return NN_HASH_DIFFERENT;
return nn_strcmp(slot->address, ent->address) == 0 ? NN_HASH_EQUAL : NN_HASH_DIFFERENT;
}
return 0;
}
static const nn_HashContext nn_componentHasher = {
.entSize = sizeof(nn_Component),
.handler = (nn_HashHandler *)nn_componentHash,
};
// the values
typedef enum nn_ValueType {
NN_VAL_NULL,
@@ -725,9 +845,7 @@ typedef struct nn_Computer {
nn_Architecture desiredArch;
size_t callBudget;
size_t totalCallBudget;
size_t componentCap;
size_t componentLen;
nn_Component *components;
nn_HashMap components;
size_t deviceInfoCap;
size_t deviceInfoLen;
nn_DeviceInfo *deviceInfo;
@@ -769,6 +887,7 @@ nn_ComponentState *nn_createComponentState(nn_Universe *universe, const char *na
ctype->universe = universe;
ctype->userdata = userdata;
ctype->handler = handler;
ctype->methods.ctx = NULL;
nn_Arena *arena = &ctype->arena;
nn_arinit(arena, ctx);
@@ -780,10 +899,7 @@ nn_ComponentState *nn_createComponentState(nn_Universe *universe, const char *na
size_t methodCount = 0;
while(methods[methodCount].name != NULL) methodCount++;
nn_Method *methodscpy = nn_aralloc(arena, methodCount * sizeof(nn_Method));
if(methodscpy == NULL) goto fail;
ctype->methods = methodscpy;
ctype->methodCount = methodCount;
if(nn_hashInit(&ctype->methods, methodCount, ctx, &nn_methodHasher)) goto fail;
for(size_t i = 0; i < methodCount; i++) {
nn_Method cpy;
@@ -793,12 +909,12 @@ nn_ComponentState *nn_createComponentState(nn_Universe *universe, const char *na
cpy.docString = nn_arstrdup(arena, methods[i].docString);
if(cpy.docString == NULL) goto fail;
ctype->methods[i] = cpy;
if(!nn_hashPut(&ctype->methods, &cpy)) goto fail;
}
return ctype;
fail:;
// yes, because of arenas, we support freeing a "partially initialized state"
// yes, because of arenas and a bit of hashmap bullshit, we support freeing a "partially initialized state"
nn_destroyComponentState(ctype);
return NULL;
}
@@ -817,6 +933,10 @@ void nn_destroyComponentState(nn_ComponentState *ctype) {
req.methodCalled = NULL;
ctype->handler(&req);
if(ctype->methods.ctx != NULL) {
nn_hashDeinit(&ctype->methods);
}
nn_ardestroy(&ctype->arena);
nn_free(ctx, ctype, sizeof(nn_ComponentState));
}
@@ -863,10 +983,7 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char
c->totalCallBudget = 50000;
c->callBudget = c->totalCallBudget;
c->componentCap = maxComponents;
c->componentLen = 0;
c->components = nn_alloc(ctx, sizeof(nn_Component) * maxComponents);
if(c->components == NULL) {
if(nn_hashInit(&c->components, maxComponents, ctx, &nn_componentHasher)) {
nn_strfree(ctx, c->address);
nn_free(ctx, c, sizeof(nn_Computer));
return NULL;
@@ -876,7 +993,7 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char
c->deviceInfoLen = 0;
c->deviceInfo = nn_alloc(ctx, sizeof(nn_DeviceInfo) * maxDevices);
if(c->deviceInfo == NULL) {
nn_free(ctx, c->components, sizeof(nn_Component) * maxComponents);
nn_hashDeinit(&c->components);
nn_strfree(ctx, c->address);
nn_free(ctx, c, sizeof(nn_Computer));
return NULL;
@@ -900,6 +1017,20 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char
static void nn_dropValue(nn_Value val);
static void nn_dropComponent(nn_Computer *computer, nn_Component c);
static nn_Component *nn_getInternalComponent(nn_Computer *computer, const char *address) {
nn_Component lookingFor = {
.address = (char *)address,
};
return nn_hashGet(&computer->components, &lookingFor);
}
static const nn_Method *nn_getInternalMethod(nn_Component *c, const char *method) {
nn_Method lookingFor = {
.name = method,
};
return nn_hashGet(&c->cstate->methods, &lookingFor);
}
void nn_destroyComputer(nn_Computer *computer) {
nn_Context *ctx = &computer->universe->ctx;
@@ -915,8 +1046,9 @@ void nn_destroyComputer(nn_Computer *computer) {
for(size_t i = 0; i < computer->stackSize; i++) {
nn_dropValue(computer->callstack[i]);
}
for(size_t i = 0; i < computer->componentLen; i++) {
nn_dropComponent(computer, computer->components[i]);
for(const char *addr = nn_getNextComponent(computer, NULL); addr != NULL; addr = nn_getNextComponent(computer, addr)) {
nn_Component *c = nn_getInternalComponent(computer, addr);
nn_dropComponent(computer, *c);
}
for(size_t i = 0; i < computer->signalCount; i++) {
nn_Signal s = computer->signals[i];
@@ -927,7 +1059,7 @@ void nn_destroyComputer(nn_Computer *computer) {
nn_strfree(ctx, computer->users[i]);
}
nn_free(ctx, computer->components, sizeof(nn_Component) * computer->componentCap);
nn_hashDeinit(&computer->components);
nn_free(ctx, computer->deviceInfo, sizeof(nn_DeviceInfo) * computer->deviceInfoCap);
if(computer->tmpaddress != NULL) nn_strfree(ctx, computer->tmpaddress);
nn_strfree(ctx, computer->address);
@@ -1267,8 +1399,6 @@ nn_Exit nn_tick(nn_Computer *computer) {
}
nn_Exit nn_addComponent(nn_Computer *computer, nn_ComponentState *ctype, const char *address, int slot, void *userdata) {
if(computer->componentLen == computer->componentCap) return NN_ELIMIT;
nn_Component c;
c.address = nn_strdup(&computer->universe->ctx, address);
if(c.address == NULL) return NN_ENOMEM;
@@ -1295,7 +1425,10 @@ nn_Exit nn_addComponent(nn_Computer *computer, nn_ComponentState *ctype, const c
// get the state back!
c.state = req.state;
computer->components[computer->componentLen++] = c;
if(!nn_hashPut(&computer->components, &c)) {
nn_dropComponent(computer, c);
return NN_ELIMIT;
}
if(computer->state == NN_RUNNING) {
err = nn_pushstring(computer, "component_added");
@@ -1310,45 +1443,15 @@ nn_Exit nn_addComponent(nn_Computer *computer, nn_ComponentState *ctype, const c
return NN_OK;
}
bool nn_hasComponent(nn_Computer *computer, const char *address) {
for(size_t i = 0; i < computer->componentLen; i++) {
nn_Component *c = &computer->components[i];
if(nn_strcmp(c->address, address) == 0) {
return true;
}
}
return false;
return nn_getInternalComponent(computer, address) != NULL;
}
bool nn_hasMethod(nn_Computer *computer, const char *address, const char *method) {
for(size_t i = 0; i < computer->componentLen; i++) {
nn_Component *c = &computer->components[i];
if(nn_strcmp(c->address, address) != 0) continue;
bool found = false;
for(size_t j = 0; j < c->cstate->methodCount; j++) {
if(nn_strcmp(c->cstate->methods[j].name, method) != 0) continue;
found = true;
break;
}
if(!found) return false;
nn_ComponentRequest req;
req.typeUserdata = c->cstate->userdata;
req.compUserdata = c->userdata;
req.state = c->state;
req.computer = computer;
req.compAddress = address;
req.action = NN_COMP_ENABLED;
req.methodCalled = method;
// default response in case it is not implemented
req.methodEnabled = true;
// should never error
c->cstate->handler(&req);
return req.methodEnabled;
}
return false;
nn_Component *c = nn_getInternalComponent(computer, address);
if(c == NULL) return false;
return nn_getInternalMethod(c, method) != NULL;
}
static void nn_dropComponent(nn_Computer *computer, nn_Component c) {
@@ -1368,21 +1471,13 @@ static void nn_dropComponent(nn_Computer *computer, nn_Component c) {
nn_Exit nn_removeComponent(nn_Computer *computer, const char *address) {
size_t j = 0;
nn_Component c;
c.address = NULL;
for(size_t i = 0; i < computer->componentLen; i++) {
if(nn_strcmp(computer->components[i].address, address) == 0) {
c = computer->components[i];
} else {
computer->components[j++] = computer->components[i];
}
}
computer->componentLen = j;
nn_Component *pc = nn_getInternalComponent(computer, address);
// already removed!
if(c.address == NULL) return NN_EBADSTATE;
if(pc == NULL) return NN_EBADSTATE;
// copied cuz hashRemove will invalidate the memory
nn_Component c = *pc;
nn_dropComponent(computer, c);
nn_hashRemove(&computer->components, pc);
if(computer->state == NN_RUNNING) {
nn_Exit err = nn_pushstring(computer, "component_removed");
@@ -1399,69 +1494,50 @@ nn_Exit nn_removeComponent(nn_Computer *computer, const char *address) {
}
const char *nn_getComponentType(nn_Computer *computer, const char *address) {
for(size_t i = 0; i < computer->componentLen; i++) {
nn_Component *c = &computer->components[i];
if(nn_strcmp(c->address, address) == 0) {
return c->cstate->name;
}
}
return NULL;
nn_Component *c = nn_getInternalComponent(computer, address);
if(c == NULL) return NULL;
return c->cstate->name;
}
int nn_getComponentSlot(nn_Computer *computer, const char *address) {
for(size_t i = 0; i < computer->componentLen; i++) {
nn_Component *c = &computer->components[i];
if(nn_strcmp(c->address, address) == 0) {
return c->slot;
}
}
return 0;
nn_Component *c = nn_getInternalComponent(computer, address);
if(c == NULL) return -1;
return c->slot;
}
const nn_Method *nn_getComponentMethods(nn_Computer *computer, const char *address, size_t *len) {
for(size_t i = 0; i < computer->componentLen; i++) {
nn_Component *c = &computer->components[i];
if(nn_strcmp(c->address, address) == 0) {
if(len != NULL) *len = c->cstate->methodCount;
return c->cstate->methods;
}
}
if(len != NULL) *len = 0;
return NULL;
const nn_Method *nn_nextComponentMethod(nn_Computer *computer, const char *address, const nn_Method *method) {
nn_Component *c = nn_getInternalComponent(computer, address);
if(c == NULL) return NULL;
// fuck the const qualifier
return nn_hashIterate(&c->cstate->methods, (void *)method);
}
const char *nn_getComponentAddress(nn_Computer *computer, size_t idx) {
if(idx >= computer->componentLen) return NULL;
return computer->components[idx].address;
const char *nn_getNextComponent(nn_Computer *computer, const char *prev) {
if(prev == NULL) {
nn_Component *c = nn_hashIterate(&computer->components, NULL);
if(c == NULL) return NULL;
return c->address;
}
nn_Component *c = nn_getInternalComponent(computer, prev);
printf("cur addr iter: %s comp: %p\n", prev == NULL ? "(null)" : prev, c);
if(c == NULL) return NULL;
c = nn_hashIterate(&computer->components, c);
if(c == NULL) return NULL;
return c->address;
}
const char *nn_getComponentDoc(nn_Computer *computer, const char *address, const char *method) {
if(!nn_hasComponent(computer, address)) {
return NULL;
}
if(!nn_hasMethod(computer, address, method)) {
return NULL;
}
for(size_t i = 0; i < computer->componentLen; i++) {
nn_Component c = computer->components[i];
if(nn_strcmp(c.address, address) != 0) continue;
for(size_t j = 0; j < c.cstate->methodCount; j++) {
if(nn_strcmp(c.cstate->methods[j].name, method) == 0) return c.cstate->methods[j].docString;
}
return NULL;
}
return NULL;
nn_Component *c = nn_getInternalComponent(computer, address);
if(c == NULL) return NULL;
const nn_Method *m = nn_getInternalMethod(c, method);
if(m == NULL) return NULL;
return m->docString;
}
void *nn_getComponentUserdata(nn_Computer *computer, const char *address) {
for(size_t i = 0; i < computer->componentLen; i++) {
nn_Component *c = &computer->components[i];
if(nn_strcmp(c->address, address) == 0) {
return c->userdata;
}
}
return 0;
nn_Component *c = nn_getInternalComponent(computer, address);
if(c == NULL) return NULL;
return c->userdata;
}
static void nn_retainValue(nn_Value val) {
@@ -1507,64 +1583,55 @@ static void nn_dropValue(nn_Value val) {
}
nn_Exit nn_call(nn_Computer *computer, const char *address, const char *method) {
if(!nn_hasComponent(computer, address)) {
nn_Component *c = nn_getInternalComponent(computer, address);
if(c == NULL) {
nn_setError(computer, "no such component");
return NN_EBADCALL;
}
if(!nn_hasMethod(computer, address, method)) {
const nn_Method *m = nn_getInternalMethod(c, method);
if(m == NULL) {
nn_setError(computer, "no such method");
return NN_EBADCALL;
}
for(size_t i = 0; i < computer->componentLen; i++) {
nn_Component c = computer->components[i];
if(nn_strcmp(c.address, address) != 0) continue;
// minimum cost of a component call
if(computer->callBudget > 0) computer->callBudget--;
//if((m->flags & NN_DIRECT) == NN_INDIRECT) computer->callBudget = 0;
nn_ComponentRequest req;
req.typeUserdata = c->cstate->userdata;
req.compUserdata = c->userdata;
req.state = c->state;
req.computer = computer;
req.compAddress = address;
req.action = NN_COMP_CALL;
req.methodCalled = method;
// default is to return nothing
req.returnCount = 0;
// minimum cost of a component call
if(computer->callBudget > 0) computer->callBudget--;
for(size_t j = 0; j < c.cstate->methodCount; j++) {
nn_Method m = c.cstate->methods[j];
if(nn_strcmp(m.name, method) != 0) continue;
// indirect calls consume the entire call budget
//if((m.flags & NN_DIRECT) == NN_INDIRECT) computer->callBudget = 0;
}
nn_ComponentRequest req;
req.typeUserdata = c.cstate->userdata;
req.compUserdata = c.userdata;
req.state = c.state;
req.computer = computer;
req.compAddress = address;
req.action = NN_COMP_CALL;
req.methodCalled = method;
// default is to return nothing
req.returnCount = 0;
nn_Exit err = c.cstate->handler(&req);
if(err) {
if(err != NN_EBADCALL) nn_setErrorFromExit(computer, err);
// clear junk
nn_clearstack(computer);
return err;
}
if(computer->stackSize < req.returnCount) {
err = NN_EBELOWSTACK;
nn_setErrorFromExit(computer, err);
nn_clearstack(computer);
return err;
}
size_t endOfTrim = computer->stackSize - req.returnCount;
for(size_t i = 0; i < endOfTrim; i++) {
nn_dropValue(computer->callstack[i]);
}
for(size_t i = 0; i < req.returnCount; i++) {
computer->callstack[i] = computer->callstack[endOfTrim + i];
}
computer->stackSize = req.returnCount;
return NN_OK;
nn_Exit err = c->cstate->handler(&req);
if(err) {
if(err != NN_EBADCALL) nn_setErrorFromExit(computer, err);
// clear junk
nn_clearstack(computer);
return err;
}
return NN_EBADSTATE;
if(computer->stackSize < req.returnCount) {
err = NN_EBELOWSTACK;
nn_setErrorFromExit(computer, err);
nn_clearstack(computer);
return err;
}
size_t endOfTrim = computer->stackSize - req.returnCount;
for(size_t i = 0; i < endOfTrim; i++) {
nn_dropValue(computer->callstack[i]);
}
for(size_t i = 0; i < req.returnCount; i++) {
computer->callstack[i] = computer->callstack[endOfTrim + i];
}
computer->stackSize = req.returnCount;
return NN_OK;
}
void nn_setCallBudget(nn_Computer *computer, size_t budget) {
@@ -1584,16 +1651,16 @@ void nn_resetCallBudget(nn_Computer *computer) {
}
bool nn_componentsOverused(nn_Computer *computer) {
for(size_t i = 0; i < computer->componentLen; i++) {
if(computer->components[i].budgetUsed >= NN_COMPONENT_CALLBUDGET) return true;
for(nn_Component *c = nn_hashIterate(&computer->components, NULL); c != NULL; c = nn_hashIterate(&computer->components, c)) {
if(c->budgetUsed >= NN_COMPONENT_CALLBUDGET) return true;
}
if(computer->totalCallBudget == 0) return false;
return computer->callBudget == 0;
}
void nn_resetComponentBudgets(nn_Computer *computer) {
for(size_t i = 0; i < computer->componentLen; i++) {
computer->components[i].budgetUsed = 0;
for(nn_Component *c = nn_hashIterate(&computer->components, NULL); c != NULL; c = nn_hashIterate(&computer->components, c)) {
c->budgetUsed = 0;
}
}
bool nn_costComponent(nn_Computer *computer, const char *address, double perTick) {
@@ -1601,13 +1668,10 @@ bool nn_costComponent(nn_Computer *computer, const char *address, double perTick
}
bool nn_costComponentN(nn_Computer *computer, const char *address, double amount, double perTick) {
for(size_t i = 0; i < computer->componentLen; i++) {
nn_Component *c = &computer->components[i];
if(nn_strcmp(c->address, address) != 0) continue;
c->budgetUsed += (NN_COMPONENT_CALLBUDGET * amount) / perTick;
return c->budgetUsed >= NN_COMPONENT_CALLBUDGET;
}
return false;
nn_Component *c = nn_getInternalComponent(computer, address);
if(c == NULL) return false;
c->budgetUsed += (NN_COMPONENT_CALLBUDGET * amount) / perTick;
return c->budgetUsed >= NN_COMPONENT_CALLBUDGET;
}
bool nn_checkstack(nn_Computer *computer, size_t amount) {

View File

@@ -511,6 +511,7 @@ typedef struct nn_Method {
const char *name;
const char *docString;
nn_MethodFlags flags;
int idx;
} nn_Method;
typedef struct nn_ComponentState nn_ComponentState;
@@ -575,12 +576,15 @@ nn_Exit nn_removeComponent(nn_Computer *computer, const char *address);
const char *nn_getComponentType(nn_Computer *computer, const char *address);
// Gets the slot of a component.
int nn_getComponentSlot(nn_Computer *computer, const char *address);
// Returns the array of component methods. This can be used for doc strings or just listing methods.
const nn_Method *nn_getComponentMethods(nn_Computer *computer, const char *address, size_t *len);
// get the address at a certain index.
// It'll return NULL for out of bounds indexes.
// This can be used to iterate over all components.
const char *nn_getComponentAddress(nn_Computer *computer, size_t idx);
// Iterates over the methods of a component.
// Returns NULL at end of iteration.
// name should be NULL at the start.
// NOTE: the method pointer MUST be returned by the iterator, as it is offset during iteration.
const nn_Method *nn_nextComponentMethod(nn_Computer *computer, const char *address, const nn_Method *old);
// iterate over components.
// for prev = NULL, returns the first one.
// returns NULL at the end of iteration.
const char *nn_getNextComponent(nn_Computer *computer, const char *prev);
// Returns the doc-string associated with a method.
const char *nn_getComponentDoc(nn_Computer *computer, const char *address, const char *method);
void *nn_getComponentUserdata(nn_Computer *computer, const char *address);