table.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /**
  2. ******************************************************************************
  3. * @file : table.c
  4. * @author : simon
  5. * @brief : None
  6. * @attention : None
  7. * @date : 2023/8/24
  8. ******************************************************************************
  9. */
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include "memory.h"
  13. #include "object.h"
  14. #include "table.h"
  15. #include "value.h"
  16. #define TABLE_MAX_LOAD 0.75
  17. void initTable(Table *table) {
  18. table->count = 0;
  19. table->capacity = 0;
  20. table->entries = NULL;
  21. }
  22. void freeTable(Table *table) {
  23. FREE_ARRAY(Entry, table->entries, table->capacity);
  24. initTable(table);
  25. }
  26. /// 查找位置,hash 冲突使用 线性探测(Linear probing) 策略
  27. /// \param entries
  28. /// \param capacity
  29. /// \param key
  30. /// \return 应该设置的位置
  31. static Entry *findEntry(Entry *entries, int capacity, ObjString *key) {
  32. uint32_t index = key->hash % capacity;
  33. Entry *tombstone = NULL;
  34. for (;;) {
  35. Entry *entry = &entries[index];
  36. if (entry->key == NULL) {
  37. if (IS_NIL(entry->value)) {
  38. // Empty entry.
  39. return tombstone != NULL ? tombstone : entry;
  40. } else {
  41. // We found a tombstone.
  42. if (tombstone == NULL) tombstone = entry;
  43. }
  44. } else if (entry->key == key) {
  45. // We found the key.
  46. return entry;
  47. }
  48. index = (index + 1) % capacity;
  49. }
  50. }
  51. /// Allocating and resizing
  52. /// \param table
  53. /// \param capacity
  54. void adjustCapacity(Table *table, int capacity) {
  55. Entry *entries = ALLOCATE(Entry, capacity);
  56. for (int i = 0; i < capacity; i++) {
  57. entries[i].key = NULL;
  58. entries[i].value = NIL_VAL;
  59. }
  60. // 原来的 entry 重新放置到新位置
  61. table->count = 0;
  62. for (int i = 0; i < table->capacity; i++) {
  63. Entry *src = &table->entries[i];
  64. if (src->key == NULL) continue;
  65. Entry *dest = findEntry(entries, capacity, src->key);
  66. dest->key = src->key;
  67. dest->value = src->value;
  68. table->count++;
  69. }
  70. FREE_ARRAY(Entry, table->entries, table->capacity);
  71. table->entries = entries;
  72. table->capacity = capacity;
  73. }
  74. bool tableGet(Table *table, ObjString *key, Value *value) {
  75. // the table is completely empty
  76. if (table->count == 0) return false;
  77. Entry *entry = findEntry(table->entries, table->capacity, key);
  78. if (entry->key == NULL) return false;
  79. *value = entry->value;
  80. return true;
  81. }
  82. bool tableSet(Table *table, ObjString *key, Value value) {
  83. // 容量少于75% 就开始扩容
  84. if (table->count + 1 > table->capacity * TABLE_MAX_LOAD) {
  85. int capacity = GROW_CAPACITY(table->capacity);
  86. adjustCapacity(table, capacity);
  87. }
  88. Entry *entry = findEntry(table->entries, table->capacity, key);
  89. bool isNewKey = entry->key == NULL;
  90. if (isNewKey && IS_NIL(entry->value)) table->count++;
  91. entry->key = key;
  92. entry->value = value;
  93. return isNewKey;
  94. }
  95. bool tableDelete(Table *table, ObjString *key) {
  96. if (table->count == 0) return false;
  97. // Find the entry
  98. Entry *entry = findEntry(table->entries, table->capacity, key);
  99. if (entry->key == NULL) return false;
  100. // Place a tombstone in the entry.
  101. entry->key = NULL;
  102. entry->value = BOOL_VAL(true);
  103. return true;
  104. }
  105. void tableAddAll(Table *from, Table *to) {
  106. for (int i = 0; i < from->capacity; i++) {
  107. Entry *entry = &from->entries[i];
  108. if (entry->key != NULL) {
  109. tableSet(to, entry->key, entry->value);
  110. }
  111. }
  112. }
  113. ObjString *tableFindString(Table *table, const char *chars, int length, uint32_t hash) {
  114. if (table->count == 0) return NULL;
  115. uint32_t index = hash % table->capacity;
  116. for (;;) {
  117. Entry *entry = &table->entries[index];
  118. if (entry->key == NULL) {
  119. // Stop if we find an empty non-tombstone entry.
  120. if (IS_NIL(entry->value)) return NULL;
  121. } else if (entry->key->length == length && entry->key->hash == hash
  122. && memcmp(entry->key->chars, chars, length) == 0) {
  123. // We found it.
  124. return entry->key;
  125. }
  126. index = (index + 1) % table->capacity;
  127. }
  128. return NULL;
  129. }