| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- /**
- ******************************************************************************
- * @file : table.c
- * @author : simon
- * @brief : None
- * @attention : None
- * @date : 2023/8/24
- ******************************************************************************
- */
- #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);
- }
- /// 查找位置,hash 冲突使用 线性探测(Linear probing) 策略
- /// \param entries
- /// \param capacity
- /// \param key
- /// \return 应该设置的位置
- 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 key.
- return entry;
- }
- index = (index + 1) % capacity;
- }
- }
- /// Allocating and resizing
- /// \param table
- /// \param capacity
- 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;
- }
- // 原来的 entry 重新放置到新位置
- table->count = 0;
- for (int i = 0; i < table->capacity; i++) {
- Entry *src = &table->entries[i];
- if (src->key == NULL) continue;
- Entry *dest = findEntry(entries, capacity, src->key);
- dest->key = src->key;
- dest->value = src->value;
- table->count++;
- }
- FREE_ARRAY(Entry, table->entries, table->capacity);
- table->entries = entries;
- table->capacity = capacity;
- }
- bool tableGet(Table *table, ObjString *key, Value *value) {
- // the table is completely empty
- 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;
- }
- bool tableSet(Table *table, ObjString *key, Value value) {
- // 容量少于75% 就开始扩容
- 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;
- }
- return NULL;
- }
- void markTable(Table *table) {
- for (int i = 0; i < table->capacity; i++) {
- Entry *entry = &table->entries[i];
- markObject((Obj *) entry->key);
- markValue(entry->value);
- }
- }
- void tableRemoveWhite(Table *table) {
- for (int i = 0; i < table->capacity; i++) {
- Entry *entry = &table->entries[i];
- if (entry->key != NULL && !entry->key->obj.isMarked) {
- tableDelete(table, entry->key);
- }
- }
- }
|