from stdint import * import win32.win32console import stdio import stdlib import string import memhub import hashtable import testcheck export def main() -> int: win32.win32console.SetConsoleCP(65001) win32.win32console.SetConsoleOutputCP(65001) testcheck.begin("HashTableTest: 开放寻址哈希表测试") # Allocate the memory arena arena: bytes = stdlib.malloc(65536) bd: memhub.MemBuddy* = memhub.MemBuddy(arena, 65536) # === Test 1: basic insert and lookup === testcheck.section("Test 1: 基本插入和查找 (set_int)") ht: hashtable.HashTable = hashtable.HashTable(bd) ht.set_int("alpha", 10) ht.set_int("beta", 20) ht.set_int("gamma", 30) n: sizet = len(ht) stdio.printf("len=%lu\n", n) testcheck.check(n == 3, "ht len OK (3)", "ht len FAILED") # set_int stores the value as i32; read it back through a typed pointer, since # c.Deref width follows the pointee type and i8* (t.CPtr) always reads 1 byte. p1: t.CPtr = ht["alpha"] v1: int = *(int*)(p1) p2: t.CPtr = ht["beta"] v2: int = *(int*)(p2) p3: t.CPtr = ht["gamma"] v3: int = *(int*)(p3) stdio.printf("alpha=%d beta=%d gamma=%d\n", v1, v2, v3) testcheck.check(v1 == 10, "ht[alpha]==10 OK", "ht[alpha] FAILED") testcheck.check(v2 == 20, "ht[beta]==20 OK", "ht[beta] FAILED") testcheck.check(v3 == 30, "ht[gamma]==30 OK", "ht[gamma] FAILED") # === Test 2: update existing key === testcheck.section("Test 2: 更新已有键") ht.set_int("beta", 99) p2b: t.CPtr = ht["beta"] v2b: int = *(int*)(p2b) stdio.printf("beta(updated)=%d\n", v2b) testcheck.check(v2b == 99, "ht update OK", "ht update FAILED") testcheck.check(len(ht) == 3, "ht len still 3 OK", "ht len changed FAILED") # === Test 3: get with default === testcheck.section("Test 3: get with default") gv: t.CPtr = ht.get("missing", None) testcheck.check(gv == None, "ht get missing OK (None)", "ht get missing FAILED") gp: t.CPtr = ht.get("alpha", None) ga: int = *(int*)(gp) stdio.printf("get(alpha)=%d\n", ga) testcheck.check(ga == 10, "ht get existing OK", "ht get existing FAILED") # === Test 4: contains === testcheck.section("Test 4: contains (in)") has_alpha: int = "alpha" in ht has_missing: int = "missing" in ht stdio.printf("contains(alpha)=%d contains(missing)=%d\n", has_alpha, has_missing) testcheck.check(has_alpha == 1, "contains alpha OK", "contains alpha FAILED") testcheck.check(has_missing == 0, "not contains missing OK", "contains missing FAILED") # === Test 5: delete === testcheck.section("Test 5: 删除 (del)") deleted: int = ht.__delitem__("beta") stdio.printf("del beta=%d\n", deleted) testcheck.check(deleted == 1, "del beta OK", "del beta FAILED") testcheck.check(len(ht) == 2, "ht len 2 after del OK", "ht len after del FAILED") has_beta: int = "beta" in ht testcheck.check(has_beta == 0, "beta gone OK", "beta still exists FAILED") # Delete a nonexistent key del_missing: int = ht.__delitem__("nokey") testcheck.check(del_missing == 0, "del missing returns 0 OK", "del missing FAILED") # === Test 6: re-insert after delete === testcheck.section("Test 6: 删除后重新插入") ht.set_int("beta", 555) p2c: t.CPtr = ht["beta"] v2c: int = *(int*)(p2c) stdio.printf("beta(re-inserted)=%d\n", v2c) testcheck.check(v2c == 555, "ht re-insert beta OK", "ht re-insert beta FAILED") testcheck.check(len(ht) == 3, "ht len 3 after re-insert OK", "ht len after re-insert FAILED") # === Test 7: iterator === testcheck.section("Test 7: 迭代器 for key in ht") iter_count: int = 0 for key in ht: kp: t.CPtr = ht[key] val: int = *(int*)(kp) stdio.printf("ht[%s]=%d\n", key, val) iter_count += 1 testcheck.check(iter_count == 3, "ht iter OK (3)", "ht iter FAILED") # === Test 8: string values === testcheck.section("Test 8: 字符串值 (set_str)") ht2: hashtable.HashTable = hashtable.HashTable(bd) ht2.set_str("name", "Alice") ht2.set_str("city", "Beijing") ht2.set_str("lang", "TransPyC") n2: sizet = len(ht2) stdio.printf("ht2 len=%lu\n", n2) testcheck.check(n2 == 3, "ht set_str len OK (3)", "ht set_str len FAILED") name_p: t.CPtr = ht2["name"] city_p: t.CPtr = ht2["city"] lang_p: t.CPtr = ht2["lang"] name: str = name_p city: str = city_p lang: str = lang_p stdio.printf("name=%s city=%s lang=%s\n", name, city, lang) # i8* == compares pointer addresses (C-like); use strcmp for content testcheck.check(string.strcmp(name, "Alice") == 0, "ht str name OK", "ht str name FAILED") testcheck.check(string.strcmp(city, "Beijing") == 0, "ht str city OK", "ht str city FAILED") testcheck.check(string.strcmp(lang, "TransPyC") == 0, "ht str lang OK", "ht str lang FAILED") # === Test 9: expansion test === testcheck.section("Test 9: 扩容测试 (>16 个元素)") ht3: hashtable.HashTable = hashtable.HashTable(bd) for i in range(50): key_buf: str = stdlib.malloc(16) stdio.sprintf(key_buf, "key%d", i) ht3.set_int(key_buf, i * 100) n3: sizet = len(ht3) stdio.printf("ht3 len=%lu (after 50 inserts)\n", n3) testcheck.check(n3 == 50, "ht expand OK (50)", "ht expand FAILED") # Verify some values k5: str = stdlib.malloc(16) stdio.sprintf(k5, "key5") p5: t.CPtr = ht3[k5] v5: int = *(int*)(p5) stdio.printf("ht3[key5]=%d\n", v5) testcheck.check(v5 == 500, "ht expand key5 OK", "ht expand key5 FAILED") k25: str = stdlib.malloc(16) stdio.sprintf(k25, "key25") p25: t.CPtr = ht3[k25] v25: int = *(int*)(p25) stdio.printf("ht3[key25]=%d\n", v25) testcheck.check(v25 == 2500, "ht expand key25 OK", "ht expand key25 FAILED") k49: str = stdlib.malloc(16) stdio.sprintf(k49, "key49") p49: t.CPtr = ht3[k49] v49: int = *(int*)(p49) stdio.printf("ht3[key49]=%d\n", v49) testcheck.check(v49 == 4900, "ht expand key49 OK", "ht expand key49 FAILED") # === Test 10: iterate after expansion === testcheck.section("Test 10: 扩容后迭代") iter_count3: int = 0 for k in ht3: iter_count3 += 1 stdio.printf("ht3 iter count=%d\n", iter_count3) testcheck.check(iter_count3 == 50, "ht expand iter OK (50)", "ht expand iter FAILED") # === Test 11: operations after batch delete === testcheck.section("Test 11: 批量删除后操作") for j in range(25): del_buf: str = stdlib.malloc(16) stdio.sprintf(del_buf, "key%d", j) del ht3[del_buf] n3b: sizet = len(ht3) stdio.printf("ht3 len=%lu (after 25 deletes)\n", n3b) testcheck.check(n3b == 25, "ht after del OK (25)", "ht after del FAILED") # Verify remaining values k30: str = stdlib.malloc(16) stdio.sprintf(k30, "key30") p30: t.CPtr = ht3[k30] v30: int = *(int*)(p30) stdio.printf("ht3[key30]=%d\n", v30) testcheck.check(v30 == 3000, "ht key30 after del OK", "ht key30 after del FAILED") # Verify the deleted key is gone k0: str = stdlib.malloc(16) stdio.sprintf(k0, "key0") has_k0: int = k0 in ht3 testcheck.check(has_k0 == 0, "ht key0 deleted OK", "ht key0 still exists FAILED") # === Test 12: empty table operations === testcheck.section("Test 12: 空表操作") ht4: hashtable.HashTable = hashtable.HashTable(bd) testcheck.check(len(ht4) == 0, "empty ht len 0 OK", "empty ht len FAILED") empty_get: t.CPtr = ht4.get("none", None) testcheck.check(empty_get == None, "empty ht get OK", "empty ht get FAILED") has_none: int = "none" in ht4 testcheck.check(has_none == 0, "empty ht contains OK", "empty ht contains FAILED") empty_iter: int = 0 for ek in ht4: empty_iter += 1 testcheck.check(empty_iter == 0, "empty ht iter OK (0)", "empty ht iter FAILED") stdlib.free(arena) return testcheck.end()