Use stripped Objects in hash.c

These lack the unused .forward field, reducing table memory by ~25%.
Also bump Object.number up to a long, and add a generic Object.data field.
This commit is contained in:
Sage Vaillancourt 2022-04-08 11:49:02 -04:00 committed by Sage Vaillancourt
parent 13d1168401
commit 85fb91b4ed
7 changed files with 66 additions and 29 deletions

View File

@ -57,10 +57,10 @@ struct symFunc {
#define pf(_func) buildFuncSym(_func ## Symbol, &(_func)) #define pf(_func) buildFuncSym(_func ## Symbol, &(_func))
#endif #endif
Object* fetch(const char* name, struct Environment* env) struct StrippedObject* fetch(const char* name, struct Environment* env)
{ {
while (env) { while (env) {
Object* object = getFromTable(&env->table, name); struct StrippedObject* object = getFromTable(&env->table, name);
if (object) { if (object) {
return object; return object;
} }
@ -71,19 +71,23 @@ Object* fetch(const char* name, struct Environment* env)
Object fetchFromEnvironment(const char* name, struct Environment* env) Object fetchFromEnvironment(const char* name, struct Environment* env)
{ {
Object* object = fetch(name, env); struct StrippedObject* object = fetch(name, env);
if (object) { if (object) {
return cloneObject(*object); Object o = deStrip(*object);
return cloneObject(o);
} }
return errorWithContext(DID_NOT_FIND_SYMBOL, name); return errorWithContext(DID_NOT_FIND_SYMBOL, name);
} }
void addToEnv(struct Environment* env, const char* name, const Object obj) void addToEnv(struct Environment* env, const char* name, const Object obj)
{ {
Object* existing = fetch(name, env); struct StrippedObject* existing = fetch(name, env);
if (existing) { if (existing) {
cleanObject(existing); Object o = deStrip(*existing);
*existing = cloneObject(obj); cleanObject(&o);
o = cloneObject(obj);
existing->type = o.type;
existing->data = o.data;
return; return;
} }
char* symbol = malloc(sizeof(char) * (strlen(name) + 1)); char* symbol = malloc(sizeof(char) * (strlen(name) + 1));
@ -252,7 +256,8 @@ void printEnv(struct Environment* env, int printPointers)
printf("Native"); printf("Native");
} else { } else {
size_t length; size_t length;
char* s = stringObj(&env->table.elements[i].object, &length); // SAFETY: Casting to Object is fine because stringObj() doesn't touch .forward
char* s = stringObj((Object *) &env->table.elements[i].object, &length);
printColored(s); printColored(s);
if (env->table.elements[i].object.type == TYPE_STRING) { if (env->table.elements[i].object.type == TYPE_STRING) {
printf("\""); printf("\"");
@ -410,10 +415,11 @@ Object help(Object* params, int length, struct Environment* env)
} }
} }
Object* object = fetch(symbol, env); struct StrippedObject* object = fetch(symbol, env);
if (object) { if (object) {
size_t len = 0; size_t len = 0;
char* string = stringObj(object, &len); // SAFETY: Casting to Object is fine because stringObj() doesn't touch .forward
char* string = stringObj((Object*) object, &len);
Object text = stringFromSlice(string, len); Object text = stringFromSlice(string, len);
free(string); free(string);
return text; return text;

View File

@ -4,9 +4,14 @@
#include "object.h" #include "object.h"
#include "hash.h" #include "hash.h"
struct StrippedObject {
Type type;
void* data;
};
struct EnvElement { struct EnvElement {
char* symbol; char* symbol;
Object object; struct StrippedObject object;
}; };
struct Environment; struct Environment;
@ -19,6 +24,8 @@ struct Environment {
int refs; int refs;
}; };
Object deStrip(struct StrippedObject object);
struct Environment* global(); struct Environment* global();
void setGlobal(struct Environment* env); void setGlobal(struct Environment* env);

View File

@ -3,6 +3,19 @@
#include <string.h> #include <string.h>
void addStripped(struct ObjectTable* table, char* name, struct StrippedObject object);
Object deStrip(struct StrippedObject object)
{
// Garbage .forward data may be safe here, but since usage of that data is
// currently in flux, it should take the more cautious route for now.
return (Object) {
.type = object.type,
.string = object.data,
.forward = NULL,
};
}
struct ObjectTable buildTable(size_t capacity) struct ObjectTable buildTable(size_t capacity)
{ {
struct ObjectTable table = { struct ObjectTable table = {
@ -21,7 +34,8 @@ void deleteTable(struct ObjectTable* table)
for (int i = 0; i < table->capacity; i++) { for (int i = 0; i < table->capacity; i++) {
if (table->elements[i].symbol) { if (table->elements[i].symbol) {
free(table->elements[i].symbol); free(table->elements[i].symbol);
cleanObject(&table->elements[i].object); Object deStripped = deStrip(table->elements[i].object);
cleanObject(&deStripped);
} }
} }
free(table->elements); free(table->elements);
@ -47,7 +61,7 @@ void extendTable(struct ObjectTable* table)
struct ObjectTable newTable = buildTable(table->capacity ? table->capacity * 2 : 4); struct ObjectTable newTable = buildTable(table->capacity ? table->capacity * 2 : 4);
for (int i = 0; i < table->capacity; i++) { for (int i = 0; i < table->capacity; i++) {
if (table->elements[i].symbol) { if (table->elements[i].symbol) {
addToTable(&newTable, table->elements[i].symbol, table->elements[i].object); addStripped(&newTable, table->elements[i].symbol, table->elements[i].object);
} }
} }
free(table->elements); free(table->elements);
@ -55,7 +69,7 @@ void extendTable(struct ObjectTable* table)
} }
} }
Object* getFromTable(struct ObjectTable* table, const char* name) struct StrippedObject* getFromTable(struct ObjectTable* table, const char* name)
{ {
if (table->capacity == 0) { if (table->capacity == 0) {
return NULL; return NULL;
@ -106,11 +120,7 @@ static unsigned long hash(unused const char* str, struct ObjectTable* table)
#endif #endif
/// void addStripped(struct ObjectTable* table, char* name, struct StrippedObject object)
/// \param table
/// \param name Should be a new allocation
/// \param object Should already be cloned
void addToTable(struct ObjectTable* table, char* name, Object object)
{ {
extendTable(table); extendTable(table);
size_t h = hash(name, table); size_t h = hash(name, table);
@ -121,3 +131,15 @@ void addToTable(struct ObjectTable* table, char* name, Object object)
table->elements[h].object = object; table->elements[h].object = object;
table->count += 1; table->count += 1;
} }
///
/// \param table
/// \param name Should be a new allocation
/// \param object Should already be cloned
void addToTable(struct ObjectTable* table, char* name, Object object)
{
addStripped(table, name, (struct StrippedObject) {
.data = object.data,
.type = object.type,
});
}

View File

@ -13,7 +13,7 @@ struct ObjectTable buildTable(size_t capacity);
void addToTable(struct ObjectTable* table, char* name, Object object); void addToTable(struct ObjectTable* table, char* name, Object object);
Object* getFromTable(struct ObjectTable* table, const char* name); struct StrippedObject* getFromTable(struct ObjectTable* table, const char* name);
void deleteTable(struct ObjectTable* table); void deleteTable(struct ObjectTable* table);

View File

@ -245,7 +245,7 @@ int stringNObj(struct string* s, const Object* obj)
inflate(s, 16); inflate(s, 16);
switch (obj->type) { switch (obj->type) {
case TYPE_NUMBER: case TYPE_NUMBER:
s->cursor += sprintf(s->cursor, "%d", obj->number); s->cursor += sprintf(s->cursor, "%ld", obj->number);
break; break;
case TYPE_BOOL: case TYPE_BOOL:
s->cursor += sprintf(s->cursor, "%s", obj->number ? "T" : "F"); s->cursor += sprintf(s->cursor, "%s", obj->number ? "T" : "F");
@ -287,7 +287,7 @@ int stringNObj(struct string* s, const Object* obj)
break; break;
} }
case TYPE_FUNC: case TYPE_FUNC:
s->cursor += sprintf(s->cursor, "F%d", obj->number); s->cursor += sprintf(s->cursor, "F%ld", obj->number);
break; break;
case TYPE_LAMBDA: { case TYPE_LAMBDA: {
#ifdef STANDALONE #ifdef STANDALONE
@ -314,7 +314,7 @@ int stringNObj(struct string* s, const Object* obj)
} }
if (!isValidType(*obj)) { if (!isValidType(*obj)) {
s->cursor += sprintf(s->cursor, "BAD_TYPE(%d) X%d", obj->type, obj->number); s->cursor += sprintf(s->cursor, "BAD_TYPE(%d) X%ld", obj->type, obj->number);
} }
return 0; return 0;
@ -422,8 +422,8 @@ void cleanObject(Object* target)
if (!target->lambda->refs) { if (!target->lambda->refs) {
cleanObject(&target->lambda->params); cleanObject(&target->lambda->params);
cleanObject(&target->lambda->body); cleanObject(&target->lambda->body);
free(target->lambda);
free(target->lambda->params.docString); free(target->lambda->params.docString);
free(target->lambda);
} }
break; break;
case TYPE_STRUCT: case TYPE_STRUCT:

View File

@ -89,7 +89,7 @@ struct Object {
Type type; Type type;
union { union {
int number; long number;
Object* list; Object* list;
char* string; char* string;
@ -104,6 +104,7 @@ struct Object {
#else #else
struct Error* error; struct Error* error;
#endif #endif
void* data;
}; };
union { union {

View File

@ -184,7 +184,7 @@ Object funcyEval(Object* funcy, const Object* passedArguments, int evalLength,
struct Environment* env) struct Environment* env)
{ {
if (!funcy) { if (!funcy) {
eprintf("HIGHLY ILLEGAL NULL FUNCY!!!\n"); eprintf("HIGHLY ILLEGAL NULL FUNC-LIKE!!!\n");
return errorObject(BAD_TYPE); return errorObject(BAD_TYPE);
} }
switch (funcy->type) { switch (funcy->type) {
@ -193,7 +193,7 @@ Object funcyEval(Object* funcy, const Object* passedArguments, int evalLength,
case TYPE_FUNC: case TYPE_FUNC:
return listEvalFunc(funcy, passedArguments, evalLength, env); return listEvalFunc(funcy, passedArguments, evalLength, env);
default: default:
eprintf("HIGHLY ILLEGAL NOT-FUNCY IN funcyEval()!!!\n"); eprintf("HIGHLY ILLEGAL NOT-FUNC IN funcyEval()!!!\n");
return errorObject(BAD_TYPE); return errorObject(BAD_TYPE);
} }
} }
@ -229,8 +229,9 @@ Object evalList(const Object* obj, struct Environment* env)
Object* doc = NULL; Object* doc = NULL;
Object* body = NULL; Object* body = NULL;
if (params) { if (params) {
doc = params->forward && params->forward->forward ? params->forward : NULL; int twoParams = params->forward && params->forward->forward;
body = doc ? params->forward->forward : params->forward; doc = twoParams ? params->forward : NULL;
body = twoParams ? params->forward->forward : params->forward;
} }
return constructLambda(params, doc, body, env); return constructLambda(params, doc, body, env);
} else if (strcmp(first_form->string, "struct") == 0) { } else if (strcmp(first_form->string, "struct") == 0) {