ludic.base: tb_reserve and imap_reserve size a table up front; HandlePool (a slot and a generation, nothing made after hd_pool_new, past its capacity a panic naming it); kept_push is the one declared grow, and every growth path left says its bound in @alloc_ok
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f2dd27f443
commit
2d1d06899e
17 changed files with 199 additions and 26 deletions
62
packages/ludic.base/handle.ludic
Normal file
62
packages/ludic.base/handle.ludic
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# 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
|
||||
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)
|
||||
}
|
||||
|
||||
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) }
|
||||
Loading…
Add table
Add a link
Reference in a new issue