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  }