import t, c
from stdint import *
import memhub


class Vector[T]():
    data: t.CVoid | t.CPtr
    length: t.CSizeT
    capacity: t.CSizeT
    elem_size: t.CSizeT
    pool: memhub.MemManager | t.CPtr

    def __init__(self, pool: memhub.MemManager | t.CPtr, capacity: t.CSizeT, _hint: T):
        self.elem_size = T.__sizeof__()
        self.capacity = capacity
        self.length = 0
        self.pool = pool
        self.data = pool.alloc(capacity * self.elem_size)

    def push(self, value: T):
        if self.data == None: return
        if self.length >= self.capacity:
            self._grow()
            if self.length >= self.capacity: return
        offset: t.CUInt64T = t.CUInt64T(self.data) + self.length * self.elem_size
        dst: t.CVoid | t.CPtr = t.CVoid(offset, t.CPtr)
        c.DerefAs(dst, value)
        self.length += 1

    def _grow(self):
        if self.pool == None: return
        new_capacity: t.CSizeT = self.capacity * 2
        if new_capacity == 0: new_capacity = 4
        new_size: t.CSizeT = new_capacity * self.elem_size
        new_data: t.CVoid | t.CPtr = self.pool.realloc(self.data, new_size)
        if new_data == None: return
        self.data = new_data
        self.capacity = new_capacity

    def get(self, index: t.CSizeT) -> T:
        if self.data == None: return T(0)
        offset: t.CUInt64T = t.CUInt64T(self.data) + index * self.elem_size
        typed_ptr = T(offset, t.CPtr)
        return c.Deref(typed_ptr)

    def set(self, index: t.CSizeT, value: T):
        if index >= self.length: return
        if self.data == None: return
        offset: t.CUInt64T = t.CUInt64T(self.data) + index * self.elem_size
        dst: t.CVoid | t.CPtr = t.CVoid(offset, t.CPtr)
        c.DerefAs(dst, value)

    def len(self) -> t.CSizeT:
        return self.length

    def clear(self):
        self.length = 0

    def free(self):
        if self.data != None:
            if self.pool != None:
                self.pool.free(self.data)
            self.data = None
        self.length = 0
        self.capacity = 0
