/** * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ export interface Reference<T> { readonly value: T, usageCount: number } export function createReference<T>(value: T, usageCount = 0) { return { value, usageCount } } export interface ReferenceItem<T> { free: () => void readonly value: T } export function createReferenceItem<T>(ref: Reference<T>) { return { free: () => { ref.usageCount -= 1 }, value: ref.value } } export interface ReferenceCache<T, P, C> { get: (ctx: C, props: P) => ReferenceItem<T> clear: () => void readonly count: number dispose: () => void } export function createReferenceCache<T, P, C>(hashFn: (props: P) => string, ctor: (ctx: C, props: P) => T, deleteFn: (v: T) => void): ReferenceCache<T, P, C> { const map: Map<string, Reference<T>> = new Map() return { get: (ctx: C, props: P) => { const id = hashFn(props) let ref = map.get(id) if (!ref) { ref = createReference<T>(ctor(ctx, props)) map.set(id, ref) } ref.usageCount += 1 return createReferenceItem(ref) }, clear: () => { map.forEach((ref, id) => { if (ref.usageCount <= 0) { if (ref.usageCount < 0) { console.warn('Reference usageCount below zero.') } deleteFn(ref.value) map.delete(id) } }) }, get count () { return map.size }, dispose: () => { map.forEach(ref => deleteFn(ref.value)) map.clear() }, } }