builtin_weakset.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package goja
  2. import "sync"
  3. type weakSet struct {
  4. // need to synchronise access to the data map because it may be accessed
  5. // from the finalizer goroutine
  6. sync.Mutex
  7. data map[uintptr]struct{}
  8. }
  9. type weakSetObject struct {
  10. baseObject
  11. s *weakSet
  12. }
  13. func newWeakSet() *weakSet {
  14. return &weakSet{
  15. data: make(map[uintptr]struct{}),
  16. }
  17. }
  18. func (ws *weakSetObject) init() {
  19. ws.baseObject.init()
  20. ws.s = newWeakSet()
  21. }
  22. func (ws *weakSet) removePtr(ptr uintptr) {
  23. ws.Lock()
  24. delete(ws.data, ptr)
  25. ws.Unlock()
  26. }
  27. func (ws *weakSet) add(o *Object) {
  28. refs := o.getWeakCollRefs()
  29. ws.Lock()
  30. ws.data[refs.id()] = struct{}{}
  31. ws.Unlock()
  32. refs.add(ws)
  33. }
  34. func (ws *weakSet) remove(o *Object) bool {
  35. if o.weakColls == nil {
  36. return false
  37. }
  38. id := o.weakColls.id()
  39. ws.Lock()
  40. _, exists := ws.data[id]
  41. if exists {
  42. delete(ws.data, id)
  43. }
  44. ws.Unlock()
  45. if exists {
  46. o.weakColls.remove(ws)
  47. }
  48. return exists
  49. }
  50. func (ws *weakSet) has(o *Object) bool {
  51. if o.weakColls == nil {
  52. return false
  53. }
  54. ws.Lock()
  55. _, exists := ws.data[o.weakColls.id()]
  56. ws.Unlock()
  57. return exists
  58. }
  59. func (r *Runtime) weakSetProto_add(call FunctionCall) Value {
  60. thisObj := r.toObject(call.This)
  61. wso, ok := thisObj.self.(*weakSetObject)
  62. if !ok {
  63. panic(r.NewTypeError("Method WeakSet.prototype.add called on incompatible receiver %s", thisObj.String()))
  64. }
  65. wso.s.add(r.toObject(call.Argument(0)))
  66. return call.This
  67. }
  68. func (r *Runtime) weakSetProto_delete(call FunctionCall) Value {
  69. thisObj := r.toObject(call.This)
  70. wso, ok := thisObj.self.(*weakSetObject)
  71. if !ok {
  72. panic(r.NewTypeError("Method WeakSet.prototype.delete called on incompatible receiver %s", thisObj.String()))
  73. }
  74. obj, ok := call.Argument(0).(*Object)
  75. if ok && wso.s.remove(obj) {
  76. return valueTrue
  77. }
  78. return valueFalse
  79. }
  80. func (r *Runtime) weakSetProto_has(call FunctionCall) Value {
  81. thisObj := r.toObject(call.This)
  82. wso, ok := thisObj.self.(*weakSetObject)
  83. if !ok {
  84. panic(r.NewTypeError("Method WeakSet.prototype.has called on incompatible receiver %s", thisObj.String()))
  85. }
  86. obj, ok := call.Argument(0).(*Object)
  87. if ok && wso.s.has(obj) {
  88. return valueTrue
  89. }
  90. return valueFalse
  91. }
  92. func (r *Runtime) populateWeakSetGeneric(s *Object, adderValue Value, iterable Value) {
  93. adder := toMethod(adderValue)
  94. if adder == nil {
  95. panic(r.NewTypeError("WeakSet.add is not set"))
  96. }
  97. iter := r.getIterator(iterable, nil)
  98. r.iterate(iter, func(val Value) {
  99. adder(FunctionCall{This: s, Arguments: []Value{val}})
  100. })
  101. }
  102. func (r *Runtime) builtin_newWeakSet(args []Value, proto *Object) *Object {
  103. o := &Object{runtime: r}
  104. wso := &weakSetObject{}
  105. wso.class = classWeakSet
  106. wso.val = o
  107. wso.extensible = true
  108. o.self = wso
  109. wso.prototype = proto
  110. wso.init()
  111. if len(args) > 0 {
  112. if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
  113. adder := wso.getStr("add", nil)
  114. if adder == r.global.weakSetAdder {
  115. if arr := r.checkStdArrayIter(arg); arr != nil {
  116. for _, v := range arr.values {
  117. wso.s.add(r.toObject(v))
  118. }
  119. return o
  120. }
  121. }
  122. r.populateWeakSetGeneric(o, adder, arg)
  123. }
  124. }
  125. return o
  126. }
  127. func (r *Runtime) createWeakSetProto(val *Object) objectImpl {
  128. o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject)
  129. o._putProp("constructor", r.global.WeakSet, true, false, true)
  130. r.global.weakSetAdder = r.newNativeFunc(r.weakSetProto_add, nil, "add", nil, 1)
  131. o._putProp("add", r.global.weakSetAdder, true, false, true)
  132. o._putProp("delete", r.newNativeFunc(r.weakSetProto_delete, nil, "delete", nil, 1), true, false, true)
  133. o._putProp("has", r.newNativeFunc(r.weakSetProto_has, nil, "has", nil, 1), true, false, true)
  134. o._putSym(symToStringTag, valueProp(asciiString(classWeakSet), false, false, true))
  135. return o
  136. }
  137. func (r *Runtime) createWeakSet(val *Object) objectImpl {
  138. o := r.newNativeFuncObj(val, r.constructorThrower("WeakSet"), r.builtin_newWeakSet, "WeakSet", r.global.WeakSetPrototype, 0)
  139. return o
  140. }
  141. func (r *Runtime) initWeakSet() {
  142. r.global.WeakSetPrototype = r.newLazyObject(r.createWeakSetProto)
  143. r.global.WeakSet = r.newLazyObject(r.createWeakSet)
  144. r.addToGlobal("WeakSet", r.global.WeakSet)
  145. }