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))
|
#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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
38
src/hash.c
38
src/hash.c
|
@ -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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue