defaultMemoize.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // Cache implementation based on Erik Rasmussen's `lru-memoize`:
  2. // https://github.com/erikras/lru-memoize
  3. var NOT_FOUND = 'NOT_FOUND';
  4. function createSingletonCache(equals) {
  5. var entry;
  6. return {
  7. get: function get(key) {
  8. if (entry && equals(entry.key, key)) {
  9. return entry.value;
  10. }
  11. return NOT_FOUND;
  12. },
  13. put: function put(key, value) {
  14. entry = {
  15. key: key,
  16. value: value
  17. };
  18. },
  19. getEntries: function getEntries() {
  20. return entry ? [entry] : [];
  21. },
  22. clear: function clear() {
  23. entry = undefined;
  24. }
  25. };
  26. }
  27. function createLruCache(maxSize, equals) {
  28. var entries = [];
  29. function get(key) {
  30. var cacheIndex = entries.findIndex(function (entry) {
  31. return equals(key, entry.key);
  32. }); // We found a cached entry
  33. if (cacheIndex > -1) {
  34. var entry = entries[cacheIndex]; // Cached entry not at top of cache, move it to the top
  35. if (cacheIndex > 0) {
  36. entries.splice(cacheIndex, 1);
  37. entries.unshift(entry);
  38. }
  39. return entry.value;
  40. } // No entry found in cache, return sentinel
  41. return NOT_FOUND;
  42. }
  43. function put(key, value) {
  44. if (get(key) === NOT_FOUND) {
  45. // TODO Is unshift slow?
  46. entries.unshift({
  47. key: key,
  48. value: value
  49. });
  50. if (entries.length > maxSize) {
  51. entries.pop();
  52. }
  53. }
  54. }
  55. function getEntries() {
  56. return entries;
  57. }
  58. function clear() {
  59. entries = [];
  60. }
  61. return {
  62. get: get,
  63. put: put,
  64. getEntries: getEntries,
  65. clear: clear
  66. };
  67. }
  68. export var defaultEqualityCheck = function defaultEqualityCheck(a, b) {
  69. return a === b;
  70. };
  71. export function createCacheKeyComparator(equalityCheck) {
  72. return function areArgumentsShallowlyEqual(prev, next) {
  73. if (prev === null || next === null || prev.length !== next.length) {
  74. return false;
  75. } // Do this in a for loop (and not a `forEach` or an `every`) so we can determine equality as fast as possible.
  76. var length = prev.length;
  77. for (var i = 0; i < length; i++) {
  78. if (!equalityCheck(prev[i], next[i])) {
  79. return false;
  80. }
  81. }
  82. return true;
  83. };
  84. }
  85. // defaultMemoize now supports a configurable cache size with LRU behavior,
  86. // and optional comparison of the result value with existing values
  87. export function defaultMemoize(func, equalityCheckOrOptions) {
  88. var providedOptions = typeof equalityCheckOrOptions === 'object' ? equalityCheckOrOptions : {
  89. equalityCheck: equalityCheckOrOptions
  90. };
  91. var _providedOptions$equa = providedOptions.equalityCheck,
  92. equalityCheck = _providedOptions$equa === void 0 ? defaultEqualityCheck : _providedOptions$equa,
  93. _providedOptions$maxS = providedOptions.maxSize,
  94. maxSize = _providedOptions$maxS === void 0 ? 1 : _providedOptions$maxS,
  95. resultEqualityCheck = providedOptions.resultEqualityCheck;
  96. var comparator = createCacheKeyComparator(equalityCheck);
  97. var cache = maxSize === 1 ? createSingletonCache(comparator) : createLruCache(maxSize, comparator); // we reference arguments instead of spreading them for performance reasons
  98. function memoized() {
  99. var value = cache.get(arguments);
  100. if (value === NOT_FOUND) {
  101. // @ts-ignore
  102. value = func.apply(null, arguments);
  103. if (resultEqualityCheck) {
  104. var entries = cache.getEntries();
  105. var matchingEntry = entries.find(function (entry) {
  106. return resultEqualityCheck(entry.value, value);
  107. });
  108. if (matchingEntry) {
  109. value = matchingEntry.value;
  110. }
  111. }
  112. cache.put(arguments, value);
  113. }
  114. return value;
  115. }
  116. memoized.clearCache = function () {
  117. return cache.clear();
  118. };
  119. return memoized;
  120. }