74 lines
1.7 KiB
Go
74 lines
1.7 KiB
Go
package values
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/tetratelabs/wazero/internal/gojs/goos"
|
|
)
|
|
|
|
func NewValues() *Values {
|
|
ret := &Values{}
|
|
ret.Reset()
|
|
return ret
|
|
}
|
|
|
|
type Values struct {
|
|
// Below is needed to avoid exhausting the ID namespace finalizeRef reclaims
|
|
// See https://go-review.googlesource.com/c/go/+/203600
|
|
|
|
values []interface{} // values indexed by ID, nil
|
|
goRefCounts []uint32 // recount pair-indexed with values
|
|
ids map[interface{}]uint32 // live values
|
|
idPool []uint32 // reclaimed IDs (values[i] = nil, goRefCounts[i] nil
|
|
}
|
|
|
|
func (j *Values) Get(id uint32) interface{} {
|
|
index := id - goos.NextID
|
|
if index >= uint32(len(j.values)) {
|
|
panic(fmt.Errorf("id %d is out of range %d", id, len(j.values)))
|
|
}
|
|
if v := j.values[index]; v == nil {
|
|
panic(fmt.Errorf("value for %d was nil", id))
|
|
} else {
|
|
return v
|
|
}
|
|
}
|
|
|
|
func (j *Values) Increment(v interface{}) uint32 {
|
|
id, ok := j.ids[v]
|
|
if !ok {
|
|
if len(j.idPool) == 0 {
|
|
id, j.values, j.goRefCounts = uint32(len(j.values)), append(j.values, v), append(j.goRefCounts, 0)
|
|
} else {
|
|
id, j.idPool = j.idPool[len(j.idPool)-1], j.idPool[:len(j.idPool)-1]
|
|
j.values[id], j.goRefCounts[id] = v, 0
|
|
}
|
|
j.ids[v] = id
|
|
}
|
|
j.goRefCounts[id]++
|
|
|
|
return id + goos.NextID
|
|
}
|
|
|
|
func (j *Values) Decrement(id uint32) {
|
|
// Special IDs are not goos.Refcounted.
|
|
if id < goos.NextID {
|
|
return
|
|
}
|
|
id -= goos.NextID
|
|
j.goRefCounts[id]--
|
|
if j.goRefCounts[id] == 0 {
|
|
v := j.values[id]
|
|
j.values[id] = nil
|
|
delete(j.ids, v)
|
|
j.idPool = append(j.idPool, id)
|
|
}
|
|
}
|
|
|
|
func (j *Values) Reset() {
|
|
j.values = nil
|
|
j.goRefCounts = nil
|
|
j.ids = map[interface{}]uint32{}
|
|
j.idPool = nil
|
|
}
|