reference-cache.ts 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. /**
  2. * Copyright (c) 2018-2020 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> {
  23. get: (props: P) => ReferenceItem<T>
  24. clear: () => void
  25. readonly count: number
  26. dispose: () => void
  27. }
  28. export function createReferenceCache<T, P>(hashFn: (props: P) => string, ctor: (props: P) => T, deleteFn: (v: T) => void): ReferenceCache<T, P> {
  29. const map: Map<string, Reference<T>> = new Map();
  30. return {
  31. get: (props: P) => {
  32. const id = hashFn(props);
  33. let ref = map.get(id);
  34. if (!ref) {
  35. ref = createReference<T>(ctor(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. }