延續 Day 12 的 mongory_array
,筆者今天帶讀者把 mongory_table
的設計一次講清楚:bucket 與雜湊、碰撞(separate chaining)如何處理、何時 rehash、以及對外 API(get/set/del/each_pair
)與慣用的 keys
輔助
mongory_value*
)的雜湊表hash = hash*33 + c
)對應 hash_string
mongory_array
(直接復用自己的東西)hash(key) % capacity
對 key 算出 hash 值後對 bucket 的數量(capacity)取餘數,以確定不會超出 bucket lengthmongory_table_node*
的 linked nodesset
):
value
mongory_string_cpy
複製一份進 pool,避免外部字串生命週期問題get
):沿 bucket 串列比對字串,命中即回傳值,否則 NULL
del
):沿 bucket 串列步進,從鏈上移除節點(頭節點或中間)count > capacity * 0.75
時觸發next_prime(capacity * 2)
找出下一個質數,以計算新容量mongory_array_resize
擴容,節點記憶體不搬家,只改鏈結pool->error
,表仍可運作,但效能可能退化(維持高 load factor)mongory_table_new(pool)
:建立表,內部建立 bucket 陣列並填 NULL
table->set(table, key, value)
:新增或更新table->get(table, key)
:查詢,未命中回 NULL
table->del(table, key)
:刪除,回傳是否成功table->each(table, acc, callback)
:逐對(key, value)走訪,callback(key, value, acc)
,回傳 false
可提前終止mongory_table_merge(table, other)
:以 other 的鍵值覆寫/補齊 table插入、查詢、刪除與列舉:
#include <mongory-core/foundations/memory_pool.h>
#include <mongory-core/foundations/table.h>
#include <mongory-core/foundations/value.h>
#include <stdio.h>
static bool print_pair(char *key, mongory_value *value, void *acc) {
mongory_memory_pool *pool = (mongory_memory_pool *)acc;
char *vs = value->to_str(value, pool);
printf("%s => %s\n", key, vs);
return true;
}
int main() {
mongory_init();
mongory_memory_pool *pool = mongory_memory_pool_new();
mongory_table *t = mongory_table_new(pool);
t->set(t, "name", mongory_value_wrap_str(pool, "Jack"));
t->set(t, "age", mongory_value_wrap_int(pool, 18));
t->set(t, "score", mongory_value_wrap_int(pool, 90));
// 更新
t->set(t, "score", mongory_value_wrap_int(pool, 95));
// 查詢
mongory_value *age = t->get(t, "age");
printf("age=%lld\n", age->data.i64);
// 列舉
t->each(t, pool, print_pair);
// 刪除
t->del(t, "name");
mongory_memory_pool_free(pool);
mongory_cleanup();
return 0;
}
set
會複製 key 到 pool,外部修改原字串不影響表內 keypool_free
時一次回收table->each
走訪即可輸出(例如轉 JSON)mongory_value->to_str
可協助把值轉可讀字串get/set/del
為 O(1),最壞落到 O(n)(單 bucket 長鏈)pool->error
被寫入mongory_table
以簡潔穩健的策略處理碰撞與擴容,並與記憶體池天然貼合,讓上層 Matchers(特別是 Field
與條件文件解析)可以無痛地依 key 存取