123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- package goja
- import "sync"
- type weakMap struct {
- // need to synchronise access to the data map because it may be accessed
- // from the finalizer goroutine
- sync.Mutex
- data map[uintptr]Value
- }
- type weakMapObject struct {
- baseObject
- m *weakMap
- }
- func newWeakMap() *weakMap {
- return &weakMap{
- data: make(map[uintptr]Value),
- }
- }
- func (wmo *weakMapObject) init() {
- wmo.baseObject.init()
- wmo.m = newWeakMap()
- }
- func (wm *weakMap) removePtr(ptr uintptr) {
- wm.Lock()
- delete(wm.data, ptr)
- wm.Unlock()
- }
- func (wm *weakMap) set(key *Object, value Value) {
- refs := key.getWeakCollRefs()
- wm.Lock()
- wm.data[refs.id()] = value
- wm.Unlock()
- refs.add(wm)
- }
- func (wm *weakMap) get(key *Object) Value {
- refs := key.weakColls
- if refs == nil {
- return nil
- }
- wm.Lock()
- ret := wm.data[refs.id()]
- wm.Unlock()
- return ret
- }
- func (wm *weakMap) remove(key *Object) bool {
- refs := key.weakColls
- if refs == nil {
- return false
- }
- id := refs.id()
- wm.Lock()
- _, exists := wm.data[id]
- if exists {
- delete(wm.data, id)
- }
- wm.Unlock()
- if exists {
- refs.remove(wm)
- }
- return exists
- }
- func (wm *weakMap) has(key *Object) bool {
- refs := key.weakColls
- if refs == nil {
- return false
- }
- id := refs.id()
- wm.Lock()
- _, exists := wm.data[id]
- wm.Unlock()
- return exists
- }
- func (r *Runtime) weakMapProto_delete(call FunctionCall) Value {
- thisObj := r.toObject(call.This)
- wmo, ok := thisObj.self.(*weakMapObject)
- if !ok {
- panic(r.NewTypeError("Method WeakMap.prototype.delete called on incompatible receiver %s", thisObj.String()))
- }
- key, ok := call.Argument(0).(*Object)
- if ok && wmo.m.remove(key) {
- return valueTrue
- }
- return valueFalse
- }
- func (r *Runtime) weakMapProto_get(call FunctionCall) Value {
- thisObj := r.toObject(call.This)
- wmo, ok := thisObj.self.(*weakMapObject)
- if !ok {
- panic(r.NewTypeError("Method WeakMap.prototype.get called on incompatible receiver %s", thisObj.String()))
- }
- var res Value
- if key, ok := call.Argument(0).(*Object); ok {
- res = wmo.m.get(key)
- }
- if res == nil {
- return _undefined
- }
- return res
- }
- func (r *Runtime) weakMapProto_has(call FunctionCall) Value {
- thisObj := r.toObject(call.This)
- wmo, ok := thisObj.self.(*weakMapObject)
- if !ok {
- panic(r.NewTypeError("Method WeakMap.prototype.has called on incompatible receiver %s", thisObj.String()))
- }
- key, ok := call.Argument(0).(*Object)
- if ok && wmo.m.has(key) {
- return valueTrue
- }
- return valueFalse
- }
- func (r *Runtime) weakMapProto_set(call FunctionCall) Value {
- thisObj := r.toObject(call.This)
- wmo, ok := thisObj.self.(*weakMapObject)
- if !ok {
- panic(r.NewTypeError("Method WeakMap.prototype.set called on incompatible receiver %s", thisObj.String()))
- }
- key := r.toObject(call.Argument(0))
- wmo.m.set(key, call.Argument(1))
- return call.This
- }
- func (r *Runtime) builtin_newWeakMap(args []Value, proto *Object) *Object {
- o := &Object{runtime: r}
- wmo := &weakMapObject{}
- wmo.class = classWeakMap
- wmo.val = o
- wmo.extensible = true
- o.self = wmo
- wmo.prototype = proto
- wmo.init()
- if len(args) > 0 {
- if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
- adder := wmo.getStr("set", nil)
- iter := r.getIterator(arg, nil)
- i0 := valueInt(0)
- i1 := valueInt(1)
- if adder == r.global.weakMapAdder {
- r.iterate(iter, func(item Value) {
- itemObj := r.toObject(item)
- k := itemObj.self.getIdx(i0, nil)
- v := nilSafe(itemObj.self.getIdx(i1, nil))
- wmo.m.set(r.toObject(k), v)
- })
- } else {
- adderFn := toMethod(adder)
- if adderFn == nil {
- panic(r.NewTypeError("WeakMap.set in missing"))
- }
- r.iterate(iter, func(item Value) {
- itemObj := r.toObject(item)
- k := itemObj.self.getIdx(i0, nil)
- v := itemObj.self.getIdx(i1, nil)
- adderFn(FunctionCall{This: o, Arguments: []Value{k, v}})
- })
- }
- }
- }
- return o
- }
- func (r *Runtime) createWeakMapProto(val *Object) objectImpl {
- o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject)
- o._putProp("constructor", r.global.WeakMap, true, false, true)
- r.global.weakMapAdder = r.newNativeFunc(r.weakMapProto_set, nil, "set", nil, 2)
- o._putProp("set", r.global.weakMapAdder, true, false, true)
- o._putProp("delete", r.newNativeFunc(r.weakMapProto_delete, nil, "delete", nil, 1), true, false, true)
- o._putProp("has", r.newNativeFunc(r.weakMapProto_has, nil, "has", nil, 1), true, false, true)
- o._putProp("get", r.newNativeFunc(r.weakMapProto_get, nil, "get", nil, 1), true, false, true)
- o._putSym(symToStringTag, valueProp(asciiString(classWeakMap), false, false, true))
- return o
- }
- func (r *Runtime) createWeakMap(val *Object) objectImpl {
- o := r.newNativeFuncObj(val, r.constructorThrower("WeakMap"), r.builtin_newWeakMap, "WeakMap", r.global.WeakMapPrototype, 0)
- return o
- }
- func (r *Runtime) initWeakMap() {
- r.global.WeakMapPrototype = r.newLazyObject(r.createWeakMapProto)
- r.global.WeakMap = r.newLazyObject(r.createWeakMap)
- r.addToGlobal("WeakMap", r.global.WeakMap)
- }
|