github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/gojs/values/values.go (about) 1 package values 2 3 import ( 4 "fmt" 5 6 "github.com/bananabytelabs/wazero/internal/gojs/goos" 7 ) 8 9 func NewValues() *Values { 10 ret := &Values{} 11 ret.Reset() 12 return ret 13 } 14 15 type Values struct { 16 // Below is needed to avoid exhausting the ID namespace finalizeRef reclaims 17 // See https://go-review.googlesource.com/c/go/+/203600 18 19 values []interface{} // values indexed by ID, nil 20 goRefCounts []uint32 // recount pair-indexed with values 21 ids map[interface{}]uint32 // live values 22 idPool []uint32 // reclaimed IDs (values[i] = nil, goRefCounts[i] nil 23 } 24 25 func (j *Values) Get(id uint32) interface{} { 26 index := id - goos.NextID 27 if index >= uint32(len(j.values)) { 28 panic(fmt.Errorf("id %d is out of range %d", id, len(j.values))) 29 } 30 if v := j.values[index]; v == nil { 31 panic(fmt.Errorf("value for %d was nil", id)) 32 } else { 33 return v 34 } 35 } 36 37 func (j *Values) Increment(v interface{}) uint32 { 38 id, ok := j.ids[v] 39 if !ok { 40 if len(j.idPool) == 0 { 41 id, j.values, j.goRefCounts = uint32(len(j.values)), append(j.values, v), append(j.goRefCounts, 0) 42 } else { 43 id, j.idPool = j.idPool[len(j.idPool)-1], j.idPool[:len(j.idPool)-1] 44 j.values[id], j.goRefCounts[id] = v, 0 45 } 46 j.ids[v] = id 47 } 48 j.goRefCounts[id]++ 49 50 return id + goos.NextID 51 } 52 53 func (j *Values) Decrement(id uint32) { 54 // Special IDs are not goos.Refcounted. 55 if id < goos.NextID { 56 return 57 } 58 id -= goos.NextID 59 j.goRefCounts[id]-- 60 if j.goRefCounts[id] == 0 { 61 v := j.values[id] 62 j.values[id] = nil 63 delete(j.ids, v) 64 j.idPool = append(j.idPool, id) 65 } 66 } 67 68 func (j *Values) Reset() { 69 j.values = nil 70 j.goRefCounts = nil 71 j.ids = map[interface{}]uint32{} 72 j.idPool = nil 73 }