Initial commit
This commit is contained in:
commit
b2edca2cb4
25 changed files with 3590 additions and 0 deletions
173
table.c
Normal file
173
table.c
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
#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 = nullptr;
|
||||
}
|
||||
|
||||
void freeTable(Table* table)
|
||||
{
|
||||
FREE_ARRAY(Entry, table->entries, table->capacity);
|
||||
initTable(table);
|
||||
}
|
||||
|
||||
static Entry* findEntry(Entry* entries, int capacity, ObjString* key)
|
||||
{
|
||||
auto index = key->hash & (capacity - 1);
|
||||
Entry* tombstone = nullptr;
|
||||
|
||||
for (;;) {
|
||||
Entry* entry = &entries[index];
|
||||
if (entry->key == nullptr) {
|
||||
if (IS_NIL(entry->value)) {
|
||||
return tombstone != nullptr ? tombstone : entry;
|
||||
} else {
|
||||
if (tombstone == nullptr) {
|
||||
tombstone = entry;
|
||||
}
|
||||
}
|
||||
} else if (entry->key == key) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
index = (index + 1) & (capacity - 1);
|
||||
}
|
||||
}
|
||||
|
||||
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 == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*value = entry->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void adjustCapacity(Table* table, int capacity)
|
||||
{
|
||||
Entry* entries = ALLOCATE(Entry, capacity);
|
||||
for (auto i = 0; i < capacity; i++) {
|
||||
entries[i].key = nullptr;
|
||||
entries[i].value = NIL_VAL;
|
||||
}
|
||||
|
||||
table->count = 0;
|
||||
for (auto i = 0; i < table->capacity; i++) {
|
||||
Entry* entry = &table->entries[i];
|
||||
if (entry->key == nullptr) {
|
||||
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) {
|
||||
auto capacity = GROW_CAPACITY(table->capacity);
|
||||
adjustCapacity(table, capacity);
|
||||
}
|
||||
|
||||
Entry* entry = findEntry(table->entries, table->capacity, key);
|
||||
auto isNewKey = entry->key == nullptr;
|
||||
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;
|
||||
}
|
||||
|
||||
Entry* entry = findEntry(table->entries, table->capacity, key);
|
||||
if (entry->key == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
entry->key = nullptr;
|
||||
entry->value = BOOL_VAL(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void tableAddAll(Table* from, Table* to)
|
||||
{
|
||||
for (auto i = 0; i < from->capacity; i++) {
|
||||
Entry* entry = &from->entries[i];
|
||||
if (entry->key != nullptr) {
|
||||
tableSet(to, entry->key, entry->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ObjString* tableFindString(Table* table, const char* chars, int length, uint32_t hash)
|
||||
{
|
||||
if (table->count == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto index = hash & (table->capacity - 1);
|
||||
for (;;) {
|
||||
Entry* entry = &table->entries[index];
|
||||
if (entry->key == nullptr) {
|
||||
if (IS_NIL(entry->value)) {
|
||||
return nullptr;
|
||||
}
|
||||
} else if (entry->key->length == length && entry->key->hash == hash && memcmp(entry->key->chars, chars, length) == 0) {
|
||||
return entry->key;
|
||||
}
|
||||
|
||||
index = (index + 1) & (table->capacity - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void tableRemoveWhite(Table* table)
|
||||
{
|
||||
for (auto i = 0; i < table->capacity; i++) {
|
||||
Entry* entry = &table->entries[i];
|
||||
if (entry->key != nullptr && !entry->key->obj.isMarked) {
|
||||
tableDelete(table, entry->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void markTable(Table* table)
|
||||
{
|
||||
for (auto i = 0; i < table->capacity; i++) {
|
||||
Entry* entry = &table->entries[i];
|
||||
markObject((Obj*)entry->key);
|
||||
markValue(entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue