aboutsummaryrefslogtreecommitdiffstats
path: root/clox/src
diff options
context:
space:
mode:
authorGravatar Tom Willemse2021-09-18 11:10:11 -0700
committerGravatar Tom Willemse2021-09-18 11:10:11 -0700
commitaa41f26a26fcff212ecc55750a4806d83a6cf5dc (patch)
tree77238d0c1e8dfb90a04c2528b20484ddfab8e29c /clox/src
parent8ec913756107cc8e6aee965d0dc080039d4995ad (diff)
downloadcrafting-interpreters-aa41f26a26fcff212ecc55750a4806d83a6cf5dc.tar.gz
crafting-interpreters-aa41f26a26fcff212ecc55750a4806d83a6cf5dc.zip
Chapter 19.4 - 19.5
Diffstat (limited to 'clox/src')
-rw-r--r--clox/src/CMakeLists.txt2
-rw-r--r--clox/src/object.c30
-rw-r--r--clox/src/object.h1
-rw-r--r--clox/src/table.c142
-rw-r--r--clox/src/table.h27
-rw-r--r--clox/src/value.c5
-rw-r--r--clox/src/vm.c6
-rw-r--r--clox/src/vm.h2
8 files changed, 207 insertions, 8 deletions
diff --git a/clox/src/CMakeLists.txt b/clox/src/CMakeLists.txt
index 0deeb6a..edee2cc 100644
--- a/clox/src/CMakeLists.txt
+++ b/clox/src/CMakeLists.txt
@@ -16,6 +16,8 @@ add_executable(Lox
scanner.c
object.h
object.c
+ table.h
+ table.c
main.c)
install(TARGETS Lox)
diff --git a/clox/src/object.c b/clox/src/object.c
index 9622327..361e315 100644
--- a/clox/src/object.c
+++ b/clox/src/object.c
@@ -3,6 +3,7 @@
#include "memory.h"
#include "object.h"
+#include "table.h"
#include "value.h"
#include "vm.h"
@@ -18,22 +19,45 @@ static Obj *allocateObject(size_t size, ObjType type) {
return object;
}
-static ObjString *allocateString(char *chars, int length) {
+static ObjString *allocateString(char *chars, int length, uint32_t hash) {
ObjString *string = ALLOCATE_OBJ(ObjString, OBJ_STRING);
string->length = length;
string->chars = chars;
+ string->hash = hash;
+ tableSet(&vm.strings, string, NIL_VAL);
return string;
}
+static uint32_t hashString(const char *key, int length) {
+ uint32_t hash = 2166136261u;
+ for (int i = 0; i < length; i++) {
+ hash ^= (uint32_t)key[i];
+ hash *= 16777619;
+ }
+ return hash;
+}
+
ObjString *takeString(char *chars, int length) {
- return allocateString(chars, length);
+ uint32_t hash = hashString(chars, length);
+ ObjString *interned = tableFindString(&vm.strings, chars, length, hash);
+ if (interned != NULL) {
+ FREE_ARRAY(char, chars, length + 1);
+ return interned;
+ }
+
+ return allocateString(chars, length, hash);
}
ObjString *copyString(const char *chars, int length) {
+ uint32_t hash = hashString(chars, length);
+ ObjString *interned = tableFindString(&vm.strings, chars, length, hash);
+ if (interned != NULL)
+ return interned;
+
char *heapChars = ALLOCATE(char, length + 1);
memcpy(heapChars, chars, length);
heapChars[length] = '\0';
- return allocateString(heapChars, length);
+ return allocateString(heapChars, length, hash);
}
void printObject(Value value) {
diff --git a/clox/src/object.h b/clox/src/object.h
index 965b905..717031b 100644
--- a/clox/src/object.h
+++ b/clox/src/object.h
@@ -24,6 +24,7 @@ struct ObjString {
Obj obj;
int length;
char *chars;
+ uint32_t hash;
};
ObjString *takeString(char *chars, int length);
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 <stdlib.h>
+#include <string.h>
+
+#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;
+ }
+}
diff --git a/clox/src/table.h b/clox/src/table.h
new file mode 100644
index 0000000..b4c3271
--- /dev/null
+++ b/clox/src/table.h
@@ -0,0 +1,27 @@
+#ifndef TABLE_H
+#define TABLE_H
+
+#include "common.h"
+#include "value.h"
+
+typedef struct {
+ ObjString *key;
+ Value value;
+} Entry;
+
+typedef struct {
+ int count;
+ int capacity;
+ Entry *entries;
+} Table;
+
+void initTable(Table *table);
+void freeTable(Table *table);
+bool tableGet(Table *table, ObjString *key, Value *value);
+bool tableSet(Table *table, ObjString *key, Value value);
+bool tableDelete(Table *table, ObjString *key);
+void tableAddAll(Table *from, Table *to);
+ObjString *tableFindString(Table *talbe, const char *chars, int length,
+ uint32_t hash);
+
+#endif
diff --git a/clox/src/value.c b/clox/src/value.c
index a5f8540..28d1c9f 100644
--- a/clox/src/value.c
+++ b/clox/src/value.c
@@ -56,10 +56,7 @@ bool valuesEqual(Value a, Value b) {
case VAL_NUMBER:
return AS_NUMBER(a) == AS_NUMBER(b);
case VAL_OBJ: {
- ObjString *aString = AS_STRING(a);
- ObjString *bString = AS_STRING(b);
- return aString->length == bString->length &&
- memcmp(aString->chars, bString->chars, aString->length) == 0;
+ return AS_OBJ(a) == AS_OBJ(b);
}
default:
return false; /* Unreachable */
diff --git a/clox/src/vm.c b/clox/src/vm.c
index d253d67..e35a1e0 100644
--- a/clox/src/vm.c
+++ b/clox/src/vm.c
@@ -29,9 +29,13 @@ static void runtimeError(const char *format, ...) {
void initVM() {
resetStack();
vm.objects = NULL;
+ initTable(&vm.strings);
}
-void freeVM() { freeObjects(); }
+void freeVM() {
+ freeTable(&vm.strings);
+ freeObjects();
+}
void push(Value value) {
*vm.stackTop = value;
diff --git a/clox/src/vm.h b/clox/src/vm.h
index 6c6ada8..f11c1dd 100644
--- a/clox/src/vm.h
+++ b/clox/src/vm.h
@@ -2,6 +2,7 @@
#define clox_vm_h
#include "chunk.h"
+#include "table.h"
#include "value.h"
#define STACK_MAX 256
@@ -11,6 +12,7 @@ typedef struct {
uint8_t *ip;
Value stack[STACK_MAX];
Value *stackTop;
+ Table strings;
Obj *objects;
} VM;