namespace Leaf { export class Referencer { events = new Leaf.EventEmitter<{ ref deref init release }>() counter = 0 ref() { this.counter += 1 if (this.counter == 1) { this.events.emit("init") } else { this.events.emit("ref") } } deref() { this.counter -= 1 if (this.counter == 0) { this.events.emit("release") } else if (this.counter > 0) { this.events.emit("deref") } else { console.error("Invalid Deref") } } } export class OwnerReferencer { ttl(time?: number) { return new OwnerReferenceCachier(this, time) } events = new Leaf.EventEmitter<{ ref deref init release }>() refs: { owner: any counter: number }[] = [] release() { this.refs.length = 0 this.events.emit("release") } getCounter() { return this.refs.reduce((a, b) => { return a + b.counter }, 0) } refBy(who: any) { for (let ref of this.refs) { if (ref.owner == who) { ref.counter += 1 this.events.emit("ref") return true } } this.refs.push({ owner: who, counter: 1 }) if (this.getCounter() == 1) { this.events.emit("init") } else { this.events.emit("ref") } return true } derefBy(who: any) { let i = 0 for (let ref of this.refs) { if (ref.owner == who) { ref.counter -= 1 if (ref.counter < 0) { console.error("Invalid by ", who) throw new Error("Invalid Deref by") } if (this.getCounter() <= 0) { this.events.emit("release") } else { this.events.emit("deref") } return true } i++ } console.error("Invalid by ", who) throw new Error("Invalid derefence by") } } export class MultipleReference { constructor() { } refs: { target: T owner: any counter: number }[] = [] targetRefs: { target: T counter: number }[] = [] private refTarget(target: T) { for (let item of this.targetRefs) { if (item.target === target) { item.counter += 1 this.events.emit("ref", target) return true } } this.targetRefs.push({ target, counter: 1 }) this.events.emit("init", target) return true } private derefTarget(target: T, n = 1) { let i = 0 for (let item of this.targetRefs) { if (item.target === target) { item.counter -= n if (item.counter == 0) { this.targetRefs.splice(i, 1) this.events.emit("release", target) } else { this.events.emit("deref", target) } return true } i++ } return false } private derefAll(who) { let arr = this.refs for (let i = 0; i < arr.length; i++) { let item = arr[i] if (item.owner === who) { arr.splice(i, 1) i-- this.derefTarget(item.target, item.counter) } } } refBy(who: any, target: T) { let arr = this.refs for (let i = 0; i < arr.length; i++) { let item = arr[i] if (item.owner === who && target == item.owner) { item.counter += 1 return this.refTarget(target) } } this.refs.push({ target, owner: who, counter: 1 }) return this.refTarget(target) } derefBy(who: any, target?: T) { if (!target) { return this.derefAll(who) } let arr = this.refs for (let i = 0; i < arr.length; i++) { let item = arr[i] if (item.owner === who && target == item.owner) { item.counter -= 1 if (item.counter <= 0) { arr.splice(i, 1) } return this.derefTarget(target) } } return false } events = new Leaf.EventEmitter<{ // first ref init: T // no ref release: T ref: T deref: T }>() } export class OwnerReferenceCachier { constructor(public readonly referencer: OwnerReferencer, public readonly time = 10000) { this.referencer.refBy(this) this.referencer.events.listenBy(this, "deref", () => { let counter = this.referencer.getCounter() // Only me reference if (counter == 1) { this.debounceDeref() } }) this.referencer.events.listenBy(this, "ref", () => { this.stopDebounceDeref() }) } timer = null debounceDeref() { this.timer = setTimeout(() => { this.referencer.derefBy(this) this.referencer.events.stopListenBy(this) }, this.time) } stopDebounceDeref() { clearTimeout(this.timer) } } }