补充
This commit is contained in:
200
includes/mpool.py
Normal file
200
includes/mpool.py
Normal file
@@ -0,0 +1,200 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user