from stdint import *
import t, c
import stdio
import stdlib
import testcheck
import memhub


# 多态测试: 通过 MemManager 基类指针调用, 验证 vtable 分派到正确子类
def test_polymorphic(mgr: memhub.MemManager | t.CPtr, size: t.CSizeT) -> t.CInt:
    p: t.CVoid | t.CPtr = mgr.alloc(size)
    if p is None:
        return 0
    mgr.free(p)
    return 1


# 测试 calloc 多态: calloc 是 MemManager 具体方法, 内部调 self.alloc (虚函数)
def test_calloc_polymorphic(mgr: memhub.MemManager | t.CPtr) -> t.CInt:
    p: t.CVoid | t.CPtr = mgr.calloc(4, 8)
    if p is None:
        return 0
    # 验证清零: 读第一个字节应为 0
    first_byte: t.CUInt8T = t.CUInt8T(c.Deref(t.CUInt64T(p, t.CPtr)))
    if first_byte != 0:
        return 0
    return 1


@t.CExport
def main() -> int:
    testcheck.begin("MemhubTest: polymorphic memory manager")

    arena1: bytes = stdlib.malloc(65536)
    arena2: bytes = stdlib.malloc(65536)
    arena3: bytes = stdlib.malloc(65536)

    # ========== MemPool (bump) ==========
    testcheck.section("MemPool (bump)")
    pool: memhub.MemPool = memhub.MemPool(arena1, 65536)
    p1: t.CVoid | t.CPtr = pool.alloc(100)
    testcheck.check(p1 is not None, "MemPool alloc 100", "FAIL")
    p2: t.CVoid | t.CPtr = pool.alloc(200)
    testcheck.check(p2 is not None, "MemPool alloc 200", "FAIL")
    testcheck.check(t.CUInt64T(p1) != t.CUInt64T(p2), "MemPool different ptrs", "FAIL")
    pool.reset()
    p3: t.CVoid | t.CPtr = pool.alloc(100)
    testcheck.check(p3 is not None, "MemPool alloc after reset", "FAIL")
    testcheck.check(t.CUInt64T(p3) == t.CUInt64T(p1), "MemPool reset reuses addr", "FAIL")

    # ========== MemSlab (fixed block) ==========
    testcheck.section("MemSlab (fixed block)")
    slab: memhub.MemSlab = memhub.MemSlab(arena2, 65536, 64)
    s1: t.CVoid | t.CPtr = slab.alloc(32)
    testcheck.check(s1 is not None, "MemSlab alloc 32", "FAIL")
    s2: t.CVoid | t.CPtr = slab.alloc(64)
    testcheck.check(s2 is not None, "MemSlab alloc 64", "FAIL")
    s3: t.CVoid | t.CPtr = slab.alloc(128)
    testcheck.check(s3 is None, "MemSlab alloc > block_size fails", "FAIL")
    slab.free(s1)
    s4: t.CVoid | t.CPtr = slab.alloc(32)
    testcheck.check(s4 is not None, "MemSlab alloc after free", "FAIL")
    testcheck.check(t.CUInt64T(s4) == t.CUInt64T(s1), "MemSlab free reuse addr", "FAIL")

    # ========== MemBuddy (buddy system) ==========
    testcheck.section("MemBuddy (buddy system)")
    buddy: memhub.MemBuddy = memhub.MemBuddy(arena3, 65536)
    b1: t.CVoid | t.CPtr = buddy.alloc(100)
    testcheck.check(b1 is not None, "MemBuddy alloc 100", "FAIL")
    b2: t.CVoid | t.CPtr = buddy.alloc(200)
    testcheck.check(b2 is not None, "MemBuddy alloc 200", "FAIL")
    buddy.free(b1)
    b3: t.CVoid | t.CPtr = buddy.alloc(100)
    testcheck.check(b3 is not None, "MemBuddy alloc after free", "FAIL")
    # realloc 增长
    b4: t.CVoid | t.CPtr = buddy.realloc(b2, 400)
    testcheck.check(b4 is not None, "MemBuddy realloc 200->400", "FAIL")

    # ========== 多态分派 (核心测试) ==========
    testcheck.section("polymorphic dispatch")
    r1: t.CInt = test_polymorphic(pool, 50)
    testcheck.check(r1 == 1, "vtable: MemPool.alloc/free via MemManager", "FAIL")
    r2: t.CInt = test_polymorphic(slab, 32)
    testcheck.check(r2 == 1, "vtable: MemSlab.alloc/free via MemManager", "FAIL")
    r3: t.CInt = test_polymorphic(buddy, 50)
    testcheck.check(r3 == 1, "vtable: MemBuddy.alloc/free via MemManager", "FAIL")

    # calloc 多态 (具体方法调虚函数)
    rc1: t.CInt = test_calloc_polymorphic(pool)
    testcheck.check(rc1 == 1, "vtable: calloc dispatches MemPool.alloc", "FAIL")
    rc2: t.CInt = test_calloc_polymorphic(buddy)
    testcheck.check(rc2 == 1, "vtable: calloc dispatches MemBuddy.alloc", "FAIL")

    stdlib.free(arena1)
    stdlib.free(arena2)
    stdlib.free(arena3)
    return 0
