這一篇承接 Day 11 的 mongory_value
,筆者帶讀者走一遍 C core 裡的動態陣列 mongory_array
:為什麼長這樣、怎麼用、有哪些邊界與測試重點
整體 API 以 Ruby 習慣為靈感:push/get/set/each/sort_by/includes
,同時確保擴容策略簡潔、可觀測、易於與 Matcher 串接。
pool->error
,便於測試/回報。mongory_value
深度整合:比對/字串化皆走一致入口。mongory_array_new(pool)
:建立新陣列(初始容量 4)。array->push(array, value)
:尾端加入元素;自動擴容(倍增)。array->get(array, index)
:取得元素;越界回傳 NULL
。array->set(array, index, value)
:設定元素;若跨越目前長度,會用 NULL
補齊中間空洞並更新 count
。array->each(array, acc, callback)
:逐一走訪;callback(item, acc)
回傳 false
可提前停止。mongory_array_sort_by(array, temp_pool, ctx, callback)
:依 key 排序,回傳新陣列;callback(value, ctx) -> size_t key
。mongory_array_includes(array, value)
:是否包含;比較走 mongory_value->comp
。對照 Ruby:
arr.push(x)
→ C array->push(array, x)
arr[i]
→ C array->get(array, i)
;Ruby arr[i] = x
→ C array->set(array, i, x)
arr.each { |x| }
→ C array->each(array, acc, cb)
arr.sort_by { |x| key }
→ C mongory_array_sort_by(array, tmp, ctx, cb)
以下展示 push/get/each/sort_by 的基本用法(以整數為例):
#include <mongory-core/foundations/memory_pool.h>
#include <mongory-core/foundations/array.h>
#include <mongory-core/foundations/value.h>
#include <stdio.h>
static bool print_item(mongory_value *item, void *acc) {
mongory_memory_pool *pool = (mongory_memory_pool *)acc;
char *s = item->to_str(item, pool);
printf("%s\n", s);
return true;
}
static size_t key_of(mongory_value *item, void *ctx) {
// 以整數值作為排序 key(小到大)
(void)ctx;
return (size_t)item->data.i64;
}
int main() {
mongory_init();
mongory_memory_pool *pool = mongory_memory_pool_new();
mongory_array *array = mongory_array_new(pool);
array->push(array, mongory_value_wrap_int(pool, 3));
array->push(array, mongory_value_wrap_int(pool, 1));
array->push(array, mongory_value_wrap_int(pool, 2));
// get / set
mongory_value *v1 = array->get(array, 1); // 1
printf("get[1]=%lld\n", v1->data.i64);
array->set(array, 5, mongory_value_wrap_int(pool, 9)); // 自動補 NULL,count 變為 6
// each(列印)
array->each(array, pool, print_item);
// sort_by(回傳新陣列,不就地排序)
mongory_array *sorted = mongory_array_sort_by(array, pool, NULL, key_of);
printf("-- sorted --\n");
sorted->each(sorted, pool, print_item);
mongory_memory_pool_free(pool);
mongory_cleanup();
return 0;
}
push
攤銷 O(1),擴容發生時計 O(n) 搬移指標。set
若直接跳到遠端索引,會補 NULL
形成「洞洞」;count
會被推進到 index+1
。get
越界回 NULL
;呼叫端需判斷。set
造成的 NULL
空洞會影響部分操作:
includes
內部直接取出元素後呼叫 item->comp
;若該位置為 NULL
將不安全。建議在有空洞情境先避免 includes
,或先以實值補齊。each
會把 NULL
交給回呼;回呼需自保(可檢查 item == NULL
)。sort_by
使用合併排序實作,會在 temp_pool
產生中介陣列;是否穩定排序取決於 callback 與實作,不保證穩定。pool->error
(集中回報)。$every
、$elemMatch
等操作會頻繁走 array->each
;以「方法掛在物件」的風格,可讀性更接近 Ruby。get/set
的語意需簡單直覺、邊界明確。sort_by
與 includes
可支援測試/診斷用例(例如 explain/trace 的輸出排序一致性)。new
後容量/計數與函式指標皆正確。get
回 NULL
;跨距 set
形成空洞,count
正確。false
可提前停止;能處理 NULL
。temp_pool
釋放後不影響原陣列。pool->error
被寫入。mongory_array
提供 Ruby 風 API 與可預期的擴容行為,讓上層 Matchers(特別是 $every/$elemMatch
)易於組合與觀測。Table
(雜湊、碰撞與 rehash 取捨),完成基礎容器三件組(Value/Array/Table)。