92 lines
1.9 KiB
Go
92 lines
1.9 KiB
Go
package world
|
|
|
|
import "aego/core/handle"
|
|
|
|
type pool[T any] struct {
|
|
items []T
|
|
gens []uint32
|
|
alive []bool
|
|
free []uint32
|
|
count int
|
|
}
|
|
|
|
func newPool[T any](capacity int) pool[T] {
|
|
return pool[T]{
|
|
items: make([]T, 0, capacity),
|
|
gens: make([]uint32, 0, capacity),
|
|
alive: make([]bool, 0, capacity),
|
|
free: make([]uint32, 0, capacity),
|
|
}
|
|
}
|
|
|
|
func (p *pool[T]) alloc() (handle.Handle[T], *T) {
|
|
var idx uint32
|
|
if n := len(p.free); n > 0 {
|
|
idx = p.free[n-1]
|
|
p.free = p.free[:n-1]
|
|
} else {
|
|
var zero T
|
|
idx = uint32(len(p.items))
|
|
p.items = append(p.items, zero)
|
|
p.gens = append(p.gens, 0)
|
|
p.alive = append(p.alive, false)
|
|
}
|
|
gen := p.gens[idx] + 1
|
|
if gen == 0 {
|
|
gen = 1
|
|
}
|
|
p.gens[idx] = gen
|
|
p.alive[idx] = true
|
|
p.count++
|
|
return handle.Handle[T]{Index: idx, Gen: gen}, &p.items[idx]
|
|
}
|
|
|
|
func (p *pool[T]) valid(h handle.Handle[T]) bool {
|
|
return h.Gen != 0 && int(h.Index) < len(p.items) && p.alive[h.Index] && p.gens[h.Index] == h.Gen
|
|
}
|
|
|
|
func (p *pool[T]) get(h handle.Handle[T]) (*T, bool) {
|
|
if !p.valid(h) {
|
|
return nil, false
|
|
}
|
|
return &p.items[h.Index], true
|
|
}
|
|
|
|
func (p *pool[T]) release(h handle.Handle[T]) bool {
|
|
if !p.valid(h) {
|
|
return false
|
|
}
|
|
var zero T
|
|
p.items[h.Index] = zero
|
|
p.alive[h.Index] = false
|
|
p.free = append(p.free, h.Index)
|
|
p.count--
|
|
return true
|
|
}
|
|
|
|
func (p *pool[T]) handleAt(i int) handle.Handle[T] {
|
|
return handle.Handle[T]{Index: uint32(i), Gen: p.gens[i]}
|
|
}
|
|
|
|
func (p *pool[T]) cloneInto(dst *pool[T], cp func(dst, src *T)) {
|
|
n := len(p.items)
|
|
if cap(dst.items) < n {
|
|
items := make([]T, n, max(cap(p.items), n))
|
|
copy(items, dst.items[:cap(dst.items)])
|
|
dst.items = items
|
|
} else {
|
|
dst.items = dst.items[:n]
|
|
}
|
|
dst.gens = append(dst.gens[:0], p.gens...)
|
|
dst.alive = append(dst.alive[:0], p.alive...)
|
|
dst.free = append(dst.free[:0], p.free...)
|
|
dst.count = p.count
|
|
for i := range p.items {
|
|
if cp != nil {
|
|
cp(&dst.items[i], &p.items[i])
|
|
} else {
|
|
dst.items[i] = p.items[i]
|
|
}
|
|
}
|
|
}
|