64 lines
2 KiB
Text
64 lines
2 KiB
Text
# ludic.base/handle.ludic - ids a pool hands out, each a slot and a generation (Table's encoding): a
|
|
# freed id's slot is reused under a new generation, so an id kept past its free misses with -1
|
|
export property HandlePool {
|
|
name: string = ""
|
|
gen: words = null # slot -> generation
|
|
live: words = null # slot -> 1 while handed out
|
|
free: words = null
|
|
n: int = 0 # slots made so far
|
|
count: int = 0 # handed out now
|
|
refused: int = 0 # asks past the capacity
|
|
strict: bool = true # past the capacity is a panic naming the pool, else -1
|
|
}
|
|
|
|
# everything the pool will ever hold, made now: nothing after this allocates
|
|
@alloc_ok("a pool made at start: its owner keeps it")
|
|
export function hd_pool_new(name: string, cap: int) -> HandlePool {
|
|
let p = new HandlePool
|
|
p.name = name
|
|
p.gen = words(cap)
|
|
p.live = words(cap)
|
|
p.free = words(cap)
|
|
List.clear(p.free)
|
|
return p
|
|
}
|
|
|
|
export function hd_new(p: HandlePool) -> int {
|
|
var s = -1
|
|
if len(p.free) > 0 { s = List.pop(p.free) }
|
|
else if p.n < len(p.gen) {
|
|
s = p.n
|
|
p.n += 1
|
|
} else { return hd_refuse(p) }
|
|
p.live[s] = 1
|
|
p.count += 1
|
|
return s | (p.gen[s] << 22)
|
|
}
|
|
|
|
@alloc_ok("only when a pool is full: the words of its panic")
|
|
function hd_refuse(p: HandlePool) -> int {
|
|
p.refused += 1
|
|
if p.strict { panic(`handle pool {p.name} is full at {len(p.gen)}`) }
|
|
return ECS_NONE
|
|
}
|
|
|
|
# the slot a handle names, or -1 when it was freed (or its slot has been handed out again since)
|
|
export function hd_slot(p: HandlePool, h: int) -> int {
|
|
if h < 0 { return -1 }
|
|
let s = h & ECS_SLOT
|
|
if s >= p.n or p.live[s] == 0 or p.gen[s] != ((h >> 22) & ECS_GEN) { return -1 }
|
|
return s
|
|
}
|
|
|
|
export function hd_free(p: HandlePool, h: int) -> bool {
|
|
let s = hd_slot(p, h)
|
|
if s < 0 { return false }
|
|
p.live[s] = 0
|
|
p.gen[s] = (p.gen[s] + 1) & ECS_GEN
|
|
kept_push(p.free, s)
|
|
p.count -= 1
|
|
return true
|
|
}
|
|
|
|
export function hd_live(p: HandlePool) -> int { return p.count }
|
|
export function hd_cap(p: HandlePool) -> int { return len(p.gen) }
|