From aa41f26a26fcff212ecc55750a4806d83a6cf5dc Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Sat, 18 Sep 2021 11:10:11 -0700 Subject: Chapter 19.4 - 19.5 --- clox/src/table.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 clox/src/table.c (limited to 'clox/src/table.c') diff --git a/clox/src/table.c b/clox/src/table.c new file mode 100644 index 0000000..5b6f3f9 --- /dev/null +++ b/clox/src/table.c @@ -0,0 +1,142 @@ +#include +#include + +#include "memory.h" +#include "object.h" +#include "table.h" +#include "value.h" + +#define TABLE_MAX_LOAD 0.75 + +void initTable(Table *table) { + table->count = 0; + table->capacity = 0; + table->entries = NULL; +} + +void freeTable(Table *table) { + FREE_ARRAY(Entry, table->entries, table->capacity); + initTable(table); +} + +static Entry *findEntry(Entry *entries, int capacity, ObjString *key) { + uint32_t index = key->hash % capacity; + Entry *tombstone = NULL; + + for (;;) { + Entry *entry = &entries[index]; + if (entry->key == NULL) { + if (IS_NIL(entry->value)) { + // Empty entry. + return tombstone != NULL ? tombstone : entry; + } else { + // We found a tombstone. + if (tombstone == NULL) + tombstone = entry; + } + } else if (entry->key == key) { + // We found the entry. + return entry; + } + + index = (index + 1) % capacity; + } +} + +bool tableGet(Table *table, ObjString *key, Value *value) { + if (table->count == 0) + return false; + + Entry *entry = findEntry(table->entries, table->capacity, key); + if (entry->key == NULL) + return false; + + *value = entry->value; + return true; +} + +static void adjustCapacity(Table *table, int capacity) { + Entry *entries = ALLOCATE(Entry, capacity); + for (int i = 0; i < capacity; i++) { + entries[i].key = NULL; + entries[i].value = NIL_VAL; + } + + table->count = 0; + for (int i = 0; i < table->capacity; i++) { + Entry *entry = &table->entries[i]; + if (entry->key == NULL) + continue; + + Entry *dest = findEntry(entries, capacity, entry->key); + dest->key = entry->key; + dest->value = entry->value; + table->count++; + } + + FREE_ARRAY(Entry, table->entries, table->capacity); + table->entries = entries; + table->capacity = capacity; +} + +bool tableSet(Table *table, ObjString *key, Value value) { + if (table->count + 1 > table->capacity * TABLE_MAX_LOAD) { + int capacity = GROW_CAPACITY(table->capacity); + adjustCapacity(table, capacity); + } + + Entry *entry = findEntry(table->entries, table->capacity, key); + bool isNewKey = entry->key == NULL; + if (isNewKey && IS_NIL(entry->value)) + table->count++; + + entry->key = key; + entry->value = value; + return isNewKey; +} + +bool tableDelete(Table *table, ObjString *key) { + if (table->count == 0) + return false; + + /* Find the entry. */ + Entry *entry = findEntry(table->entries, table->capacity, key); + if (entry->key == NULL) + return false; + + /* Place a tombstone in the entry. */ + entry->key = NULL; + entry->value = BOOL_VAL(true); + return true; +} + +void tableAddAll(Table *from, Table *to) { + for (int i = 0; i < from->capacity; i++) { + Entry *entry = &from->entries[i]; + if (entry->key != NULL) { + tableSet(to, entry->key, entry->value); + } + } +} + +ObjString *tableFindString(Table *table, const char *chars, int length, + uint32_t hash) { + if (table->count == 0) + return NULL; + + uint32_t index = hash % table->capacity; + for (;;) { + Entry *entry = &table->entries[index]; + if (entry->key == NULL) { + /* Stop if we find an empty non-tombstone entry. */ + if (IS_NIL(entry->value)) + return NULL; + } else if (entry->key->length == length && entry->key->hash == hash && + memcmp(entry->key->chars, chars, length) == 0) { + /* We found it. */ + return entry->key; + } + + index = (index + 1) % table->capacity; + } +} -- cgit v1.2.3-54-g00ecf