reference-cache.ts 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. export interface Reference<T> { readonly value: T, usageCount: number }
  7. export function createReference<T>(value: T, usageCount = 0) {
  8. return { value, usageCount }
  9. }
  10. export interface ReferenceItem<T> {
  11. free: () => void
  12. readonly value: T
  13. }
  14. export function createReferenceItem<T>(ref: Reference<T>) {
  15. return {
  16. free: () => {
  17. ref.usageCount -= 1
  18. },
  19. value: ref.value
  20. }
  21. }
  22. export interface ReferenceCache<T, P, C> {
  23. get: (ctx: C, props: P) => ReferenceItem<T>
  24. clear: () => void
  25. readonly count: number
  26. dispose: () => void
  27. }
  28. export function createReferenceCache<T, P, C>(hashFn: (props: P) => string, ctor: (ctx: C, props: P) => T, deleteFn: (v: T) => void): ReferenceCache<T, P, C> {
  29. const map: Map<string, Reference<T>> = new Map()
  30. return {
  31. get: (ctx: C, props: P) => {
  32. const id = hashFn(props)
  33. let ref = map.get(id)
  34. if (!ref) {
  35. ref = createReference<T>(ctor(ctx, props))
  36. map.set(id, ref)
  37. }
  38. ref.usageCount += 1
  39. return createReferenceItem(ref)
  40. },
  41. clear: () => {
  42. map.forEach((ref, id) => {
  43. if (ref.usageCount <= 0) {
  44. if (ref.usageCount < 0) {
  45. console.warn('Reference usageCount below zero.')
  46. }
  47. deleteFn(ref.value)
  48. map.delete(id)
  49. }
  50. })
  51. },
  52. get count () {
  53. return map.size
  54. },
  55. dispose: () => {
  56. map.forEach(ref => deleteFn(ref.value))
  57. map.clear()
  58. },
  59. }
  60. }