pebblisp/src/hash.c

197 lines
5.3 KiB
C
Raw Normal View History

#include "hash.h"
#include "env.h"
#include <string.h>
2022-04-18 16:59:29 -04:00
#include <stdio.h>
size_t 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 = {
.count = 0,
.capacity = capacity,
.elements = capacity ? malloc(sizeof(struct EnvElement) * capacity) : NULL,
};
for (int i = 0; i < table.capacity; i++) {
table.elements[i].symbol = NULL;
}
return table;
}
2022-04-06 20:12:26 -04:00
void deleteTable(struct ObjectTable* table)
{
for (int i = 0; i < table->capacity; i++) {
if (table->elements[i].symbol) {
free(table->elements[i].symbol);
Object deStripped = deStrip(table->elements[i].object);
cleanObject(&deStripped);
2022-04-06 20:12:26 -04:00
}
}
free(table->elements);
}
#ifndef HASHLESS_ENV
static size_t hash(const char* str, struct ObjectTable* table)
2022-04-06 20:12:26 -04:00
{
size_t hash = 5381;
char c;
2022-04-06 20:12:26 -04:00
while ((c = *str++)) {
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
}
return hash;
2022-04-06 20:12:26 -04:00
}
void extendTable(struct ObjectTable* table)
{
if (table->capacity >= (table->count + 1) * 2) {
return;
}
struct ObjectTable newTable = buildTable(table->capacity ? table->capacity * 2 : 4);
for (int i = 0; i < table->capacity; i++) {
if (table->elements[i].symbol) {
addStripped(&newTable, table->elements[i].symbol, table->elements[i].object);
}
}
free(table->elements);
*table = newTable;
}
struct StrippedObject* getFromTable(struct ObjectTable* table, const char* name)
{
if (table->capacity == 0) {
return NULL;
}
size_t h = hash(name, table) % table->capacity;
2022-04-06 20:12:26 -04:00
while (table->elements[h].symbol) {
if (strcmp(name, table->elements[h].symbol) == 0) {
return &table->elements[h].object;
}
h = (h + 1) % table->capacity;
}
return NULL;
}
2022-04-06 20:12:26 -04:00
#else
void extendTable(struct ObjectTable* table)
{
2022-04-06 20:12:26 -04:00
if (table->count == (table->capacity - 1)) {
struct EnvElement* oldElements = table->elements;
size_t oldCapacity = table->capacity;
table->capacity *= 2;
table->elements = malloc(sizeof(struct EnvElement) * table->capacity);
for (int i = 0; i < oldCapacity; i++) {
table->elements[i] = oldElements[i];
}
for (size_t i = oldCapacity; i < table->capacity; i++) {
table->elements[i].symbol = NULL;
}
free(oldElements);
}
2022-04-06 20:12:26 -04:00
}
struct StrippedObject* getFromTable(struct ObjectTable* table, const char* name)
2022-04-06 20:12:26 -04:00
{
for (size_t i = 0; i < table->count; i++) {
if (strcmp(name, table->elements[i].symbol) == 0) {
return &table->elements[i].object;
}
}
return NULL;
}
static size_t hash(unused const char* str, struct ObjectTable* table)
2022-04-06 20:12:26 -04:00
{
return table->count;
}
#endif
size_t addStripped(struct ObjectTable* table, char* name, struct StrippedObject object)
2022-04-06 20:12:26 -04:00
{
extendTable(table);
size_t initial = hash(name, table);
size_t h = initial % table->capacity;
2022-04-06 20:12:26 -04:00
while (table->elements[h].symbol) {
h = (h + 1) % table->capacity;
}
//eprintf("adding at %ld: `%s`\n", h, name);
2022-04-06 20:12:26 -04:00
table->elements[h].symbol = name;
table->elements[h].object = object;
table->count += 1;
return initial;
2022-04-06 20:12:26 -04:00
}
///
/// \param table
/// \param name Should be a new allocation
/// \param object Should already be cloned
size_t addToTable(struct ObjectTable* table, char* name, Object object)
{
return addStripped(table, name, (struct StrippedObject) {
.data = object.data,
.type = object.type,
});
}
2022-04-18 16:59:29 -04:00
#ifdef STANDALONE
Object buildHashTable(Object* params, int length, struct Environment* env)
{
long capacity = 16;
if (length > 0 && params[0].type == TYPE_NUMBER) {
capacity = params[0].number;
}
Object table = newObject(TYPE_HASH_TABLE);
table.table = malloc(sizeof(struct ObjectTableObject));
table.table->table = buildTable(capacity);
table.table->refs = 1;
2022-04-18 16:59:29 -04:00
return table;
}
Object addToHashTable(Object* params, int length, struct Environment* env)
{
Object table = params[0];
Object name = params[1];
Object add = params[2];
//eprintf("Adding `%s`\n", table.string);
//eprintf("Adding `%s`\n", strdup(name.string));
addToTable(&table.table->table, strdup(name.string), cloneObject(add));
2022-04-18 16:59:29 -04:00
return numberObject(0);
}
Object getFromHashTable(Object* params, int length, struct Environment* env)
{
//eprintf("getFromHashTable()\n");
2022-04-18 16:59:29 -04:00
struct ObjectTable* table = &params[0].table->table;
//eprintf("*table = %p\n", table);
//eprintf("*table->capacity = %d\n", table->capacity);
2022-04-18 16:59:29 -04:00
for (int i = 0; i < table->capacity; i++) {
//eprintf("for i = %d\n", i);
//eprintf("[%d] %s\n", i, table->elements[i].symbol);
2022-04-18 16:59:29 -04:00
}
struct StrippedObject* fetched = getFromTable(&params[0].table->table, params[1].string);
if (fetched) {
return deStrip(*fetched);
}
throw(DID_NOT_FIND_SYMBOL, "Hash table does not contain %s", params[1].string);
}
#endif