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:
parent
13d1168401
commit
85fb91b4ed
26
src/env.c
26
src/env.c
|
@ -57,10 +57,10 @@ struct symFunc {
|
|||
#define pf(_func) buildFuncSym(_func ## Symbol, &(_func))
|
||||
#endif
|
||||
|
||||
Object* fetch(const char* name, struct Environment* env)
|
||||
struct StrippedObject* fetch(const char* name, struct Environment* env)
|
||||
{
|
||||
while (env) {
|
||||
Object* object = getFromTable(&env->table, name);
|
||||
struct StrippedObject* object = getFromTable(&env->table, name);
|
||||
if (object) {
|
||||
return object;
|
||||
}
|
||||
|
@ -71,19 +71,23 @@ Object* fetch(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) {
|
||||
return cloneObject(*object);
|
||||
Object o = deStrip(*object);
|
||||
return cloneObject(o);
|
||||
}
|
||||
return errorWithContext(DID_NOT_FIND_SYMBOL, name);
|
||||
}
|
||||
|
||||
void addToEnv(struct Environment* env, const char* name, const Object obj)
|
||||
{
|
||||
Object* existing = fetch(name, env);
|
||||
struct StrippedObject* existing = fetch(name, env);
|
||||
if (existing) {
|
||||
cleanObject(existing);
|
||||
*existing = cloneObject(obj);
|
||||
Object o = deStrip(*existing);
|
||||
cleanObject(&o);
|
||||
o = cloneObject(obj);
|
||||
existing->type = o.type;
|
||||
existing->data = o.data;
|
||||
return;
|
||||
}
|
||||
char* symbol = malloc(sizeof(char) * (strlen(name) + 1));
|
||||
|
@ -252,7 +256,8 @@ void printEnv(struct Environment* env, int printPointers)
|
|||
printf("Native");
|
||||
} else {
|
||||
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);
|
||||
if (env->table.elements[i].object.type == TYPE_STRING) {
|
||||
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) {
|
||||
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);
|
||||
free(string);
|
||||
return text;
|
||||
|
|
|
@ -4,9 +4,14 @@
|
|||
#include "object.h"
|
||||
#include "hash.h"
|
||||
|
||||
struct StrippedObject {
|
||||
Type type;
|
||||
void* data;
|
||||
};
|
||||
|
||||
struct EnvElement {
|
||||
char* symbol;
|
||||
Object object;
|
||||
struct StrippedObject object;
|
||||
};
|
||||
|
||||
struct Environment;
|
||||
|
@ -19,6 +24,8 @@ struct Environment {
|
|||
int refs;
|
||||
};
|
||||
|
||||
Object deStrip(struct StrippedObject object);
|
||||
|
||||
struct Environment* global();
|
||||
|
||||
void setGlobal(struct Environment* env);
|
||||
|
|
38
src/hash.c
38
src/hash.c
|
@ -3,6 +3,19 @@
|
|||
|
||||
#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 table = {
|
||||
|
@ -21,7 +34,8 @@ void deleteTable(struct ObjectTable* table)
|
|||
for (int i = 0; i < table->capacity; i++) {
|
||||
if (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);
|
||||
|
@ -47,7 +61,7 @@ void extendTable(struct ObjectTable* table)
|
|||
struct ObjectTable newTable = buildTable(table->capacity ? table->capacity * 2 : 4);
|
||||
for (int i = 0; i < table->capacity; i++) {
|
||||
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);
|
||||
|
@ -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) {
|
||||
return NULL;
|
||||
|
@ -106,11 +120,7 @@ static unsigned long hash(unused const char* str, struct ObjectTable* table)
|
|||
|
||||
#endif
|
||||
|
||||
///
|
||||
/// \param table
|
||||
/// \param name Should be a new allocation
|
||||
/// \param object Should already be cloned
|
||||
void addToTable(struct ObjectTable* table, char* name, Object object)
|
||||
void addStripped(struct ObjectTable* table, char* name, struct StrippedObject object)
|
||||
{
|
||||
extendTable(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->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,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ struct ObjectTable buildTable(size_t capacity);
|
|||
|
||||
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);
|
||||
|
||||
|
|
|
@ -245,7 +245,7 @@ int stringNObj(struct string* s, const Object* obj)
|
|||
inflate(s, 16);
|
||||
switch (obj->type) {
|
||||
case TYPE_NUMBER:
|
||||
s->cursor += sprintf(s->cursor, "%d", obj->number);
|
||||
s->cursor += sprintf(s->cursor, "%ld", obj->number);
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
s->cursor += sprintf(s->cursor, "%s", obj->number ? "T" : "F");
|
||||
|
@ -287,7 +287,7 @@ int stringNObj(struct string* s, const Object* obj)
|
|||
break;
|
||||
}
|
||||
case TYPE_FUNC:
|
||||
s->cursor += sprintf(s->cursor, "F%d", obj->number);
|
||||
s->cursor += sprintf(s->cursor, "F%ld", obj->number);
|
||||
break;
|
||||
case TYPE_LAMBDA: {
|
||||
#ifdef STANDALONE
|
||||
|
@ -314,7 +314,7 @@ int stringNObj(struct string* s, const Object* 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;
|
||||
|
@ -422,8 +422,8 @@ void cleanObject(Object* target)
|
|||
if (!target->lambda->refs) {
|
||||
cleanObject(&target->lambda->params);
|
||||
cleanObject(&target->lambda->body);
|
||||
free(target->lambda);
|
||||
free(target->lambda->params.docString);
|
||||
free(target->lambda);
|
||||
}
|
||||
break;
|
||||
case TYPE_STRUCT:
|
||||
|
|
|
@ -89,7 +89,7 @@ struct Object {
|
|||
Type type;
|
||||
|
||||
union {
|
||||
int number;
|
||||
long number;
|
||||
Object* list;
|
||||
char* string;
|
||||
|
||||
|
@ -104,6 +104,7 @@ struct Object {
|
|||
#else
|
||||
struct Error* error;
|
||||
#endif
|
||||
void* data;
|
||||
};
|
||||
|
||||
union {
|
||||
|
|
|
@ -184,7 +184,7 @@ Object funcyEval(Object* funcy, const Object* passedArguments, int evalLength,
|
|||
struct Environment* env)
|
||||
{
|
||||
if (!funcy) {
|
||||
eprintf("HIGHLY ILLEGAL NULL FUNCY!!!\n");
|
||||
eprintf("HIGHLY ILLEGAL NULL FUNC-LIKE!!!\n");
|
||||
return errorObject(BAD_TYPE);
|
||||
}
|
||||
switch (funcy->type) {
|
||||
|
@ -193,7 +193,7 @@ Object funcyEval(Object* funcy, const Object* passedArguments, int evalLength,
|
|||
case TYPE_FUNC:
|
||||
return listEvalFunc(funcy, passedArguments, evalLength, env);
|
||||
default:
|
||||
eprintf("HIGHLY ILLEGAL NOT-FUNCY IN funcyEval()!!!\n");
|
||||
eprintf("HIGHLY ILLEGAL NOT-FUNC IN funcyEval()!!!\n");
|
||||
return errorObject(BAD_TYPE);
|
||||
}
|
||||
}
|
||||
|
@ -229,8 +229,9 @@ Object evalList(const Object* obj, struct Environment* env)
|
|||
Object* doc = NULL;
|
||||
Object* body = NULL;
|
||||
if (params) {
|
||||
doc = params->forward && params->forward->forward ? params->forward : NULL;
|
||||
body = doc ? params->forward->forward : params->forward;
|
||||
int twoParams = params->forward && params->forward->forward;
|
||||
doc = twoParams ? params->forward : NULL;
|
||||
body = twoParams ? params->forward->forward : params->forward;
|
||||
}
|
||||
return constructLambda(params, doc, body, env);
|
||||
} else if (strcmp(first_form->string, "struct") == 0) {
|
||||
|
|
Loading…
Reference in New Issue