Files
TransPyC/includes/mpool.py
2026-06-16 16:09:42 +08:00

201 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import viperio
import string
MPOOL_ALIGN: t.CDefine = 8
MPOOL_TYPE_SLAB: t.CDefine = 0
MPOOL_TYPE_BUMP: t.CDefine = 2
def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT:
if align == 0: return val
return (val + align - 1) & ~(align - 1)
class MPool:
mtype: t.CInt
mem: t.CVoid | t.CPtr
mem_size: t.CSizeT
offset: t.CSizeT
high_water: t.CSizeT
block_size: t.CSizeT
block_count: t.CSizeT
used_count: t.CSizeT
free_list: t.CVoid | t.CPtr
alloc_map: t.CUInt8T | t.CPtr
alloc_map_size: t.CSizeT
def __init__(self, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT):
self.mtype = MPOOL_TYPE_BUMP
self.mem = None
self.mem_size = 0
self.offset = 0
self.high_water = 0
self.block_size = 0
self.block_count = 0
self.used_count = 0
self.free_list = None
self.alloc_map = None
self.alloc_map_size = 0
if mem == None: return
if block_size > 0:
self._init_slab(mem, mem_size, block_size)
else:
self._init_bump(mem, mem_size)
def _init_bump(self, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT):
if mem == None: return
if mem_size < 8: return
self.mtype = MPOOL_TYPE_BUMP
self.mem = mem
self.mem_size = mem_size
self.offset = 0
self.high_water = 0
def _init_slab(self, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT):
if mem == None: return
bs: t.CSizeT = _align_up(block_size, MPOOL_ALIGN)
if bs < 16: bs = 16
alloc_map_bytes: t.CSizeT = _align_up(256, MPOOL_ALIGN)
if mem_size < alloc_map_bytes + bs: return
self.mtype = MPOOL_TYPE_SLAB
self.alloc_map = mem
self.alloc_map_size = alloc_map_bytes
self.mem = t.CVoid(t.CUInt64T(mem) + alloc_map_bytes, t.CPtr)
self.mem_size = mem_size - alloc_map_bytes
self.block_size = bs
self.used_count = 0
idx: t.CSizeT = 0
while idx < alloc_map_bytes:
self.alloc_map[idx] = 0
idx += 1
self.block_count = self.mem_size / bs
if self.block_count == 0: return
self.free_list = None
i: t.CSizeT = 0
while i < self.block_count:
block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.mem) + i * bs, t.CPtr)
c.DerefAs(block, self.free_list)
self.free_list = block
i += 1
def __enter__(self) -> 'MPool' | t.CPtr:
return self
def __exit__(self):
if self.mtype == MPOOL_TYPE_BUMP:
self.offset = 0
self.high_water = 0
elif self.mtype == MPOOL_TYPE_SLAB:
self._slab_reset()
def _slab_reset(self):
self.used_count = 0
self.free_list = None
i: t.CSizeT = 0
while i < self.block_count:
block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.mem) + i * self.block_size, t.CPtr)
c.DerefAs(block, self.free_list)
self.free_list = block
if i / 8 < self.alloc_map_size:
self.alloc_map[i / 8] = 0
i += 1
def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr:
if self.mtype == MPOOL_TYPE_SLAB:
return self._slab_alloc()
if self.mtype == MPOOL_TYPE_BUMP:
return self._bump_alloc(size)
return None
def alloc_buf(self, capacity: t.CSizeT) -> viperio.Buf | t.CPtr:
ptr: t.CVoid | t.CPtr = self.alloc(capacity)
if ptr == None:
return viperio.Buf(None, 0)
return viperio.Buf(t.CChar(t.CUInt64T(ptr), t.CPtr), capacity)
def free(self, ptr: t.CVoid | t.CPtr):
if ptr == None: return
if self.mtype == MPOOL_TYPE_SLAB:
self._slab_free(ptr)
def realloc(self, ptr: t.CVoid | t.CPtr, old_size: t.CSizeT, new_size: t.CSizeT) -> t.CVoid | t.CPtr:
if ptr == None:
return self.alloc(new_size)
if new_size == 0:
self.free(ptr)
return None
if self.mtype == MPOOL_TYPE_SLAB:
if new_size <= self.block_size:
return ptr
new_ptr: t.CVoid | t.CPtr = self.alloc(new_size)
if new_ptr == None:
return ptr
copy_size: t.CSizeT = old_size
if new_size < old_size:
copy_size = new_size
string.memcpy(new_ptr, ptr, copy_size)
self.free(ptr)
return new_ptr
def reset(self):
if self.mtype == MPOOL_TYPE_BUMP:
self.offset = 0
self.high_water = 0
elif self.mtype == MPOOL_TYPE_SLAB:
self._slab_reset()
def _bump_alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr:
if size == 0: return None
aligned: t.CSizeT = _align_up(size, MPOOL_ALIGN)
if self.offset + aligned > self.mem_size: return None
ptr: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.mem) + self.offset, t.CPtr)
self.offset += aligned
if self.offset > self.high_water:
self.high_water = self.offset
return ptr
def _slab_alloc(self) -> t.CVoid | t.CPtr:
if self.free_list == None: return None
block: t.CVoid | t.CPtr = self.free_list
self.free_list = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr)
self.used_count += 1
idx: t.CSizeT = (t.CUInt64T(block) - t.CUInt64T(self.mem)) / self.block_size
self.alloc_map[idx / 8] = self.alloc_map[idx / 8] | t.CUInt8T(1 << (idx % 8))
return block
def _slab_free(self, ptr: t.CVoid | t.CPtr):
if ptr == None: return
p: t.CUInt64T = t.CUInt64T(ptr)
if p < t.CUInt64T(self.mem): return
if p >= t.CUInt64T(self.mem) + self.block_count * self.block_size: return
if (p - t.CUInt64T(self.mem)) % self.block_size != 0: return
idx: t.CSizeT = (p - t.CUInt64T(self.mem)) / self.block_size
byte_idx: t.CSizeT = idx / 8
bit_idx: t.CInt = t.CInt(idx % 8)
if (self.alloc_map[byte_idx] >> bit_idx) & 1 == 0: return
self.alloc_map[byte_idx] = self.alloc_map[byte_idx] & t.CUInt8T(~(1 << bit_idx))
c.DerefAs(ptr, self.free_list)
self.free_list = ptr
self.used_count -= 1
# 模块级包装函数C 风格 API第一个参数传入 pool 指针)
def bump_create(mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> MPool | t.CPtr:
p: MPool | t.CPtr = MPool(mem, mem_size, 0)
return p
def alloc(pool: MPool | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr:
return pool.alloc(size)
def reset(pool: MPool | t.CPtr):
pool.reset()